aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-05-08 17:10:06 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2015-10-11 23:55:58 +0200
commit8ff62c5f34db48aa15c7252c40fea3381bba0952 (patch)
tree2a0ffd9bcf9a2648c45f170426cf86fb319509f2 /main
parent1d2b34e71a01d6af118ed89258ad0ecb983e1a9c (diff)
parent59b8b2e26a7fff6072c4d5d96f51035dc900e0bc (diff)
downloadcgeo-8ff62c5f34db48aa15c7252c40fea3381bba0952.zip
cgeo-8ff62c5f34db48aa15c7252c40fea3381bba0952.tar.gz
cgeo-8ff62c5f34db48aa15c7252c40fea3381bba0952.tar.bz2
merge upstream
Diffstat (limited to 'main')
-rw-r--r--main/.factorypath4
-rw-r--r--main/.settings/org.eclipse.jdt.core.prefs8
-rw-r--r--main/.settings/org.eclipse.jdt.ui.prefs10
-rw-r--r--main/.settings/org.moreunit.prefs4
-rw-r--r--main/AndroidManifest.xml503
-rw-r--r--main/build.gradle51
-rw-r--r--main/build.xml284
-rw-r--r--main/cgeo.iml218
-rw-r--r--main/compile-libs/androidannotations-3.0.1.jarbin617458 -> 0 bytes
-rw-r--r--main/compile-libs/androidannotations-3.2.jarbin0 -> 701151 bytes
-rw-r--r--main/libs/androidannotations-api-3.0.1.jarbin87369 -> 0 bytes
-rw-r--r--main/libs/androidannotations-api-3.2.jarbin0 -> 112164 bytes
-rw-r--r--main/libs/androidannotations-api-3.2.jar.properties2
-rw-r--r--main/libs/annotations-3.0.0.jar (renamed from main/libs/findbugs-annotations.jar)bin77185 -> 77209 bytes
-rw-r--r--main/libs/annotations-3.0.0.jar.properties2
-rw-r--r--main/libs/butterknife-5.1.1.jarbin45897 -> 0 bytes
-rw-r--r--main/libs/butterknife-6.1.0.jarbin0 -> 50414 bytes
-rw-r--r--main/libs/butterknife-6.1.0.jar.properties2
-rw-r--r--main/libs/commons-collections4-4.0.jar.properties3
-rw-r--r--main/libs/commons-io-2.4.jar.properties2
-rw-r--r--main/libs/commons-lang3-3.3.2.jarbin412740 -> 412739 bytes
-rw-r--r--main/libs/commons-lang3-3.3.2.jar.properties3
-rw-r--r--main/libs/jackson-annotations-2.5.1.jarbin0 -> 39817 bytes
-rw-r--r--main/libs/jackson-annotations-2.5.1.jar.properties2
-rw-r--r--main/libs/jackson-core-2.5.1.jarbin0 -> 229860 bytes
-rw-r--r--main/libs/jackson-core-2.5.1.jar.properties2
-rw-r--r--main/libs/jackson-databind-2.5.1.jarbin0 -> 1138921 bytes
-rw-r--r--main/libs/jackson-databind-2.5.1.jar.properties2
-rw-r--r--main/libs/mapsforge-map-0.2.4.jarbin392417 -> 0 bytes
-rw-r--r--main/libs/rxandroid-0.24.0.jarbin0 -> 79811 bytes
-rw-r--r--main/libs/rxandroid-0.24.0.jar.properties2
-rw-r--r--main/libs/rxjava-1.0.8.jarbin0 -> 738300 bytes
-rw-r--r--main/libs/rxjava-1.0.8.jar.properties2
-rw-r--r--main/libs/rxjava-android-0.19.6.jarbin35201 -> 0 bytes
-rw-r--r--main/libs/rxjava-android-0.19.6.jar.properties2
-rw-r--r--main/libs/rxjava-async-util-0.19.6.jarbin47677 -> 0 bytes
-rw-r--r--main/libs/rxjava-async-util-0.19.6.jar.properties2
-rw-r--r--main/libs/rxjava-core-0.19.6.jarbin635914 -> 0 bytes
-rw-r--r--main/libs/rxjava-core-0.19.6.jar.properties2
-rw-r--r--main/libs/src/androidannotations-api-3.2-javadoc.jarbin0 -> 692279 bytes
-rw-r--r--main/libs/src/androidannotations-api-3.2-sources.jarbin0 -> 160807 bytes
-rw-r--r--main/libs/src/annotations-3.0.0-javadoc.jarbin0 -> 362 bytes
-rw-r--r--main/libs/src/annotations-3.0.0-sources.jarbin0 -> 362 bytes
-rw-r--r--main/libs/src/butterknife-6.1.0-javadoc.jarbin0 -> 113755 bytes
-rw-r--r--main/libs/src/butterknife-6.1.0-sources.jarbin0 -> 29195 bytes
-rw-r--r--main/libs/src/commons-collections4-4.0-javadoc.jarbin0 -> 2169984 bytes
-rw-r--r--main/libs/src/commons-lang3-3.3.2-javadoc.jarbin1074965 -> 1074965 bytes
-rw-r--r--main/libs/src/commons-lang3-3.3.2-sources.jarbin0 -> 470961 bytes
-rw-r--r--main/libs/src/jackson-annotations-2.5.1-javadoc.jarbin0 -> 277589 bytes
-rw-r--r--main/libs/src/jackson-annotations-2.5.1-sources.jarbin0 -> 44580 bytes
-rw-r--r--main/libs/src/jackson-core-2.5.1-javadoc.jarbin0 -> 819576 bytes
-rw-r--r--main/libs/src/jackson-core-2.5.1-sources.jarbin0 -> 240812 bytes
-rw-r--r--main/libs/src/jackson-databind-2.5.1-javadoc.jarbin0 -> 4275310 bytes
-rw-r--r--main/libs/src/jackson-databind-2.5.1-sources.jarbin0 -> 820494 bytes
-rw-r--r--main/libs/src/rxandroid-0.24.0-javadoc.jarbin0 -> 96788 bytes
-rw-r--r--main/libs/src/rxandroid-0.24.0-sources.jarbin0 -> 32586 bytes
-rw-r--r--main/libs/src/rxjava-1.0.8-javadoc.jarbin0 -> 416919 bytes
-rw-r--r--main/libs/src/rxjava-1.0.8-sources.jarbin0 -> 403090 bytes
-rw-r--r--main/libs/src/rxjava-android-0.19.6-javadoc.jarbin78283 -> 0 bytes
-rw-r--r--main/libs/src/rxjava-android-0.19.6-sources.jarbin15756 -> 0 bytes
-rw-r--r--main/libs/src/rxjava-async-util-0.19.6-javadoc.jarbin62129 -> 0 bytes
-rw-r--r--main/libs/src/rxjava-async-util-0.19.6-sources.jarbin15553 -> 0 bytes
-rw-r--r--main/libs/src/rxjava-core-0.19.6-javadoc.jarbin796349 -> 0 bytes
-rw-r--r--main/libs/src/rxjava-core-0.19.6-sources.jarbin342298 -> 0 bytes
-rw-r--r--main/lint.xml2
-rw-r--r--main/proguard-project.txt19
-rw-r--r--main/project.properties8
-rw-r--r--main/project/annotations/java/lang/annotations.xml7
-rw-r--r--main/project/annotations/java/util/annotations.xml7
-rw-r--r--main/project/annotations/org/apache/commons/lang3/annotations.xml34
-rw-r--r--main/project/eclipse installation/cgeo eclipse components.p2f77
-rw-r--r--main/project/libraries/.gitignore1
-rw-r--r--main/project/libraries/pom.xml203
-rwxr-xr-xmain/project/libraries/update-libs.sh31
-rw-r--r--main/project/rawimages/new-idea-modified.svg76
-rw-r--r--main/project/rawimages/noun_104277_cc.svg26
-rw-r--r--main/res/drawable-hdpi/ic_menu_hint.pngbin0 -> 1228 bytes
-rw-r--r--main/res/drawable-hdpi/ic_menu_mylocation_off.pngbin0 -> 1848 bytes
-rw-r--r--main/res/drawable-hdpi/star_half.pngbin766 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_barcode.pngbin1866 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_filter.pngbin1193 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_goto.pngbin1317 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_shopping.pngbin1283 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/ic_menu_trail.pngbin1300 -> 0 bytes
-rw-r--r--main/res/drawable-ldpi/star_half.pngbin372 -> 0 bytes
-rw-r--r--main/res/drawable-mdpi/ic_menu_hint.pngbin0 -> 795 bytes
-rw-r--r--main/res/drawable-mdpi/star_half.pngbin522 -> 0 bytes
-rw-r--r--main/res/drawable-xhdpi/ic_menu_hint.pngbin0 -> 1686 bytes
-rw-r--r--main/res/drawable-xxhdpi/ic_menu_hint.pngbin0 -> 2547 bytes
-rw-r--r--main/res/drawable/star_rating.xml9
-rw-r--r--main/res/layout-land/coordinatesinput_dialog.xml11
-rw-r--r--main/res/layout-v11/actionbar_maps.xml54
-rw-r--r--main/res/layout-v14/actionbar_maps.xml7
-rw-r--r--main/res/layout/about_changes_page.xml19
-rw-r--r--main/res/layout/about_contributors_page.xml4
-rw-r--r--main/res/layout/about_help_page.xml262
-rw-r--r--main/res/layout/about_license_page.xml3
-rw-r--r--main/res/layout/about_system_page.xml46
-rw-r--r--main/res/layout/about_version_page.xml5
-rw-r--r--main/res/layout/addresslist_activity.xml3
-rw-r--r--main/res/layout/addresslist_item.xml4
-rw-r--r--main/res/layout/attribute_descriptions.xml18
-rw-r--r--main/res/layout/attribute_image.xml4
-rw-r--r--main/res/layout/authorization_activity.xml4
-rw-r--r--main/res/layout/cache_information_item.xml8
-rw-r--r--main/res/layout/cachedetail_activity.xml4
-rw-r--r--main/res/layout/cachedetail_description_page.xml5
-rw-r--r--main/res/layout/cachedetail_details_page.xml33
-rw-r--r--main/res/layout/cachedetail_images_page.xml4
-rw-r--r--main/res/layout/cachedetail_inventory_page.xml4
-rw-r--r--main/res/layout/cachedetail_waypoints_footer.xml7
-rw-r--r--main/res/layout/cachedetail_waypoints_page.xml4
-rw-r--r--main/res/layout/cachelist_spinneritem.xml11
-rw-r--r--main/res/layout/cacheslist_activity.xml7
-rw-r--r--main/res/layout/cacheslist_footer.xml4
-rw-r--r--main/res/layout/cacheslist_item.xml15
-rw-r--r--main/res/layout/compass_activity.xml18
-rw-r--r--main/res/layout/coordinatesinput_dialog.xml14
-rw-r--r--main/res/layout/editwaypoint_activity.xml21
-rw-r--r--main/res/layout/fieldnote_export_dialog.xml4
-rw-r--r--main/res/layout/filter_activity.xml30
-rw-r--r--main/res/layout/filter_list_child.xml9
-rw-r--r--main/res/layout/fragment_edit_note.xml4
-rw-r--r--main/res/layout/gcvote_dialog.xml10
-rw-r--r--main/res/layout/gcvote_rating_bar.xml26
-rw-r--r--main/res/layout/gpx.xml5
-rw-r--r--main/res/layout/gpx_export_dialog.xml4
-rw-r--r--main/res/layout/gpx_item.xml4
-rw-r--r--main/res/layout/grid_image.xml11
-rw-r--r--main/res/layout/image_item.xml4
-rw-r--r--main/res/layout/images_activity.xml4
-rw-r--r--main/res/layout/images_gridview.xml15
-rw-r--r--main/res/layout/imageselect_activity.xml8
-rw-r--r--main/res/layout/internal_browser.xml16
-rw-r--r--main/res/layout/livemapinfo.xml5
-rw-r--r--main/res/layout/logcache_activity.xml27
-rw-r--r--main/res/layout/logcache_trackable_item.xml4
-rw-r--r--main/res/layout/logs_item.xml4
-rw-r--r--main/res/layout/logs_page.xml1
-rw-r--r--main/res/layout/logtrackable_activity.xml5
-rw-r--r--main/res/layout/main_activity.xml3
-rw-r--r--main/res/layout/main_activity_connectorstatus.xml4
-rw-r--r--main/res/layout/map_google.xml6
-rw-r--r--main/res/layout/map_mapsforge.xml4
-rw-r--r--main/res/layout/map_mapsforge_old.xml42
-rw-r--r--main/res/layout/mapfile_item.xml4
-rw-r--r--main/res/layout/navigateanypoint_activity.xml4
-rw-r--r--main/res/layout/navigateanypoint_header.xml8
-rw-r--r--main/res/layout/popup.xml2
-rw-r--r--main/res/layout/preference_info_icon.xml6
-rw-r--r--main/res/layout/recaptcha_dialog.xml6
-rw-r--r--main/res/layout/search_activity.xml3
-rw-r--r--main/res/layout/simple_dir_chooser.xml4
-rw-r--r--main/res/layout/simple_dir_item.xml4
-rw-r--r--main/res/layout/simple_way_point.xml4
-rw-r--r--main/res/layout/star_image.xml9
-rw-r--r--main/res/layout/staticmaps_activity.xml4
-rw-r--r--main/res/layout/staticmaps_activity_item.xml4
-rw-r--r--main/res/layout/status.xml4
-rw-r--r--main/res/layout/template_preference_dialog.xml4
-rw-r--r--main/res/layout/trackable_details_view.xml4
-rw-r--r--main/res/layout/trackable_image.xml4
-rw-r--r--main/res/layout/usefulapps_activity.xml3
-rw-r--r--main/res/layout/usefulapps_item.xml5
-rw-r--r--main/res/layout/waypoint_item.xml5
-rw-r--r--main/res/layout/waypoint_popup.xml6
-rw-r--r--main/res/menu/abstract_logging_activity.xml5
-rw-r--r--main/res/menu/cache_list_context.xml26
-rw-r--r--main/res/menu/cache_list_options.xml17
-rw-r--r--main/res/menu/cache_options.xml23
-rw-r--r--main/res/menu/compass_activity_options.xml19
-rw-r--r--main/res/menu/details_context.xml2
-rw-r--r--main/res/menu/filter_options.xml12
-rw-r--r--main/res/menu/images_list_context.xml10
-rw-r--r--main/res/menu/logging_ui.xml12
-rw-r--r--main/res/menu/main_activity_options.xml99
-rw-r--r--main/res/menu/map_activity.xml19
-rw-r--r--main/res/menu/navigate_any_point_activity_options.xml2
-rw-r--r--main/res/menu/search_activity_options.xml5
-rw-r--r--main/res/menu/static_maps_activity_options.xml6
-rw-r--r--main/res/menu/trackable_activity.xml12
-rw-r--r--main/res/menu/waypoint_options.xml7
-rw-r--r--main/res/values-ca/strings.xml71
-rw-r--r--main/res/values-cs/strings.xml132
-rw-r--r--main/res/values-da/strings.xml78
-rw-r--r--main/res/values-de/strings.xml116
-rw-r--r--main/res/values-es/strings.xml559
-rw-r--r--main/res/values-fr/strings.xml73
-rw-r--r--main/res/values-hu/strings.xml112
-rw-r--r--main/res/values-it/strings.xml67
-rw-r--r--main/res/values-ja/strings.xml40
-rw-r--r--main/res/values-lt/strings.xml68
-rw-r--r--main/res/values-lv/strings.xml773
-rw-r--r--main/res/values-nb/strings.xml107
-rw-r--r--main/res/values-nl/strings.xml72
-rw-r--r--main/res/values-pl/strings.xml61
-rw-r--r--main/res/values-pt/strings.xml87
-rw-r--r--main/res/values-ro/strings.xml77
-rw-r--r--main/res/values-sk/strings.xml79
-rw-r--r--main/res/values-sl/strings.xml18
-rw-r--r--main/res/values-sv/strings.xml68
-rw-r--r--main/res/values/changelog_release.xml65
-rw-r--r--main/res/values/dimens.xml4
-rw-r--r--main/res/values/ids.xml3
-rw-r--r--main/res/values/preference_keys.xml10
-rw-r--r--main/res/values/strings.xml90
-rw-r--r--main/res/values/strings_not_translatable.xml8
-rw-r--r--main/res/values/styles.xml11
-rw-r--r--main/res/values/themes.xml2
-rw-r--r--main/res/xml/preferences.xml35
-rw-r--r--main/src/cgeo/calendar/CalendarAddon.java14
-rw-r--r--main/src/cgeo/calendar/ICalendar.java27
-rw-r--r--main/src/cgeo/contacts/ContactsAddon.java4
-rw-r--r--main/src/cgeo/contacts/IContacts.java10
-rw-r--r--main/src/cgeo/geocaching/AboutActivity.java115
-rw-r--r--main/src/cgeo/geocaching/AbstractDialogFragment.java24
-rw-r--r--main/src/cgeo/geocaching/AbstractLoggingActivity.java23
-rw-r--r--main/src/cgeo/geocaching/AddressListActivity.java68
-rw-r--r--main/src/cgeo/geocaching/AttributesGridAdapter.java79
-rw-r--r--main/src/cgeo/geocaching/CacheCache.java2
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java945
-rw-r--r--main/src/cgeo/geocaching/CacheListActivity.java525
-rw-r--r--main/src/cgeo/geocaching/CacheMenuHandler.java14
-rw-r--r--main/src/cgeo/geocaching/CachePopupFragment.java30
-rw-r--r--main/src/cgeo/geocaching/CgeoApplication.java89
-rw-r--r--main/src/cgeo/geocaching/CompassActivity.java303
-rw-r--r--main/src/cgeo/geocaching/CreateShortcutActivity.java113
-rw-r--r--main/src/cgeo/geocaching/DataStore.java668
-rw-r--r--main/src/cgeo/geocaching/Destination.java2
-rw-r--r--main/src/cgeo/geocaching/EditWaypointActivity.java176
-rw-r--r--main/src/cgeo/geocaching/Geocache.java394
-rw-r--r--main/src/cgeo/geocaching/GpxFileListActivity.java127
-rw-r--r--main/src/cgeo/geocaching/ICache.java164
-rw-r--r--main/src/cgeo/geocaching/ICoordinates.java2
-rw-r--r--main/src/cgeo/geocaching/Image.java8
-rw-r--r--main/src/cgeo/geocaching/ImageSelectActivity.java101
-rw-r--r--main/src/cgeo/geocaching/ImagesActivity.java14
-rw-r--r--main/src/cgeo/geocaching/Intents.java50
-rw-r--r--main/src/cgeo/geocaching/LogCacheActivity.java160
-rw-r--r--main/src/cgeo/geocaching/LogEntry.java9
-rw-r--r--main/src/cgeo/geocaching/LogTrackableActivity.java72
-rw-r--r--main/src/cgeo/geocaching/MainActivity.java255
-rw-r--r--main/src/cgeo/geocaching/NavigateAnyPointActivity.java121
-rw-r--r--main/src/cgeo/geocaching/PocketQueryList.java15
-rw-r--r--main/src/cgeo/geocaching/SearchActivity.java35
-rw-r--r--main/src/cgeo/geocaching/SearchResult.java19
-rw-r--r--main/src/cgeo/geocaching/SelectMapfileActivity.java10
-rw-r--r--main/src/cgeo/geocaching/StaticMapsActivity.java21
-rw-r--r--main/src/cgeo/geocaching/StaticMapsProvider.java70
-rw-r--r--main/src/cgeo/geocaching/StatusFragment.java13
-rw-r--r--main/src/cgeo/geocaching/Trackable.java68
-rw-r--r--main/src/cgeo/geocaching/TrackableActivity.java368
-rw-r--r--main/src/cgeo/geocaching/UsefulAppsActivity.java26
-rw-r--r--main/src/cgeo/geocaching/Waypoint.java39
-rw-r--r--main/src/cgeo/geocaching/WaypointPopupFragment.java17
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractActivity.java54
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractListActivity.java2
-rw-r--r--main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java2
-rw-r--r--main/src/cgeo/geocaching/activity/ActionBarListActivity.java4
-rw-r--r--main/src/cgeo/geocaching/activity/ActivityMixin.java29
-rw-r--r--main/src/cgeo/geocaching/activity/OAuthAuthorizationActivity.java (renamed from main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java)82
-rw-r--r--main/src/cgeo/geocaching/activity/Progress.java2
-rw-r--r--main/src/cgeo/geocaching/activity/ShowcaseViewBuilder.java1
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractApp.java23
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractAppFactory.java16
-rw-r--r--main/src/cgeo/geocaching/apps/AbstractLocusApp.java38
-rw-r--r--main/src/cgeo/geocaching/apps/App.java5
-rw-r--r--main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java18
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/AbstractRadarApp.java7
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java9
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/AndroidWearApp.java52
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/CacheNavigationApp.java3
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java15
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GeopointNavigationApp.java4
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java20
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java32
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java8
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java8
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java12
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java35
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/NavigationSelectionActionProvider.java18
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java4
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java10
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java50
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java12
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java22
-rw-r--r--main/src/cgeo/geocaching/apps/cache/navi/WaypointNavigationApp.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java6
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java84
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/CacheListApps.java29
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java2
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/ListNavigationSelectionActionProvider.java60
-rw-r--r--main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java17
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel11.java15
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java12
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel11Interface.java9
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel13.java9
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java7
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java3
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19.java4
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java4
-rw-r--r--main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java2
-rw-r--r--main/src/cgeo/geocaching/compatibility/Compatibility.java13
-rw-r--r--main/src/cgeo/geocaching/concurrent/BlockingThreadPool.java57
-rw-r--r--main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java25
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java69
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractLoggingManager.java3
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractLogin.java11
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java54
-rw-r--r--main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java9
-rw-r--r--main/src/cgeo/geocaching/connector/GeopeitusConnector.java11
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java79
-rw-r--r--main/src/cgeo/geocaching/connector/ILoggingManager.java29
-rw-r--r--main/src/cgeo/geocaching/connector/ImageResult.java8
-rw-r--r--main/src/cgeo/geocaching/connector/LogResult.java8
-rw-r--r--main/src/cgeo/geocaching/connector/NoLoggingManager.java13
-rw-r--r--main/src/cgeo/geocaching/connector/UnknownConnector.java22
-rw-r--r--main/src/cgeo/geocaching/connector/UserAction.java12
-rw-r--r--main/src/cgeo/geocaching/connector/WaymarkingConnector.java30
-rw-r--r--main/src/cgeo/geocaching/connector/capability/FieldNotesCapability.java4
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ILogin.java31
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java2
-rw-r--r--main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java5
-rw-r--r--main/src/cgeo/geocaching/connector/capability/IgnoreCapability.java14
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java101
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java59
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java22
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java35
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java115
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConstants.java225
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java40
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLogin.java182
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java177
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java578
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java11
-rw-r--r--main/src/cgeo/geocaching/connector/gc/IconDecoder.java24
-rw-r--r--main/src/cgeo/geocaching/connector/gc/MapTokens.java4
-rw-r--r--main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java10
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Tile.java102
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UTFGrid.java14
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java13
-rw-r--r--main/src/cgeo/geocaching/connector/gc/UncertainProperty.java7
-rw-r--r--main/src/cgeo/geocaching/connector/oc/IOCAuthParams.java9
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiConnector.java14
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java23
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCAuthParams.java2
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java10
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCCZConnector.java34
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCConnector.java40
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java361
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiError.java14
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java10
-rw-r--r--main/src/cgeo/geocaching/connector/oc/UserInfo.java6
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXConnector.java36
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXGPXParser.java1
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java20
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java20
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java21
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java6
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/SwaggieConnector.java51
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/SwaggieParser.java55
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java27
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java22
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java11
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheAttribute.java31
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheListType.java6
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheSize.java28
-rw-r--r--main/src/cgeo/geocaching/enumerations/CacheType.java85
-rw-r--r--main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java48
-rw-r--r--main/src/cgeo/geocaching/enumerations/LoadFlags.java8
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogType.java39
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java7
-rw-r--r--main/src/cgeo/geocaching/enumerations/StatusCode.java6
-rw-r--r--main/src/cgeo/geocaching/enumerations/WaypointType.java23
-rw-r--r--main/src/cgeo/geocaching/export/AbstractExport.java4
-rw-r--r--main/src/cgeo/geocaching/export/FieldNotes.java2
-rw-r--r--main/src/cgeo/geocaching/export/FieldnoteExport.java11
-rw-r--r--main/src/cgeo/geocaching/export/GpxExport.java11
-rw-r--r--main/src/cgeo/geocaching/export/GpxSerializer.java25
-rw-r--r--main/src/cgeo/geocaching/files/AbstractFileListActivity.java32
-rw-r--r--main/src/cgeo/geocaching/files/FileParser.java28
-rw-r--r--main/src/cgeo/geocaching/files/FileTypeDetector.java14
-rw-r--r--main/src/cgeo/geocaching/files/GPX10Parser.java4
-rw-r--r--main/src/cgeo/geocaching/files/GPX11Parser.java4
-rw-r--r--main/src/cgeo/geocaching/files/GPXImporter.java51
-rw-r--r--main/src/cgeo/geocaching/files/GPXParser.java125
-rw-r--r--main/src/cgeo/geocaching/files/IFileSelectionView.java2
-rw-r--r--main/src/cgeo/geocaching/files/InvalidXMLCharacterFilterReader.java185
-rw-r--r--main/src/cgeo/geocaching/files/LocParser.java200
-rw-r--r--main/src/cgeo/geocaching/files/LocalStorage.java88
-rw-r--r--main/src/cgeo/geocaching/files/NoCloseInputStream.java4
-rw-r--r--main/src/cgeo/geocaching/files/ParserException.java4
-rw-r--r--main/src/cgeo/geocaching/files/ProgressInputStream.java6
-rw-r--r--main/src/cgeo/geocaching/files/SimpleDirChooser.java4
-rw-r--r--main/src/cgeo/geocaching/filter/AbstractFilter.java21
-rw-r--r--main/src/cgeo/geocaching/filter/AttributeFilter.java7
-rw-r--r--main/src/cgeo/geocaching/filter/DifficultyFilter.java5
-rw-r--r--main/src/cgeo/geocaching/filter/DistanceFilter.java18
-rw-r--r--main/src/cgeo/geocaching/filter/FilterActivity.java154
-rw-r--r--main/src/cgeo/geocaching/filter/FilterRegistry.java86
-rw-r--r--main/src/cgeo/geocaching/filter/FilterUserInterface.java130
-rw-r--r--main/src/cgeo/geocaching/filter/IFilter.java12
-rw-r--r--main/src/cgeo/geocaching/filter/IFilterFactory.java3
-rw-r--r--main/src/cgeo/geocaching/filter/ModifiedFilter.java8
-rw-r--r--main/src/cgeo/geocaching/filter/OfflineLogFilter.java19
-rw-r--r--main/src/cgeo/geocaching/filter/OriginFilter.java9
-rw-r--r--main/src/cgeo/geocaching/filter/OwnRatingFilter.java34
-rw-r--r--main/src/cgeo/geocaching/filter/PersonalDataFilterFactory.java16
-rw-r--r--main/src/cgeo/geocaching/filter/PersonalNoteFilter.java10
-rw-r--r--main/src/cgeo/geocaching/filter/PopularityFilter.java10
-rw-r--r--main/src/cgeo/geocaching/filter/PopularityRatioFilter.java16
-rw-r--r--main/src/cgeo/geocaching/filter/RatingFilter.java25
-rw-r--r--main/src/cgeo/geocaching/filter/SizeFilter.java12
-rw-r--r--main/src/cgeo/geocaching/filter/StateFilter.java153
-rw-r--r--main/src/cgeo/geocaching/filter/StateFilterFactory.java145
-rw-r--r--main/src/cgeo/geocaching/filter/TerrainFilter.java5
-rw-r--r--main/src/cgeo/geocaching/filter/TrackablesFilter.java15
-rw-r--r--main/src/cgeo/geocaching/filter/TypeFilter.java15
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java239
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVoteDialog.java112
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVoteRatingBarUtil.java58
-rw-r--r--main/src/cgeo/geocaching/list/AbstractList.java4
-rw-r--r--main/src/cgeo/geocaching/list/ListNameMemento.java21
-rw-r--r--main/src/cgeo/geocaching/list/StoredList.java45
-rw-r--r--main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java13
-rw-r--r--main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java23
-rw-r--r--main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java3
-rw-r--r--main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java4
-rw-r--r--main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java3
-rw-r--r--main/src/cgeo/geocaching/loaders/PocketGeocacheListLoader.java2
-rw-r--r--main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java28
-rw-r--r--main/src/cgeo/geocaching/location/AndroidGeocoder.java82
-rw-r--r--main/src/cgeo/geocaching/location/DistanceParser.java (renamed from main/src/cgeo/geocaching/geopoint/DistanceParser.java)4
-rw-r--r--main/src/cgeo/geocaching/location/GCGeocoder.java65
-rw-r--r--main/src/cgeo/geocaching/location/Geopoint.java (renamed from main/src/cgeo/geocaching/geopoint/Geopoint.java)66
-rw-r--r--main/src/cgeo/geocaching/location/GeopointFormatter.java (renamed from main/src/cgeo/geocaching/geopoint/GeopointFormatter.java)2
-rw-r--r--main/src/cgeo/geocaching/location/GeopointParser.java (renamed from main/src/cgeo/geocaching/geopoint/GeopointParser.java)63
-rw-r--r--main/src/cgeo/geocaching/location/IConversion.java (renamed from main/src/cgeo/geocaching/geopoint/IConversion.java)2
-rw-r--r--main/src/cgeo/geocaching/location/MapQuestGeocoder.java135
-rw-r--r--main/src/cgeo/geocaching/location/Units.java (renamed from main/src/cgeo/geocaching/geopoint/Units.java)20
-rw-r--r--main/src/cgeo/geocaching/location/Viewport.java (renamed from main/src/cgeo/geocaching/geopoint/Viewport.java)21
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java16
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractMap.java12
-rw-r--r--main/src/cgeo/geocaching/maps/AbstractMapProvider.java2
-rw-r--r--main/src/cgeo/geocaching/maps/CGeoMap.java464
-rw-r--r--main/src/cgeo/geocaching/maps/CachesOverlay.java46
-rw-r--r--main/src/cgeo/geocaching/maps/DirectionDrawer.java60
-rw-r--r--main/src/cgeo/geocaching/maps/DistanceDrawer.java130
-rw-r--r--main/src/cgeo/geocaching/maps/LivemapStrategy.java45
-rw-r--r--main/src/cgeo/geocaching/maps/MapActivity.java17
-rw-r--r--main/src/cgeo/geocaching/maps/MapProviderFactory.java13
-rw-r--r--main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java43
-rw-r--r--main/src/cgeo/geocaching/maps/PositionDrawer.java50
-rw-r--r--main/src/cgeo/geocaching/maps/PositionHistory.java6
-rw-r--r--main/src/cgeo/geocaching/maps/ScaleDrawer.java10
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java3
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java2
-rw-r--r--main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java5
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java26
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java22
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapController.java20
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java4
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProjection.java6
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java50
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapSource.java2
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java57
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java11
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java113
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java37
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeGeoPoint.java18
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java124
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapController.java55
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java20
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapProjection.java29
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java254
-rw-r--r--main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java54
-rw-r--r--main/src/cgeo/geocaching/network/AndroidBeam.java93
-rw-r--r--main/src/cgeo/geocaching/network/Cookies.java2
-rw-r--r--main/src/cgeo/geocaching/network/DownloadProgress.java15
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java202
-rw-r--r--main/src/cgeo/geocaching/network/Network.java83
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java18
-rw-r--r--main/src/cgeo/geocaching/network/OAuthTokens.java38
-rw-r--r--main/src/cgeo/geocaching/network/Parameters.java1
-rw-r--r--main/src/cgeo/geocaching/network/Send2CgeoDownloader.java70
-rw-r--r--main/src/cgeo/geocaching/network/SmileyImage.java40
-rw-r--r--main/src/cgeo/geocaching/network/StatusUpdater.java23
-rw-r--r--main/src/cgeo/geocaching/playservices/LocationProvider.java160
-rw-r--r--main/src/cgeo/geocaching/sensors/DirectionProvider.java146
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoData.java128
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoDataProvider.java255
-rw-r--r--main/src/cgeo/geocaching/sensors/GeoDirHandler.java69
-rw-r--r--main/src/cgeo/geocaching/sensors/GpsStatusProvider.java99
-rw-r--r--main/src/cgeo/geocaching/sensors/IGeoData.java22
-rw-r--r--main/src/cgeo/geocaching/sensors/LocationProviderType.java (renamed from main/src/cgeo/geocaching/enumerations/LocationProviderType.java)5
-rw-r--r--main/src/cgeo/geocaching/sensors/OrientationProvider.java72
-rw-r--r--main/src/cgeo/geocaching/sensors/RotationProvider.java97
-rw-r--r--main/src/cgeo/geocaching/sensors/Sensors.java165
-rw-r--r--main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java11
-rw-r--r--main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java15
-rw-r--r--main/src/cgeo/geocaching/settings/AbstractClickablePreference.java6
-rw-r--r--main/src/cgeo/geocaching/settings/CapabilitiesPreference.java22
-rw-r--r--main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java14
-rw-r--r--main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java4
-rw-r--r--main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java7
-rw-r--r--main/src/cgeo/geocaching/settings/EditPasswordPreference.java8
-rw-r--r--main/src/cgeo/geocaching/settings/InfoPreference.java22
-rw-r--r--main/src/cgeo/geocaching/settings/OAuthPreference.java2
-rw-r--r--main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java24
-rw-r--r--main/src/cgeo/geocaching/settings/Settings.java320
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java93
-rw-r--r--main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java10
-rw-r--r--main/src/cgeo/geocaching/sorting/DateComparator.java22
-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/EventDateComparator.java14
-rw-r--r--main/src/cgeo/geocaching/sorting/FindsComparator.java10
-rw-r--r--main/src/cgeo/geocaching/sorting/GeocodeComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/InventoryComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/InverseComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/NameComparator.java13
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java9
-rw-r--r--main/src/cgeo/geocaching/sorting/RatingComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/SizeComparator.java9
-rw-r--r--main/src/cgeo/geocaching/sorting/SortActionProvider.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/StateComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/StorageTimeComparator.java4
-rw-r--r--main/src/cgeo/geocaching/sorting/TerrainComparator.java2
-rw-r--r--main/src/cgeo/geocaching/sorting/VoteComparator.java4
-rw-r--r--main/src/cgeo/geocaching/speech/SpeechService.java13
-rw-r--r--main/src/cgeo/geocaching/speech/TextFactory.java22
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java20
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java6
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java14
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java1
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractImageAdapter.java66
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractMenuActionProvider.java24
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractUserClickListener.java8
-rw-r--r--main/src/cgeo/geocaching/ui/AbstractViewHolder.java2
-rw-r--r--main/src/cgeo/geocaching/ui/AddressListAdapter.java13
-rw-r--r--main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java4
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java90
-rw-r--r--main/src/cgeo/geocaching/ui/CacheListAdapter.java41
-rw-r--r--main/src/cgeo/geocaching/ui/CompassMiniView.java23
-rw-r--r--main/src/cgeo/geocaching/ui/CompassView.java16
-rw-r--r--main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java10
-rw-r--r--main/src/cgeo/geocaching/ui/DecryptTextClickListener.java77
-rw-r--r--main/src/cgeo/geocaching/ui/DirectionImage.java10
-rw-r--r--main/src/cgeo/geocaching/ui/DistanceView.java12
-rw-r--r--main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java2
-rw-r--r--main/src/cgeo/geocaching/ui/ImagesList.java12
-rw-r--r--main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java18
-rw-r--r--main/src/cgeo/geocaching/ui/LoggingUI.java15
-rw-r--r--main/src/cgeo/geocaching/ui/NavigationActionProvider.java4
-rw-r--r--main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java4
-rw-r--r--main/src/cgeo/geocaching/ui/UrlPopup.java8
-rw-r--r--main/src/cgeo/geocaching/ui/UserActionsClickListener.java6
-rw-r--r--main/src/cgeo/geocaching/ui/WeakReferenceHandler.java1
-rw-r--r--main/src/cgeo/geocaching/ui/WrappingGridView.java38
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java63
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/DateDialog.java6
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/Dialogs.java48
-rw-r--r--main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java4
-rw-r--r--main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java51
-rw-r--r--main/src/cgeo/geocaching/ui/logs/EditOfflineLogListener.java25
-rw-r--r--main/src/cgeo/geocaching/ui/logs/LogViewHolder.java2
-rw-r--r--main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java17
-rw-r--r--main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java21
-rw-r--r--main/src/cgeo/geocaching/utils/AngleUtils.java43
-rw-r--r--main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java14
-rw-r--r--main/src/cgeo/geocaching/utils/BundleUtils.java4
-rw-r--r--main/src/cgeo/geocaching/utils/CalendarUtils.java (renamed from main/src/cgeo/geocaching/utils/DateUtils.java)23
-rw-r--r--main/src/cgeo/geocaching/utils/CancellableHandler.java2
-rw-r--r--main/src/cgeo/geocaching/utils/CheckerUtils.java35
-rw-r--r--main/src/cgeo/geocaching/utils/ClipboardUtils.java17
-rw-r--r--main/src/cgeo/geocaching/utils/CryptUtils.java84
-rw-r--r--main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java123
-rw-r--r--main/src/cgeo/geocaching/utils/DebugUtils.java7
-rw-r--r--main/src/cgeo/geocaching/utils/EditUtils.java6
-rw-r--r--main/src/cgeo/geocaching/utils/FileUtils.java61
-rw-r--r--main/src/cgeo/geocaching/utils/Formatter.java83
-rw-r--r--main/src/cgeo/geocaching/utils/HtmlUtils.java31
-rw-r--r--main/src/cgeo/geocaching/utils/ImageUtils.java180
-rw-r--r--main/src/cgeo/geocaching/utils/JsonUtils.java20
-rw-r--r--main/src/cgeo/geocaching/utils/LazyInitializedList.java2
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java23
-rw-r--r--main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java89
-rw-r--r--main/src/cgeo/geocaching/utils/Log.java27
-rw-r--r--main/src/cgeo/geocaching/utils/LogTemplateProvider.java2
-rw-r--r--main/src/cgeo/geocaching/utils/MapUtils.java3
-rw-r--r--main/src/cgeo/geocaching/utils/MatcherWrapper.java16
-rw-r--r--main/src/cgeo/geocaching/utils/OOMDumpingUncaughtExceptionHandler.java7
-rw-r--r--main/src/cgeo/geocaching/utils/ProcessUtils.java44
-rw-r--r--main/src/cgeo/geocaching/utils/RxUtils.java179
-rw-r--r--main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java30
-rw-r--r--main/src/cgeo/geocaching/utils/StartableHandlerThread.java80
-rw-r--r--main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java2
-rw-r--r--main/src/cgeo/geocaching/utils/TextUtils.java83
-rw-r--r--main/src/cgeo/geocaching/utils/UnknownTagsHandler.java14
-rw-r--r--main/src/cgeo/geocaching/utils/XmlUtils.java2
-rw-r--r--main/templates/keys.xml2
-rw-r--r--main/thirdparty/android/support/v4/app/FragmentListActivity.java10
-rw-r--r--main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java1
-rw-r--r--main/thirdparty/com/google/zxing/integration/android/IntentIntegrator.java2
-rw-r--r--main/thirdparty/menion/android/locus/LocusDataStorageProvider.java (renamed from main/src/cgeo/geocaching/apps/LocusDataStorageProvider.java)2
616 files changed, 14814 insertions, 9754 deletions
diff --git a/main/.factorypath b/main/.factorypath
index 1440abd..289e9ae 100644
--- a/main/.factorypath
+++ b/main/.factorypath
@@ -1,4 +1,4 @@
<factorypath>
- <factorypathentry kind="WKSPJAR" id="/cgeo/libs/butterknife-5.1.1.jar" enabled="true" runInBatchMode="false"/>
- <factorypathentry kind="WKSPJAR" id="/cgeo/compile-libs/androidannotations-3.0.1.jar" enabled="true" runInBatchMode="false"/>
+ <factorypathentry kind="WKSPJAR" id="/cgeo/libs/butterknife-6.1.0.jar" enabled="true" runInBatchMode="false"/>
+ <factorypathentry kind="WKSPJAR" id="/cgeo/compile-libs/androidannotations-3.2.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 0de28b5..70c3ee6 100644
--- a/main/.settings/org.eclipse.jdt.core.prefs
+++ b/main/.settings/org.eclipse.jdt.core.prefs
@@ -49,9 +49,9 @@ org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
@@ -61,7 +61,7 @@ org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
-org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=no_tag
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
diff --git a/main/.settings/org.eclipse.jdt.ui.prefs b/main/.settings/org.eclipse.jdt.ui.prefs
index 4d4a905..4c0bdef 100644
--- a/main/.settings/org.eclipse.jdt.ui.prefs
+++ b/main/.settings/org.eclipse.jdt.ui.prefs
@@ -6,13 +6,15 @@ 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.javadoc=false
org.eclipse.jdt.ui.keywordthis=false
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.overrideannotation=true
org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * \n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * \n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
-sp_cleanup.add_missing_annotations=false
+sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
@@ -41,15 +43,15 @@ sp_cleanup.organize_imports=true
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
-sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_redundant_type_arguments=false
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
-sp_cleanup.remove_unnecessary_casts=false
-sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
sp_cleanup.remove_unused_imports=true
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
diff --git a/main/.settings/org.moreunit.prefs b/main/.settings/org.moreunit.prefs
new file mode 100644
index 0000000..17ff166
--- /dev/null
+++ b/main/.settings/org.moreunit.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.moreunit.preferences.version=2
+org.moreunit.unitsourcefolder=cgeo\:src\:cgeo-test\:src\#cgeo\:src\:cgeo-test\:gen
+org.moreunit.useprojectsettings=true
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml
index dfc1e43..372e4b9 100644
--- a/main/AndroidManifest.xml
+++ b/main/AndroidManifest.xml
@@ -7,7 +7,7 @@
<uses-sdk
android:minSdkVersion="9"
- android:targetSdkVersion="19" />
+ android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -45,16 +45,34 @@
android:name="com.google.android.maps"
android:required="false" />
+ <!-- Samsung Multi-Window support -->
+ <uses-library
+ android:name="com.sec.android.app.multiwindow"
+ android:required="false" />
+
+ <meta-data
+ android:name="com.sec.android.support.multiwindow"
+ android:value="true" />
+ <meta-data
+ android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W"
+ android:resource="@dimen/app_defaultsize_w" />
+ <meta-data
+ android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H"
+ android:resource="@dimen/app_defaultsize_h" />
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchActivity" />
<meta-data
android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAIsvD_aUSDMwWOf9NkwwxZ4kJJI_AG2EaxjSu2jw" />
+ <meta-data
+ android:name="com.google.android.gms.version"
+ android:value="@integer/google_play_services_version" />
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="true"
android:label="@string/app_name"
android:theme="@style/cgeo_main"
android:windowSoftInputMode="stateHidden" >
@@ -68,14 +86,24 @@
<activity
android:name=".SearchActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTop"
android:parentActivityName="cgeo.geocaching.MainActivity"
android:windowSoftInputMode="stateHidden" >
+
+ <!-- keyword based search from search widget -->
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
-
+
+ <!-- This can trigger our app from Google Now by something like "Search for keyword on c:geo".
+ See http://developer.android.com/guide/components/intents-common.html#Search -->
+ <intent-filter>
+ <action android:name="com.google.android.gms.actions.SEARCH_ACTION"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="cgeo.geocaching.MainActivity" />
@@ -136,6 +164,7 @@
<activity
android:name=".NavigateAnyPointActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="true"
android:label="@string/search_destination"
android:parentActivityName="cgeo.geocaching.MainActivity"
android:windowSoftInputMode="stateHidden" >
@@ -166,6 +195,7 @@
<activity
android:name=".CacheListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="true"
android:label="@string/app_name"
android:parentActivityName="cgeo.geocaching.MainActivity" >
<meta-data
@@ -207,6 +237,11 @@
</intent-filter>
</activity>
<activity
+ android:exported="true"
+ android:name=".maps.MapActivity"
+ android:label="@string/map_map" >
+ </activity>
+ <activity
android:name=".maps.google.v1.GoogleMapActivity"
android:label="@string/map_map" >
</activity>
@@ -245,8 +280,37 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+
+ <!-- extremcaching.com -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="extremcaching.com"
+ android:pathPrefix="/index.php/output-2/"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.extremcaching.com"
+ android:pathPrefix="/index.php/output-2/"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- geocaching.com -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -258,6 +322,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -269,6 +334,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -280,6 +346,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -289,8 +356,49 @@
android:pathPrefix="/seek/cache_details.aspx"
android:scheme="http" />
</intent-filter>
+
+ <!-- opencaching.CZ -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.cz"
+ android:pathPrefix="/OZ"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.cz"
+ android:pathPrefix="/OZ"
+ android:scheme="http" />
+ </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.cz"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.DE -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -302,6 +410,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -313,6 +422,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -322,7 +432,350 @@
android:pathPrefix="/viewcache.php"
android:scheme="http" />
</intent-filter>
+
+ <!-- opencaching.ES -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencachingspain.es"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencachingspain.es"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencachingspain.es"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.FR -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.fr"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.fr"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.fr"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.IT -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.it"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.it"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.it"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.NO -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.no"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.no"
+ android:pathPrefix="/OC"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.no"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.NL -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.nl"
+ android:pathPrefix="/OB"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.nl"
+ android:pathPrefix="/OB"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.nl"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.PL -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.pl"
+ android:pathPrefix="/OP"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.pl"
+ android:pathPrefix="/OP"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.pl"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.ORG.UK -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.org.uk"
+ android:pathPrefix="/OK"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.org.uk"
+ android:pathPrefix="/OK"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.org.uk"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.RO -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.ro"
+ android:pathPrefix="/OR"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.ro"
+ android:pathPrefix="/OR"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.ro"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- opencaching.US -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="opencaching.us"
+ android:pathPrefix="/OU"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.us"
+ android:pathPrefix="/OU"
+ android:scheme="http" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="www.opencaching.us"
+ android:pathPrefix="/viewcache.php"
+ android:scheme="http" />
+ </intent-filter>
</activity>
+
<activity
android:name="cgeo.geocaching.TrackableActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
@@ -331,6 +784,7 @@
<!-- TravelBug URL via coord.info redirection -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -342,6 +796,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -355,6 +810,7 @@
<!-- TravelBug URL tracking page -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -366,6 +822,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -376,9 +833,24 @@
android:scheme="http" />
</intent-filter>
- <!-- GeoKrety URLs -->
+ <!-- geocaching.com.au swaggies -->
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data
+ android:host="geocaching.com.au"
+ android:pathPrefix="/swaggie/sw"
+ android:scheme="http" />
+ </intent-filter>
+
+ <!-- GeoKrety.org -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -390,6 +862,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
@@ -400,31 +873,32 @@
android:scheme="http" />
</intent-filter>
- <!--
- Geokrety QR code URLs, not yet implemented
+ <!-- GeoKretyMap.org -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<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:host="geokretymap.org"
+ android:pathPrefix="/"
android:scheme="http" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
<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:host="www.geokretymap.org"
+ android:pathPrefix="/"
android:scheme="http" />
</intent-filter>
- -->
+
</activity>
<activity
android:name=".CompassActivity"
@@ -501,9 +975,14 @@
</activity>
+ <activity
+ android:name=".filter.FilterActivity_"
+ android:label="@string/caches_filter_title" >
+ </activity>
+
<!-- provide enhanced meta data for caches (and waypoints) when invoking Locus from c:geo -->
<provider
- android:name=".apps.LocusDataStorageProvider"
+ android:name="menion.android.locus.LocusDataStorageProvider"
android:authorities="cgeo.geocaching.apps.locusdatastorageprovider" />
<!-- search suggestions for the search bar at the top -->
@@ -512,4 +991,4 @@
android:authorities="cgeo.geocaching.search.SuggestionProvider" />
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/main/build.gradle b/main/build.gradle
index e809018..06a36e8 100644
--- a/main/build.gradle
+++ b/main/build.gradle
@@ -26,15 +26,22 @@ gradle connectedCheck
//Testing guide : http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing
//https://github.com/stephanenicolas/Quality-Tools-for-Android
-def AAVersion = '3.0.1'
-def RXVersion = '0.19.6'
+def AAVersion = '3.2'
+def RXJavaVersion = '1.0.8'
+def RXAndroidVersion = '0.24.0'
+def JacksonCoreVersion = '2.5.1'
+def JacksonDatabindVersion = '2.5.1'
+def JacksonAnnotationsVersion = '2.5.1'
+def CommonsCollections4Version = '4.0'
+def CommonsLang3Version = '3.3.2'
+def CommonsIoVersion = '2.4'
group = 'cgeo.geocaching'
version = '0.0.1'
android {
//compileSdkVersion "Google Inc.:Google APIs:19"
compileSdkVersion 19
- buildToolsVersion "19.1.0"
+ buildToolsVersion "21.1.2"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
@@ -61,9 +68,7 @@ android {
// NOTE: must match the package in the test directory and must be different from the app package
testApplicationId "cgeo.geocaching.test"
- // standard android test runner
- //testInstrumentationRunner "android.test.InstrumentationTestRunner"
- testInstrumentationRunner "com.zutubi.android.junitreport.JUnitReportTestRunner"
+ testInstrumentationRunner "cgeo.junit.CgeoTestRunner"
//testHandlingProfiling true
testFunctionalTest true
@@ -81,8 +86,8 @@ android {
//packageNameSuffix ".debug"
//zipAlign = true
debuggable true
- runProguard false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), '../tests/proguard.cfg'
+ runProguard true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
versionNameSuffix " Debug " + versionProps['betaNumber']
}
release {
@@ -152,19 +157,23 @@ dependencies {
compile files('libs/mapsforge-map-0.3.0-jar-with-dependencies.jar')
compile 'com.android.support:appcompat-v7:19.1.0'
+ compile 'com.google.android.gms:play-services:6.5.+'
+
+ compile 'com.jakewharton:butterknife:6.1.0'
+ compile "org.apache.commons:commons-collections4:$CommonsCollections4Version"
+ compile "org.apache.commons:commons-lang3:$CommonsLang3Version"
+ compile "commons-io:commons-io:$CommonsIoVersion"
+ compile 'com.google.code.findbugs:annotations:3.0.0'
- compile 'com.jakewharton:butterknife:5.1.1'
- compile 'org.apache.commons:commons-collections4:4.0'
- compile 'org.apache.commons:commons-lang3:3.3.2'
- compile 'commons-io:commons-io:2.4'
- compile 'com.google.code.findbugs:annotations:2.0.3'
+ compile "io.reactivex:rxjava:$RXJavaVersion"
+ compile "io.reactivex:rxandroid:$RXAndroidVersion"
- compile "com.netflix.rxjava:rxjava-core:$RXVersion"
- compile "com.netflix.rxjava:rxjava-android:$RXVersion"
- compile "com.netflix.rxjava:rxjava-async-util:$RXVersion"
+ compile "com.fasterxml.jackson.core:jackson-core:$JacksonCoreVersion"
+ compile "com.fasterxml.jackson.core:jackson-databind:$JacksonDatabindVersion"
+ compile "com.fasterxml.jackson.core:jackson-annotations:$JacksonAnnotationsVersion"
//TEST
- //compile files('compile-libs/androidannotations-3.0.1.jar')
+ //compile files('compile-libs/androidannotations-3.2.jar')
//compile files('compile-libs/findbugs-ant.jar')
//compile files('compile-libs/findbugs-jsr305.jar') //CheckForNull conflict with com.google.code.findbugs:annotations
compile files('compile-libs/org.eclipse.jdt.annotation_1.1.0.v20130513-1648.jar')
@@ -202,7 +211,7 @@ apt {
//http://www.gradle.org/docs/current/dsl/org.gradle.api.plugins.quality.FindBugsExtension.html
findbugs {
- toolVersion = "2.0.1"
+ toolVersion = "3.0.0"
//sourceSets = [sourceSets.main]
ignoreFailures = true
reportsDir = file("$project.buildDir/reports")
@@ -249,11 +258,11 @@ dependencies {
unitTestCompile 'com.google.android:android-test:4.1.1.4'
unitTestCompile 'com.googlecode.androidannotations:androidannotations-api:$AAVersion'
- unitTestCompile 'com.jakewharton:butterknife:5.1.1'
+ unitTestCompile 'com.jakewharton:butterknife:6.1.0'
unitTestCompile 'org.apache.commons:commons-collections4:4.0'
unitTestCompile 'commons-io:commons-io:2.4'
- unitTestCompile 'org.apache.commons:commons-lang3:3.3.2'
- unitTestCompile 'com.google.code.findbugs:annotations:2.0.3'
+ unitTestCompile 'org.apache.commons:commons-lang3:$CommonsLang3Version'
+ unitTestCompile 'com.google.code.findbugs:annotations:3.0.0'
unitTestCompile 'com.netflix.rxjava:rxjava-core:$RXVersion'
unitTestCompile 'com.netflix.rxjava:rxjava-android:$RXVersion'
}
diff --git a/main/build.xml b/main/build.xml
index 43c37b2..5eb7768 100644
--- a/main/build.xml
+++ b/main/build.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="cgeo">
- <!-- The local.properties file is created and updated by the 'android' tool.
+ <!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
- <loadproperties srcFile="local.properties" />
+ <loadproperties srcFile="local.properties" />
- <!-- The ant.properties file can be created by you. It is only edited by the
+ <!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
@@ -26,9 +26,9 @@
application and should be checked into Version Control Systems.
-->
- <property file="ant.properties" />
+ <property file="ant.properties" />
- <!-- The project.properties file is created and updated by the 'android'
+ <!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
@@ -37,36 +37,48 @@
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- The private.properties file sets api-keys as well as keystore,
+ <loadproperties srcFile="project.properties" />
+
+ <!-- The private.properties file sets api-keys as well as keystore,
certificate and passwords (if you want).
See /templates/private.properties for more information. -->
- <property file="private.properties" />
+ <property file="private.properties" />
- <!-- quick check on sdk.dir -->
- <fail
+ <!-- quick check on sdk.dir -->
+ <fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
unless="sdk.dir"
/>
-
- <!-- Custom targets -->
- <target name="install_release" description="Install signed release application" depends="release">
- <exec executable="${sdk.dir}/platform-tools/adb">
- <arg line="-d install -r ./bin/${ant.project.name}-release.apk" />
- </exec>
- </target>
-
- <target name="debugAPI" depends="-pre-build"
+
+ <!-- Custom targets -->
+ <target name="install_release" description="Install signed release application" depends="release">
+ <exec executable="${sdk.dir}/platform-tools/adb">
+ <arg line="-d install -r ./bin/${ant.project.name}-release.apk" />
+ </exec>
+ </target>
+
+ <target name="run_release" description="Run signed release application" depends="install_release">
+ <exec executable="${sdk.dir}/platform-tools/adb">
+ <arg line="-d shell am start -n cgeo.geocaching/.MainActivity" />
+ </exec>
+ </target>
+
+ <target name="debugAPI" depends="-pre-build"
description="Changes API key to debug">
- </target>
-
+ </target>
+
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask">
<classpath>
- <pathelement location="./compile-libs/findbugs-ant.jar"/>
+ <pathelement location="./compile-libs/findbugs-ant.jar"/>
</classpath>
</taskdef>
+ <!-- We need to enable ProGuard in debug mode as we otherwise run into the 64 K methods dex limit.
+ As long as we don't obfuscate, we can even use the same ProGuard config in both builds. -->
+ <target name="-debug-obfuscation-check">
+ <property name="proguard.enabled" value="true"/>
+ </target>
+
<target name="findbugs">
<mkdir dir="reports" />
<gettarget
@@ -81,67 +93,83 @@
outputFile="reports/findbugs.xml"
excludefilter="project/findbugs/exclusions.xml"
effort="max"
- reportLevel="low">
+ reportLevel="low"
+ jvmargs="-Xmx1024m">
<auxClasspath path="${project.target.android.jar}" />
<class location="${out.dir}" />
</findbugs>
</target>
-
+
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
- <target name="-pre-build">
- <condition property="build.mode.release" else="false">
- <equals arg1="${build.target}" arg2="release" />
- </condition>
-
- <if condition="${build.mode.release}">
- <then>
- <filterset id="maps-key">
- <filter token="maps.api.key" value="${maps.api.key.market}"/>
- </filterset>
- </then>
- <else>
- <filterset id="maps-key">
- <filter token="maps.api.key" value="${maps.api.key}"/>
- </filterset>
- </else>
- </if>
- <copy file="./templates/keys.xml" todir="./res/values/" overwrite="true">
- <filterset refid="maps-key" />
- <filterset>
- <filter token="ocde.okapi.consumer.key" value="${ocde.okapi.consumer.key}"/>
- <filter token="ocde.okapi.consumer.secret" value="${ocde.okapi.consumer.secret}"/>
- <filter token="ocpl.okapi.consumer.key" value="${ocpl.okapi.consumer.key}"/>
- <filter token="ocpl.okapi.consumer.secret" value="${ocpl.okapi.consumer.secret}"/>
- <filter token="ocus.okapi.consumer.key" value="${ocus.okapi.consumer.key}"/>
- <filter token="ocus.okapi.consumer.secret" value="${ocus.okapi.consumer.secret}"/>
- <filter token="ocnl.okapi.consumer.key" value="${ocnl.okapi.consumer.key}"/>
- <filter token="ocnl.okapi.consumer.secret" value="${ocnl.okapi.consumer.secret}"/>
- <filter token="ocro.okapi.consumer.key" value="${ocro.okapi.consumer.key}"/>
- <filter token="ocro.okapi.consumer.secret" value="${ocro.okapi.consumer.secret}"/>
- <filter token="ocuk.okapi.consumer.key" value="${ocuk.okapi.consumer.key}"/>
- <filter token="ocuk.okapi.consumer.secret" value="${ocuk.okapi.consumer.secret}"/>
- </filterset>
- </copy>
- </target>
+ <target name="-pre-build">
+ <!-- Enable ProGuard in debug builds -->
+ <condition property="proguard.enabled" value="true" else="false">
+ <isset property="proguard.config" />
+ </condition>
+ <if condition="${proguard.enabled}">
+ <then>
+ <echo level="info">Proguard.config is enabled</echo>
+ <!-- Secondary dx input (jar files) is empty since all the jar files will be in the obfuscated jar -->
+ <path id="out.dex.jar.input.ref" />
+ </then>
+ <else>
+ <echo level="info">Proguard.config is disabled</echo>
+ </else>
+ </if>
+
+ <!-- Add all the keys for Google Maps, Twitter and OKAPI in the build -->
+ <condition property="build.mode.release" else="false">
+ <equals arg1="${build.target}" arg2="release" />
+ </condition>
+ <if condition="${build.mode.release}">
+ <then>
+ <filterset id="maps-key">
+ <filter token="maps.api.key" value="${maps.api.key.market}" />
+ </filterset>
+ </then>
+ <else>
+ <filterset id="maps-key">
+ <filter token="maps.api.key" value="${maps.api.key}"/>
+ </filterset>
+ </else>
+ </if>
+ <copy file="./templates/keys.xml" todir="./res/values/" overwrite="true">
+ <filterset refid="maps-key" />
+ <filterset>
+ <filter token="ocde.okapi.consumer.key" value="${ocde.okapi.consumer.key}"/>
+ <filter token="ocde.okapi.consumer.secret" value="${ocde.okapi.consumer.secret}"/>
+ <filter token="ocpl.okapi.consumer.key" value="${ocpl.okapi.consumer.key}"/>
+ <filter token="ocpl.okapi.consumer.secret" value="${ocpl.okapi.consumer.secret}"/>
+ <filter token="ocus.okapi.consumer.key" value="${ocus.okapi.consumer.key}"/>
+ <filter token="ocus.okapi.consumer.secret" value="${ocus.okapi.consumer.secret}"/>
+ <filter token="ocnl.okapi.consumer.key" value="${ocnl.okapi.consumer.key}"/>
+ <filter token="ocnl.okapi.consumer.secret" value="${ocnl.okapi.consumer.secret}"/>
+ <filter token="ocro.okapi.consumer.key" value="${ocro.okapi.consumer.key}"/>
+ <filter token="ocro.okapi.consumer.secret" value="${ocro.okapi.consumer.secret}"/>
+ <filter token="ocuk.okapi.consumer.key" value="${ocuk.okapi.consumer.key}"/>
+ <filter token="ocuk.okapi.consumer.secret" value="${ocuk.okapi.consumer.secret}"/>
+ </filterset>
+ </copy>
+ </target>
-<!-- start of modifications for android annotations, see https://github.com/excilys/androidannotations/wiki/Building-Project-Ant -->
+ <!-- start of modifications for android annotations, see https://github.com/excilys/androidannotations/wiki/Building-Project-Ant -->
<property name="generated.dir" value="annotation_gen" />
<property name="generated.absolute.dir" location="${generated.dir}" />
- <property name="java.compilerargs" value="-s &apos;${generated.absolute.dir}&apos;" />
+ <property name="java.compilerargs" value="-s &apos;${generated.absolute.dir}&apos;" />
<target name="-pre-compile">
<mkdir dir="${generated.absolute.dir}" />
</target>
- <target name="-compile" depends="-pre-build, -build-setup, -code-gen, -pre-compile">
- <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
- <!-- merge the project's own classpath and the tested project's classpath -->
- <path id="project.javac.classpath">
- <path refid="project.all.jars.path" />
- <path refid="tested.project.classpath" />
- <path path="${java.compiler.classpath}" />
- <fileset dir="compile-libs" includes="*.jar"/>
- </path>
- <javac encoding="${java.encoding}"
+ <target name="-compile" depends="-pre-build, -build-setup, -code-gen, -pre-compile">
+ <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
+ <!-- merge the project's own classpath and the tested project's classpath -->
+ <path id="project.javac.classpath">
+ <path refid="project.all.jars.path" />
+ <path refid="tested.project.classpath" />
+ <path path="${java.compiler.classpath}" />
+ <fileset dir="compile-libs" includes="*.jar"/>
+ </path>
+ <javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
@@ -149,77 +177,77 @@
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}">
- <src path="${source.absolute.dir}" />
- <src path="${gen.absolute.dir}" />
- <compilerarg line="${java.compilerargs}" />
- </javac>
-
- <!-- if the project is instrumented, intrument the classes -->
- <if condition="${build.is.instrumented}">
- <then>
- <echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo>
-
- <!-- build the filter to remove R, Manifest, BuildConfig -->
- <getemmafilter
+ <src path="${source.absolute.dir}" />
+ <src path="${gen.absolute.dir}" />
+ <compilerarg line="${java.compilerargs}" />
+ </javac>
+
+ <!-- if the project is instrumented, intrument the classes -->
+ <if condition="${build.is.instrumented}">
+ <then>
+ <echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo>
+
+ <!-- build the filter to remove R, Manifest, BuildConfig -->
+ <getemmafilter
appPackage="${project.app.package}"
libraryPackagesRefId="project.library.packages"
filterOut="emma.default.filter"/>
- <!-- define where the .em file is going. This may have been
+ <!-- define where the .em file is going. This may have been
setup already if this is a library -->
- <property name="emma.coverage.absolute.file" location="${out.absolute.dir}/coverage.em" />
+ <property name="emma.coverage.absolute.file" location="${out.absolute.dir}/coverage.em" />
- <!-- It only instruments class files, not any external libs -->
- <emma enabled="true">
- <instr verbosity="${verbosity}"
+ <!-- It only instruments class files, not any external libs -->
+ <emma enabled="true">
+ <instr verbosity="${verbosity}"
mode="overwrite"
instrpath="${out.absolute.dir}/classes"
outdir="${out.absolute.dir}/classes"
metadatafile="${emma.coverage.absolute.file}">
- <filter excludes="${emma.default.filter}" />
- <filter excludes="android.*, com.*, org.*" />
- <filter value="${emma.filter}" />
- </instr>
- </emma>
- </then>
- </if>
-
- <!-- if the project is a library then we generate a jar file -->
- <if condition="${project.is.library}">
- <then>
- <echo level="info">Creating library output jar file...</echo>
- <property name="out.library.jar.file" location="${out.absolute.dir}/classes.jar" />
- <if>
- <condition>
- <length string="${android.package.excludes}" trim="true" when="greater" length="0" />
- </condition>
- <then>
- <echo level="info">Custom jar packaging exclusion: ${android.package.excludes}</echo>
- </then>
- </if>
-
- <propertybyreplace name="project.app.package.path" input="${project.app.package}" replace="." with="/" />
-
- <jar destfile="${out.library.jar.file}">
- <fileset dir="${out.classes.absolute.dir}"
+ <filter excludes="${emma.default.filter}" />
+ <filter excludes="android.*, com.*, org.*" />
+ <filter value="${emma.filter}" />
+ </instr>
+ </emma>
+ </then>
+ </if>
+
+ <!-- if the project is a library then we generate a jar file -->
+ <if condition="${project.is.library}">
+ <then>
+ <echo level="info">Creating library output jar file...</echo>
+ <property name="out.library.jar.file" location="${out.absolute.dir}/classes.jar" />
+ <if>
+ <condition>
+ <length string="${android.package.excludes}" trim="true" when="greater" length="0" />
+ </condition>
+ <then>
+ <echo level="info">Custom jar packaging exclusion: ${android.package.excludes}</echo>
+ </then>
+ </if>
+
+ <propertybyreplace name="project.app.package.path" input="${project.app.package}" replace="." with="/" />
+
+ <jar destfile="${out.library.jar.file}">
+ <fileset dir="${out.classes.absolute.dir}"
includes="**/*.class"
excludes="${project.app.package.path}/R.class ${project.app.package.path}/R$*.class ${project.app.package.path}/BuildConfig.class"/>
- <fileset dir="${source.absolute.dir}" excludes="**/*.java ${android.package.excludes}" />
- </jar>
- </then>
- </if>
+ <fileset dir="${source.absolute.dir}" excludes="**/*.java ${android.package.excludes}" />
+ </jar>
+ </then>
+ </if>
- </do-only-if-manifest-hasCode>
- </target>
-<!-- end of modifications for android-annotations -->
-
-
-<!--
+ </do-only-if-manifest-hasCode>
+ </target>
+ <!-- end of modifications for android-annotations -->
+
+
+ <!--
<target name="-post-compile">
</target>
-->
- <!-- Import the actual build file.
+ <!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
@@ -237,7 +265,7 @@
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
- <!-- version-tag: custom -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
+ <!-- version-tag: custom -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
</project>
diff --git a/main/cgeo.iml b/main/cgeo.iml
index 7ba7ab9..bb3a4d2 100644
--- a/main/cgeo.iml
+++ b/main/cgeo.iml
@@ -6,12 +6,16 @@
<proGuardCfgFiles>
<file>file://$MODULE_DIR$/proguard-project.txt</file>
</proGuardCfgFiles>
+ <option name="UPDATE_PROPERTY_FILES" value="false" />
<includeAssetsFromLibraries>true</includeAssetsFromLibraries>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
+ <annotation-paths>
+ <root url="file://$MODULE_DIR$/project/annotations" />
+ </annotation-paths>
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
@@ -19,6 +23,9 @@
</content>
<orderEntry type="module-library" exported="">
<library name="libs">
+ <ANNOTATIONS>
+ <root url="file://$MODULE_DIR$/project/annotations" />
+ </ANNOTATIONS>
<CLASSES>
<root url="file://$MODULE_DIR$/libs" />
</CLASSES>
@@ -39,14 +46,11 @@
<root url="file://$MODULE_DIR$/compile-libs" />
</CLASSES>
<JAVADOC />
- <SOURCES>
- <root url="file://$MODULE_DIR$/compile-libs" />
- </SOURCES>
+ <SOURCES />
<jarDirectory url="file://$MODULE_DIR$/compile-libs" recursive="false" />
- <jarDirectory url="file://$MODULE_DIR$/compile-libs" recursive="false" type="SOURCES" />
</library>
</orderEntry>
- <orderEntry type="module-library" exported="" scope="PROVIDED">
+ <orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/libs" />
@@ -59,6 +63,206 @@
<orderEntry type="module" module-name="mapswithme-api" exported="" />
<orderEntry type="module" module-name="showcaseview" exported="" />
<orderEntry type="module" module-name="android-support-v7-appcompat" exported="" />
+ <orderEntry type="module" module-name="play-services-base" exported="" />
+ <orderEntry type="module" module-name="play-services-location" exported="" />
+ </component>
+ <component name="org.twodividedbyzero.idea.findbugs">
+ <option name="_basePreferences">
+ <map>
+ <entry key="property.analysisEffortLevel" value="default" />
+ <entry key="property.analyzeAfterCompile" value="false" />
+ <entry key="property.annotationGutterIconEnabled" value="true" />
+ <entry key="property.annotationSuppressWarningsClass" value="edu.umd.cs.findbugs.annotations.SuppressFBWarnings" />
+ <entry key="property.annotationTextRangeMarkupEnabled" value="true" />
+ <entry key="property.exportAsHtml" value="true" />
+ <entry key="property.exportAsXml" value="true" />
+ <entry key="property.exportBaseDir" value="" />
+ <entry key="property.exportCreateArchiveDir" value="false" />
+ <entry key="property.exportOpenBrowser" value="true" />
+ <entry key="property.minPriorityToReport" value="Medium" />
+ <entry key="property.runAnalysisInBackground" value="false" />
+ <entry key="property.showHiddenDetectors" value="false" />
+ <entry key="property.toolWindowToFront" value="true" />
+ </map>
+ </option>
+ <option name="_detectors">
+ <map>
+ <entry key="AppendingToAnObjectOutputStream" value="true" />
+ <entry key="AtomicityProblem" value="true" />
+ <entry key="BadAppletConstructor" value="false" />
+ <entry key="BadResultSetAccess" value="true" />
+ <entry key="BadSyntaxForRegularExpression" value="true" />
+ <entry key="BadUseOfReturnValue" value="true" />
+ <entry key="BadlyOverriddenAdapter" value="true" />
+ <entry key="BooleanReturnNull" value="true" />
+ <entry key="BuildInterproceduralCallGraph" value="false" />
+ <entry key="BuildObligationPolicyDatabase" value="true" />
+ <entry key="BuildStringPassthruGraph" value="true" />
+ <entry key="CallToUnsupportedMethod" value="false" />
+ <entry key="CalledMethods" value="true" />
+ <entry key="CheckCalls" value="false" />
+ <entry key="CheckExpectedWarnings" value="false" />
+ <entry key="CheckImmutableAnnotation" value="true" />
+ <entry key="CheckRelaxingNullnessAnnotation" value="true" />
+ <entry key="CheckTypeQualifiers" value="true" />
+ <entry key="CloneIdiom" value="true" />
+ <entry key="ComparatorIdiom" value="true" />
+ <entry key="ConfusedInheritance" value="true" />
+ <entry key="ConfusionBetweenInheritedAndOuterMethod" value="true" />
+ <entry key="CrossSiteScripting" value="true" />
+ <entry key="DefaultEncodingDetector" value="true" />
+ <entry key="DoInsideDoPrivileged" value="true" />
+ <entry key="DontCatchIllegalMonitorStateException" value="true" />
+ <entry key="DontIgnoreResultOfPutIfAbsent" value="true" />
+ <entry key="DontUseEnum" value="true" />
+ <entry key="DroppedException" value="true" />
+ <entry key="DumbMethodInvocations" value="true" />
+ <entry key="DumbMethods" value="true" />
+ <entry key="DuplicateBranches" value="true" />
+ <entry key="EmptyZipFileEntry" value="false" />
+ <entry key="EqualsOperandShouldHaveClassCompatibleWithThis" value="true" />
+ <entry key="ExplicitSerialization" value="true" />
+ <entry key="FieldItemSummary" value="true" />
+ <entry key="FinalizerNullsFields" value="true" />
+ <entry key="FindBadCast2" value="true" />
+ <entry key="FindBadForLoop" value="true" />
+ <entry key="FindBugsSummaryStats" value="true" />
+ <entry key="FindCircularDependencies" value="false" />
+ <entry key="FindDeadLocalStores" value="true" />
+ <entry key="FindDoubleCheck" value="true" />
+ <entry key="FindEmptySynchronizedBlock" value="true" />
+ <entry key="FindFieldSelfAssignment" value="true" />
+ <entry key="FindFinalizeInvocations" value="true" />
+ <entry key="FindFloatEquality" value="true" />
+ <entry key="FindFloatMath" value="false" />
+ <entry key="FindHEmismatch" value="true" />
+ <entry key="FindInconsistentSync2" value="true" />
+ <entry key="FindJSR166LockMonitorenter" value="true" />
+ <entry key="FindLocalSelfAssignment2" value="true" />
+ <entry key="FindMaskedFields" value="true" />
+ <entry key="FindMismatchedWaitOrNotify" value="true" />
+ <entry key="FindNakedNotify" value="true" />
+ <entry key="FindNoSideEffectMethods" value="true" />
+ <entry key="FindNonSerializableStoreIntoSession" value="false" />
+ <entry key="FindNonSerializableValuePassedToWriteObject" value="false" />
+ <entry key="FindNonShortCircuit" value="true" />
+ <entry key="FindNullDeref" value="true" />
+ <entry key="FindNullDerefsInvolvingNonShortCircuitEvaluation" value="true" />
+ <entry key="FindOpenStream" value="true" />
+ <entry key="FindPuzzlers" value="true" />
+ <entry key="FindRefComparison" value="true" />
+ <entry key="FindReturnRef" value="true" />
+ <entry key="FindRoughConstants" value="true" />
+ <entry key="FindRunInvocations" value="true" />
+ <entry key="FindSelfComparison" value="true" />
+ <entry key="FindSelfComparison2" value="true" />
+ <entry key="FindSleepWithLockHeld" value="true" />
+ <entry key="FindSpinLoop" value="true" />
+ <entry key="FindSqlInjection" value="true" />
+ <entry key="FindTwoLockWait" value="true" />
+ <entry key="FindUncalledPrivateMethods" value="true" />
+ <entry key="FindUnconditionalWait" value="true" />
+ <entry key="FindUninitializedGet" value="true" />
+ <entry key="FindUnrelatedTypesInGenericContainer" value="true" />
+ <entry key="FindUnreleasedLock" value="true" />
+ <entry key="FindUnsatisfiedObligation" value="true" />
+ <entry key="FindUnsyncGet" value="true" />
+ <entry key="FindUseOfNonSerializableValue" value="true" />
+ <entry key="FindUselessControlFlow" value="true" />
+ <entry key="FormatStringChecker" value="true" />
+ <entry key="FunctionsThatMightBeMistakenForProcedures" value="true" />
+ <entry key="HugeSharedStringConstants" value="true" />
+ <entry key="IDivResultCastToDouble" value="true" />
+ <entry key="IncompatMask" value="true" />
+ <entry key="InconsistentAnnotations" value="true" />
+ <entry key="InefficientIndexOf" value="true" />
+ <entry key="InefficientInitializationInsideLoop" value="true" />
+ <entry key="InefficientMemberAccess" value="false" />
+ <entry key="InefficientToArray" value="true" />
+ <entry key="InfiniteLoop" value="true" />
+ <entry key="InfiniteRecursiveLoop" value="true" />
+ <entry key="InheritanceUnsafeGetResource" value="true" />
+ <entry key="InitializationChain" value="true" />
+ <entry key="InitializeNonnullFieldsInConstructor" value="true" />
+ <entry key="InstantiateStaticClass" value="true" />
+ <entry key="IntCast2LongAsInstant" value="true" />
+ <entry key="InvalidJUnitTest" value="true" />
+ <entry key="IteratorIdioms" value="true" />
+ <entry key="LazyInit" value="true" />
+ <entry key="LoadOfKnownNullValue" value="true" />
+ <entry key="LostLoggerDueToWeakReference" value="true" />
+ <entry key="MethodReturnCheck" value="true" />
+ <entry key="Methods" value="true" />
+ <entry key="MultithreadedInstanceAccess" value="true" />
+ <entry key="MutableLock" value="true" />
+ <entry key="MutableStaticFields" value="true" />
+ <entry key="Naming" value="true" />
+ <entry key="Noise" value="false" />
+ <entry key="NoiseNullDeref" value="false" />
+ <entry key="NoteAnnotationRetention" value="true" />
+ <entry key="NoteCheckReturnValueAnnotations" value="true" />
+ <entry key="NoteDirectlyRelevantTypeQualifiers" value="true" />
+ <entry key="NoteJCIPAnnotation" value="true" />
+ <entry key="NoteNonNullAnnotations" value="false" />
+ <entry key="NoteNonnullReturnValues" value="false" />
+ <entry key="NoteSuppressedWarnings" value="true" />
+ <entry key="NoteUnconditionalParamDerefs" value="true" />
+ <entry key="NumberConstructor" value="true" />
+ <entry key="OptionalReturnNull" value="true" />
+ <entry key="OverridingEqualsNotSymmetrical" value="true" />
+ <entry key="PreferZeroLengthArrays" value="true" />
+ <entry key="PublicSemaphores" value="false" />
+ <entry key="QuestionableBooleanAssignment" value="true" />
+ <entry key="ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass" value="true" />
+ <entry key="ReadReturnShouldBeChecked" value="true" />
+ <entry key="RedundantInterfaces" value="true" />
+ <entry key="ReflectiveClasses" value="true" />
+ <entry key="RepeatedConditionals" value="true" />
+ <entry key="ResolveAllReferences" value="false" />
+ <entry key="RuntimeExceptionCapture" value="true" />
+ <entry key="SerializableIdiom" value="true" />
+ <entry key="StartInConstructor" value="true" />
+ <entry key="StaticCalendarDetector" value="true" />
+ <entry key="StringConcatenation" value="true" />
+ <entry key="SuperfluousInstanceOf" value="true" />
+ <entry key="SuspiciousThreadInterrupted" value="true" />
+ <entry key="SwitchFallthrough" value="true" />
+ <entry key="SynchronizationOnSharedBuiltinConstant" value="true" />
+ <entry key="SynchronizeAndNullCheckField" value="true" />
+ <entry key="SynchronizeOnClassLiteralNotGetClass" value="true" />
+ <entry key="SynchronizingOnContentsOfFieldToProtectField" value="true" />
+ <entry key="TestASM" value="false" />
+ <entry key="TestDataflowAnalysis" value="false" />
+ <entry key="TestingGround" value="false" />
+ <entry key="TestingGround2" value="false" />
+ <entry key="TrainFieldStoreTypes" value="true" />
+ <entry key="TrainLongInstantfParams" value="true" />
+ <entry key="TrainNonNullAnnotations" value="true" />
+ <entry key="TrainUnconditionalDerefParams" value="true" />
+ <entry key="URLProblems" value="true" />
+ <entry key="UncallableMethodOfAnonymousClass" value="true" />
+ <entry key="UnnecessaryMath" value="true" />
+ <entry key="UnreadFields" value="true" />
+ <entry key="UselessSubclassMethod" value="false" />
+ <entry key="VarArgsProblems" value="true" />
+ <entry key="VolatileUsage" value="true" />
+ <entry key="WaitInLoop" value="true" />
+ <entry key="WrongMapIterator" value="true" />
+ <entry key="XMLFactoryBypass" value="true" />
+ </map>
+ </option>
+ <option name="_reportCategories">
+ <map>
+ <entry key="BAD_PRACTICE" value="true" />
+ <entry key="CORRECTNESS" value="true" />
+ <entry key="EXPERIMENTAL" value="true" />
+ <entry key="I18N" value="true" />
+ <entry key="MALICIOUS_CODE" value="true" />
+ <entry key="MT_CORRECTNESS" value="true" />
+ <entry key="PERFORMANCE" value="true" />
+ <entry key="SECURITY" value="true" />
+ <entry key="STYLE" value="true" />
+ </map>
+ </option>
</component>
-</module>
-
+</module> \ No newline at end of file
diff --git a/main/compile-libs/androidannotations-3.0.1.jar b/main/compile-libs/androidannotations-3.0.1.jar
deleted file mode 100644
index 4c96d6c..0000000
--- a/main/compile-libs/androidannotations-3.0.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/compile-libs/androidannotations-3.2.jar b/main/compile-libs/androidannotations-3.2.jar
new file mode 100644
index 0000000..9f40472
--- /dev/null
+++ b/main/compile-libs/androidannotations-3.2.jar
Binary files differ
diff --git a/main/libs/androidannotations-api-3.0.1.jar b/main/libs/androidannotations-api-3.0.1.jar
deleted file mode 100644
index 90bfe7a..0000000
--- a/main/libs/androidannotations-api-3.0.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/androidannotations-api-3.2.jar b/main/libs/androidannotations-api-3.2.jar
new file mode 100644
index 0000000..12d4ef0
--- /dev/null
+++ b/main/libs/androidannotations-api-3.2.jar
Binary files differ
diff --git a/main/libs/androidannotations-api-3.2.jar.properties b/main/libs/androidannotations-api-3.2.jar.properties
new file mode 100644
index 0000000..6e05cd2
--- /dev/null
+++ b/main/libs/androidannotations-api-3.2.jar.properties
@@ -0,0 +1,2 @@
+src=src/androidannotations-api-3.2-sources.jar
+doc=src/androidannotations-api-3.2-javadoc.jar \ No newline at end of file
diff --git a/main/libs/findbugs-annotations.jar b/main/libs/annotations-3.0.0.jar
index 3641ad6..a2f68fe 100644
--- a/main/libs/findbugs-annotations.jar
+++ b/main/libs/annotations-3.0.0.jar
Binary files differ
diff --git a/main/libs/annotations-3.0.0.jar.properties b/main/libs/annotations-3.0.0.jar.properties
new file mode 100644
index 0000000..a32a2ea
--- /dev/null
+++ b/main/libs/annotations-3.0.0.jar.properties
@@ -0,0 +1,2 @@
+src=src/annotations-3.0.0-sources.jar
+doc=src/annotations-3.0.0-javadoc.jar
diff --git a/main/libs/butterknife-5.1.1.jar b/main/libs/butterknife-5.1.1.jar
deleted file mode 100644
index 45ab11f..0000000
--- a/main/libs/butterknife-5.1.1.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/butterknife-6.1.0.jar b/main/libs/butterknife-6.1.0.jar
new file mode 100644
index 0000000..699077a
--- /dev/null
+++ b/main/libs/butterknife-6.1.0.jar
Binary files differ
diff --git a/main/libs/butterknife-6.1.0.jar.properties b/main/libs/butterknife-6.1.0.jar.properties
new file mode 100644
index 0000000..3db4372
--- /dev/null
+++ b/main/libs/butterknife-6.1.0.jar.properties
@@ -0,0 +1,2 @@
+src=src/butterknife-6.1.0-sources.jar
+doc=src/butterknife-6.1.0-javadoc.jar
diff --git a/main/libs/commons-collections4-4.0.jar.properties b/main/libs/commons-collections4-4.0.jar.properties
index a50b66c..1807323 100644
--- a/main/libs/commons-collections4-4.0.jar.properties
+++ b/main/libs/commons-collections4-4.0.jar.properties
@@ -1 +1,2 @@
-src=src/commons-collections4-4.0-sources.jar \ No newline at end of file
+src=src/commons-collections4-4.0-sources.jar
+doc=src/commons-collections4-4.0-javadoc.jar
diff --git a/main/libs/commons-io-2.4.jar.properties b/main/libs/commons-io-2.4.jar.properties
index d160263..ff1c9c9 100644
--- a/main/libs/commons-io-2.4.jar.properties
+++ b/main/libs/commons-io-2.4.jar.properties
@@ -1,2 +1,2 @@
src=src/commons-io-2.4-sources.jar
-doc=src/commons-io-2.4-javadoc.jar \ No newline at end of file
+doc=src/commons-io-2.4-javadoc.jar
diff --git a/main/libs/commons-lang3-3.3.2.jar b/main/libs/commons-lang3-3.3.2.jar
index bb06979..2ce08ae 100644
--- a/main/libs/commons-lang3-3.3.2.jar
+++ b/main/libs/commons-lang3-3.3.2.jar
Binary files differ
diff --git a/main/libs/commons-lang3-3.3.2.jar.properties b/main/libs/commons-lang3-3.3.2.jar.properties
index 0885ede..08f905f 100644
--- a/main/libs/commons-lang3-3.3.2.jar.properties
+++ b/main/libs/commons-lang3-3.3.2.jar.properties
@@ -1 +1,2 @@
-doc=src/commons-lang3-3.3.2-javadoc.jar \ No newline at end of file
+src=src/commons-lang3-3.3.2-sources.jar
+doc=src/commons-lang3-3.3.2-javadoc.jar
diff --git a/main/libs/jackson-annotations-2.5.1.jar b/main/libs/jackson-annotations-2.5.1.jar
new file mode 100644
index 0000000..9bce595
--- /dev/null
+++ b/main/libs/jackson-annotations-2.5.1.jar
Binary files differ
diff --git a/main/libs/jackson-annotations-2.5.1.jar.properties b/main/libs/jackson-annotations-2.5.1.jar.properties
new file mode 100644
index 0000000..d96e699
--- /dev/null
+++ b/main/libs/jackson-annotations-2.5.1.jar.properties
@@ -0,0 +1,2 @@
+src=src/jackson-annotations-2.5.1-sources.jar
+doc=src/jackson-annotations-2.5.1-javadoc.jar
diff --git a/main/libs/jackson-core-2.5.1.jar b/main/libs/jackson-core-2.5.1.jar
new file mode 100644
index 0000000..8c9c4e0
--- /dev/null
+++ b/main/libs/jackson-core-2.5.1.jar
Binary files differ
diff --git a/main/libs/jackson-core-2.5.1.jar.properties b/main/libs/jackson-core-2.5.1.jar.properties
new file mode 100644
index 0000000..c32e143
--- /dev/null
+++ b/main/libs/jackson-core-2.5.1.jar.properties
@@ -0,0 +1,2 @@
+src=src/jackson-core-2.5.1-sources.jar
+doc=src/jackson-core-2.5.1-javadoc.jar
diff --git a/main/libs/jackson-databind-2.5.1.jar b/main/libs/jackson-databind-2.5.1.jar
new file mode 100644
index 0000000..9b82e3f
--- /dev/null
+++ b/main/libs/jackson-databind-2.5.1.jar
Binary files differ
diff --git a/main/libs/jackson-databind-2.5.1.jar.properties b/main/libs/jackson-databind-2.5.1.jar.properties
new file mode 100644
index 0000000..8fefb06
--- /dev/null
+++ b/main/libs/jackson-databind-2.5.1.jar.properties
@@ -0,0 +1,2 @@
+src=src/jackson-databind-2.5.1-sources.jar
+doc=src/jackson-databind-2.5.1-javadoc.jar
diff --git a/main/libs/mapsforge-map-0.2.4.jar b/main/libs/mapsforge-map-0.2.4.jar
deleted file mode 100644
index ec9aa4c..0000000
--- a/main/libs/mapsforge-map-0.2.4.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/rxandroid-0.24.0.jar b/main/libs/rxandroid-0.24.0.jar
new file mode 100644
index 0000000..35eb088
--- /dev/null
+++ b/main/libs/rxandroid-0.24.0.jar
Binary files differ
diff --git a/main/libs/rxandroid-0.24.0.jar.properties b/main/libs/rxandroid-0.24.0.jar.properties
new file mode 100644
index 0000000..d995320
--- /dev/null
+++ b/main/libs/rxandroid-0.24.0.jar.properties
@@ -0,0 +1,2 @@
+src=src/rxandroid-0.24.0-sources.jar
+doc=src/rxandroid-0.24.0-javadoc.jar
diff --git a/main/libs/rxjava-1.0.8.jar b/main/libs/rxjava-1.0.8.jar
new file mode 100644
index 0000000..f60ebe1
--- /dev/null
+++ b/main/libs/rxjava-1.0.8.jar
Binary files differ
diff --git a/main/libs/rxjava-1.0.8.jar.properties b/main/libs/rxjava-1.0.8.jar.properties
new file mode 100644
index 0000000..757e3be
--- /dev/null
+++ b/main/libs/rxjava-1.0.8.jar.properties
@@ -0,0 +1,2 @@
+src=src/rxjava-1.0.8-sources.jar
+doc=src/rxjava-1.0.8-javadoc.jar
diff --git a/main/libs/rxjava-android-0.19.6.jar b/main/libs/rxjava-android-0.19.6.jar
deleted file mode 100644
index ccc8b6a..0000000
--- a/main/libs/rxjava-android-0.19.6.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/rxjava-android-0.19.6.jar.properties b/main/libs/rxjava-android-0.19.6.jar.properties
deleted file mode 100644
index 7414a89..0000000
--- a/main/libs/rxjava-android-0.19.6.jar.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-src=src/rxjava-android-0.19.6-sources.jar
-doc=src/rxjava-android-0.19.6-javadoc.jar
diff --git a/main/libs/rxjava-async-util-0.19.6.jar b/main/libs/rxjava-async-util-0.19.6.jar
deleted file mode 100644
index 93c1a9b..0000000
--- a/main/libs/rxjava-async-util-0.19.6.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/rxjava-async-util-0.19.6.jar.properties b/main/libs/rxjava-async-util-0.19.6.jar.properties
deleted file mode 100644
index 0396d9a..0000000
--- a/main/libs/rxjava-async-util-0.19.6.jar.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-src=src/rxjava-async-util-0.19.6-sources.jar
-doc=src/rxjava-async-util-0.19.6-javadoc.jar
diff --git a/main/libs/rxjava-core-0.19.6.jar b/main/libs/rxjava-core-0.19.6.jar
deleted file mode 100644
index 9b6cbfa..0000000
--- a/main/libs/rxjava-core-0.19.6.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/rxjava-core-0.19.6.jar.properties b/main/libs/rxjava-core-0.19.6.jar.properties
deleted file mode 100644
index 41b8394..0000000
--- a/main/libs/rxjava-core-0.19.6.jar.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-src=src/rxjava-core-0.19.6-sources.jar
-doc=src/rxjava-core-0.19.6-javadoc.jar
diff --git a/main/libs/src/androidannotations-api-3.2-javadoc.jar b/main/libs/src/androidannotations-api-3.2-javadoc.jar
new file mode 100644
index 0000000..efdaf1f
--- /dev/null
+++ b/main/libs/src/androidannotations-api-3.2-javadoc.jar
Binary files differ
diff --git a/main/libs/src/androidannotations-api-3.2-sources.jar b/main/libs/src/androidannotations-api-3.2-sources.jar
new file mode 100644
index 0000000..acc6ba9
--- /dev/null
+++ b/main/libs/src/androidannotations-api-3.2-sources.jar
Binary files differ
diff --git a/main/libs/src/annotations-3.0.0-javadoc.jar b/main/libs/src/annotations-3.0.0-javadoc.jar
new file mode 100644
index 0000000..0098501
--- /dev/null
+++ b/main/libs/src/annotations-3.0.0-javadoc.jar
Binary files differ
diff --git a/main/libs/src/annotations-3.0.0-sources.jar b/main/libs/src/annotations-3.0.0-sources.jar
new file mode 100644
index 0000000..0098501
--- /dev/null
+++ b/main/libs/src/annotations-3.0.0-sources.jar
Binary files differ
diff --git a/main/libs/src/butterknife-6.1.0-javadoc.jar b/main/libs/src/butterknife-6.1.0-javadoc.jar
new file mode 100644
index 0000000..44577e4
--- /dev/null
+++ b/main/libs/src/butterknife-6.1.0-javadoc.jar
Binary files differ
diff --git a/main/libs/src/butterknife-6.1.0-sources.jar b/main/libs/src/butterknife-6.1.0-sources.jar
new file mode 100644
index 0000000..f980a1d
--- /dev/null
+++ b/main/libs/src/butterknife-6.1.0-sources.jar
Binary files differ
diff --git a/main/libs/src/commons-collections4-4.0-javadoc.jar b/main/libs/src/commons-collections4-4.0-javadoc.jar
new file mode 100644
index 0000000..35989f8
--- /dev/null
+++ b/main/libs/src/commons-collections4-4.0-javadoc.jar
Binary files differ
diff --git a/main/libs/src/commons-lang3-3.3.2-javadoc.jar b/main/libs/src/commons-lang3-3.3.2-javadoc.jar
index bd2f422..9cad4b1 100644
--- a/main/libs/src/commons-lang3-3.3.2-javadoc.jar
+++ b/main/libs/src/commons-lang3-3.3.2-javadoc.jar
Binary files differ
diff --git a/main/libs/src/commons-lang3-3.3.2-sources.jar b/main/libs/src/commons-lang3-3.3.2-sources.jar
new file mode 100644
index 0000000..fa12693
--- /dev/null
+++ b/main/libs/src/commons-lang3-3.3.2-sources.jar
Binary files differ
diff --git a/main/libs/src/jackson-annotations-2.5.1-javadoc.jar b/main/libs/src/jackson-annotations-2.5.1-javadoc.jar
new file mode 100644
index 0000000..d4d2c55
--- /dev/null
+++ b/main/libs/src/jackson-annotations-2.5.1-javadoc.jar
Binary files differ
diff --git a/main/libs/src/jackson-annotations-2.5.1-sources.jar b/main/libs/src/jackson-annotations-2.5.1-sources.jar
new file mode 100644
index 0000000..a7f0358
--- /dev/null
+++ b/main/libs/src/jackson-annotations-2.5.1-sources.jar
Binary files differ
diff --git a/main/libs/src/jackson-core-2.5.1-javadoc.jar b/main/libs/src/jackson-core-2.5.1-javadoc.jar
new file mode 100644
index 0000000..a7f96ce
--- /dev/null
+++ b/main/libs/src/jackson-core-2.5.1-javadoc.jar
Binary files differ
diff --git a/main/libs/src/jackson-core-2.5.1-sources.jar b/main/libs/src/jackson-core-2.5.1-sources.jar
new file mode 100644
index 0000000..fd77726
--- /dev/null
+++ b/main/libs/src/jackson-core-2.5.1-sources.jar
Binary files differ
diff --git a/main/libs/src/jackson-databind-2.5.1-javadoc.jar b/main/libs/src/jackson-databind-2.5.1-javadoc.jar
new file mode 100644
index 0000000..1ea90be
--- /dev/null
+++ b/main/libs/src/jackson-databind-2.5.1-javadoc.jar
Binary files differ
diff --git a/main/libs/src/jackson-databind-2.5.1-sources.jar b/main/libs/src/jackson-databind-2.5.1-sources.jar
new file mode 100644
index 0000000..8ca50ff
--- /dev/null
+++ b/main/libs/src/jackson-databind-2.5.1-sources.jar
Binary files differ
diff --git a/main/libs/src/rxandroid-0.24.0-javadoc.jar b/main/libs/src/rxandroid-0.24.0-javadoc.jar
new file mode 100644
index 0000000..ea887e5
--- /dev/null
+++ b/main/libs/src/rxandroid-0.24.0-javadoc.jar
Binary files differ
diff --git a/main/libs/src/rxandroid-0.24.0-sources.jar b/main/libs/src/rxandroid-0.24.0-sources.jar
new file mode 100644
index 0000000..8bffa81
--- /dev/null
+++ b/main/libs/src/rxandroid-0.24.0-sources.jar
Binary files differ
diff --git a/main/libs/src/rxjava-1.0.8-javadoc.jar b/main/libs/src/rxjava-1.0.8-javadoc.jar
new file mode 100644
index 0000000..59c118d
--- /dev/null
+++ b/main/libs/src/rxjava-1.0.8-javadoc.jar
Binary files differ
diff --git a/main/libs/src/rxjava-1.0.8-sources.jar b/main/libs/src/rxjava-1.0.8-sources.jar
new file mode 100644
index 0000000..4fc97d2
--- /dev/null
+++ b/main/libs/src/rxjava-1.0.8-sources.jar
Binary files differ
diff --git a/main/libs/src/rxjava-android-0.19.6-javadoc.jar b/main/libs/src/rxjava-android-0.19.6-javadoc.jar
deleted file mode 100644
index a92ab4f..0000000
--- a/main/libs/src/rxjava-android-0.19.6-javadoc.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/rxjava-android-0.19.6-sources.jar b/main/libs/src/rxjava-android-0.19.6-sources.jar
deleted file mode 100644
index ea4eba0..0000000
--- a/main/libs/src/rxjava-android-0.19.6-sources.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/rxjava-async-util-0.19.6-javadoc.jar b/main/libs/src/rxjava-async-util-0.19.6-javadoc.jar
deleted file mode 100644
index f943e5f..0000000
--- a/main/libs/src/rxjava-async-util-0.19.6-javadoc.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/rxjava-async-util-0.19.6-sources.jar b/main/libs/src/rxjava-async-util-0.19.6-sources.jar
deleted file mode 100644
index 82ca499..0000000
--- a/main/libs/src/rxjava-async-util-0.19.6-sources.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/rxjava-core-0.19.6-javadoc.jar b/main/libs/src/rxjava-core-0.19.6-javadoc.jar
deleted file mode 100644
index 5523ee0..0000000
--- a/main/libs/src/rxjava-core-0.19.6-javadoc.jar
+++ /dev/null
Binary files differ
diff --git a/main/libs/src/rxjava-core-0.19.6-sources.jar b/main/libs/src/rxjava-core-0.19.6-sources.jar
deleted file mode 100644
index 0c2aa68..0000000
--- a/main/libs/src/rxjava-core-0.19.6-sources.jar
+++ /dev/null
Binary files differ
diff --git a/main/lint.xml b/main/lint.xml
index 905b9a4..60a2d28 100644
--- a/main/lint.xml
+++ b/main/lint.xml
@@ -12,6 +12,8 @@
</issue>
<issue id="MissingTranslation" severity="ignore" />
<issue id="Registered" severity="ignore" />
+ <issue id="RtlHardcoded" severity="ignore" />
+ <issue id="RtlSymmetry" severity="ignore" />
<issue id="UnusedAttribute" severity="ignore" />
<issue id="UnusedResources">
<ignore path="res/drawable-mdpi/attribute_maintenance.png" />
diff --git a/main/proguard-project.txt b/main/proguard-project.txt
index 2a27d99..230d85f 100644
--- a/main/proguard-project.txt
+++ b/main/proguard-project.txt
@@ -21,9 +21,12 @@
# rxjava internal references sun.misc.Unsafe
-dontwarn sun.misc.Unsafe
+# jackson internal references
+-dontwarn org.w3c.dom.bootstrap.DOMImplementationRegistry
+
#-dontnote org.apache.commons.logging.**
--keep public class cgeo.geocaching.*
+-keep class cgeo.geocaching.** { *; }
-keep class android.support.v4.os.** { *; }
-keep class ch.boye.httpclientandroidlib.conn.scheme.Scheme { *; }
@@ -59,7 +62,19 @@
# Null analysis annotations of Eclipse JDT are just used by the Eclipse compiler, so ignore them here
-dontwarn org.eclipse.jdt.annotation.**
+# keep Emma code coverage during debug builds, and ignore related warnings
+-keep class com.vladium.** { *; }
+-dontwarn com.vladium.**
+
+# keep some test only utils classes
+-keep class org.apache.commons.lang3.StringUtils { *; }
+-keep class org.apache.commons.io.IOUtils { *; }
+-keep class org.apache.commons.io.FileUtils { *; }
+
# action providers are only referenced from XML
-keep public class cgeo.geocaching.sorting.SortActionProvider { *; }
-keep public class cgeo.geocaching.ui.NavigationActionProvider { *; }
--keep public class cgeo.geocaching.apps.cache.navi.NavigationSelectionActionProvider { *; } \ No newline at end of file
+-keep public class cgeo.geocaching.apps.cache.navi.NavigationSelectionActionProvider { *; }
+
+# Play Service references to classes introduced in higher API levels
+-dontwarn com.google.android.gms.**
diff --git a/main/project.properties b/main/project.properties
index b341d6c..600d70f 100644
--- a/main/project.properties
+++ b/main/project.properties
@@ -8,12 +8,14 @@
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt:../play-services-base/proguard.txt:../play-services-location/proguard.txt
# Project target.
-target=android-19
+target=android-21
android.library.reference.1=../mapswithme-api
android.library.reference.2=../android-support-v7-appcompat
+android.library.reference.3=../showcaseview
java.source=1.7
java.target=1.7
-android.library.reference.3=../showcaseview
+android.library.reference.4=../play-services-base
+android.library.reference.5=../play-services-location
diff --git a/main/project/annotations/java/lang/annotations.xml b/main/project/annotations/java/lang/annotations.xml
new file mode 100644
index 0000000..0926f42
--- /dev/null
+++ b/main/project/annotations/java/lang/annotations.xml
@@ -0,0 +1,7 @@
+<root>
+ <item name='java.lang.String java.lang.String trim()'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;-&gt;!null&quot;" />
+ </annotation>
+ </item>
+</root> \ No newline at end of file
diff --git a/main/project/annotations/java/util/annotations.xml b/main/project/annotations/java/util/annotations.xml
new file mode 100644
index 0000000..854909b
--- /dev/null
+++ b/main/project/annotations/java/util/annotations.xml
@@ -0,0 +1,7 @@
+<root>
+ <item name='java.util.List java.lang.Object[] toArray()'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;-&gt;!null&quot;" />
+ </annotation>
+ </item>
+</root> \ No newline at end of file
diff --git a/main/project/annotations/org/apache/commons/lang3/annotations.xml b/main/project/annotations/org/apache/commons/lang3/annotations.xml
new file mode 100644
index 0000000..0ed3c67
--- /dev/null
+++ b/main/project/annotations/org/apache/commons/lang3/annotations.xml
@@ -0,0 +1,34 @@
+<root>
+ <item name='org.apache.commons.lang3.StringUtils boolean isNotBlank(java.lang.CharSequence)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null-&gt;false&quot;" />
+ </annotation>
+ </item>
+ <item
+ name='org.apache.commons.lang3.StringUtils boolean startsWith(java.lang.CharSequence, java.lang.CharSequence)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null,null-&gt;true;null,!null-&gt;false;!null,null-&gt;false&quot;" />
+ </annotation>
+ </item>
+ <item
+ name='org.apache.commons.lang3.StringUtils java.lang.String substringBetween(java.lang.String, java.lang.String, java.lang.String)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null,_,_-&gt;null;_,null,_-&gt;null;_,_,null-&gt;null&quot;" />
+ </annotation>
+ </item>
+ <item name='org.apache.commons.lang3.StringUtils java.lang.String trim(java.lang.String)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null-&gt;null;!null-&gt;!null&quot;" />
+ </annotation>
+ </item>
+ <item name='org.apache.commons.lang3.StringUtils java.lang.String upperCase(java.lang.String)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null-&gt;null;!null-&gt;!null&quot;" />
+ </annotation>
+ </item>
+ <item name='org.apache.commons.lang3.StringUtils java.lang.String[] split(java.lang.String)'>
+ <annotation name='org.jetbrains.annotations.Contract'>
+ <val val="&quot;null-&gt;null;!null-&gt;!null&quot;" />
+ </annotation>
+ </item>
+</root> \ No newline at end of file
diff --git a/main/project/eclipse installation/cgeo eclipse components.p2f b/main/project/eclipse installation/cgeo eclipse components.p2f
index f758e68..edac095 100644
--- a/main/project/eclipse installation/cgeo eclipse components.p2f
+++ b/main/project/eclipse installation/cgeo eclipse components.p2f
@@ -1,40 +1,95 @@
<?xml version='1.0' encoding='UTF-8'?>
<?p2f version='1.0.0'?>
<p2f version='1.0.0'>
- <ius size='7'>
- <iu id='com.android.ide.eclipse.ddms.feature.group' name='Android DDMS' version='22.2.1.v201309180102-833290'>
+ <ius size='18'>
+ <iu id='com.android.ide.eclipse.ddms.feature.feature.group' name='Android DDMS' version='23.0.4.1468518'>
<repositories size='1'>
<repository location='https://dl-ssl.google.com/android/eclipse/'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.adt.feature.group' name='Android Development Tools' version='22.2.1.v201309180102-833290'>
+ <iu id='com.android.ide.eclipse.adt.feature.feature.group' name='Android Development Tools' version='23.0.4.1468518'>
<repositories size='1'>
<repository location='https://dl-ssl.google.com/android/eclipse/'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.hierarchyviewer.feature.group' name='Android Hierarchy Viewer' version='22.2.1.v201309180102-833290'>
+ <iu id='com.android.ide.eclipse.hierarchyviewer.feature.feature.group' name='Android Hierarchy Viewer' version='23.0.4.1468518'>
<repositories size='1'>
<repository location='https://dl-ssl.google.com/android/eclipse/'/>
</repositories>
</iu>
- <iu id='com.android.ide.eclipse.traceview.feature.group' name='Android Traceview' version='22.2.1.v201309180102-833290'>
+ <iu id='com.android.ide.eclipse.traceview.feature.feature.group' name='Android Traceview' version='23.0.4.1468518'>
<repositories size='1'>
<repository location='https://dl-ssl.google.com/android/eclipse/'/>
</repositories>
</iu>
- <iu id='org.eclipse.mylyn.github.feature.feature.group' name='Eclipse GitHub integration with task focused interface' version='3.0.0.201306101825-r'>
+ <iu id='org.eclipse.recommenders.mylyn.rcp.feature.feature.group' name='Code Recommenders Mylyn Integration' version='2.1.9.v20140917-1240'>
<repositories size='1'>
- <repository location='http://download.eclipse.org/releases/kepler'/>
+ <repository location='http://download.eclipse.org/releases/luna'/>
</repositories>
</iu>
- <iu id='epp.package.java' name='Eclipse IDE for Java Developers' version='2.0.1.20130919-0803'>
+ <iu id='org.eclipse.recommenders.snipmatch.rcp.feature.feature.group' name='Code Recommenders Snipmatch' version='2.1.9.v20140917-1240'>
<repositories size='1'>
- <repository location='http://download.eclipse.org/releases/kepler'/>
+ <repository location='http://download.eclipse.org/releases/luna'/>
</repositories>
</iu>
- <iu id='edu.umd.cs.findbugs.plugin.eclipse.feature.group' name='FindBugs Feature' version='2.0.2.20121210'>
+ <iu id='org.eclipse.mylyn.github.feature.feature.group' name='Eclipse GitHub integration with task focused interface' version='3.5.0.201409260305-r'>
<repositories size='1'>
- <repository location='http://findbugs.cs.umd.edu/eclipse'/>
+ <repository location='http://download.eclipse.org/egit/github/updates'/>
+ </repositories>
+ </iu>
+ <iu id='epp.package.java' name='Eclipse IDE for Java Developers' version='4.4.1.20140925-1820'>
+ <repositories size='1'>
+ <repository location='http://download.eclipse.org/releases/luna'/>
+ </repositories>
+ </iu>
+ <iu id='edu.umd.cs.findbugs.plugin.eclipse.feature.group' name='FindBugs Feature' version='3.0.0.20140706-2cfb468'>
+ <repositories size='1'>
+ <repository location='http://findbugs.cs.umd.edu/eclipse/'/>
+ </repositories>
+ </iu>
+ <iu id='com.genymobile.genymotion.ide.eclipse.feature.group' name='Genymotion Eclipse Tools' version='1.0.3.201403261147'>
+ <repositories size='1'>
+ <repository location='http://plugins.genymotion.com/eclipse'/>
+ </repositories>
+ </iu>
+ <iu id='org.springsource.ide.eclipse.gradle.feature.feature.group' name='Gradle IDE' version='3.6.1.201408250705-RELEASE'>
+ <repositories size='1'>
+ <repository location='http://dist.springsource.com/release/TOOLS/gradle'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.jgit.http.apache.feature.group' name='Java implementation of Git - optional Http support using Apache httpclient' version='3.5.0.201409260305-r'>
+ <repositories size='1'>
+ <repository location='http://download.eclipse.org/egit/updates'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.jgit.java7.feature.group' name='Java implementation of Git - optional Java 7 libraries' version='3.5.0.201409260305-r'>
+ <repositories size='1'>
+ <repository location='http://download.eclipse.org/egit/updates'/>
+ </repositories>
+ </iu>
+ <iu id='org.eclipse.wst.jsdt.feature.feature.group' name='JavaScript Development Tools' version='1.6.100.v201409111605'>
+ <repositories size='1'>
+ <repository location='http://download.eclipse.org/releases/luna'/>
+ </repositories>
+ </iu>
+ <iu id='markdown.editor.feature.feature.group' name='Markdown Editor' version='0.2.3'>
+ <repositories size='1'>
+ <repository location='http://www.winterwell.com/software/updatesite/'/>
+ </repositories>
+ </iu>
+ <iu id='org.moreunit.feature.group' name='MoreUnit For Java' version='3.0.4'>
+ <repositories size='1'>
+ <repository location='http://moreunit.sourceforge.net/update-site/'/>
+ </repositories>
+ </iu>
+ <iu id='org.projectusus.feature.group' name='Project Usus' version='0.7.4.201401122006'>
+ <repositories size='1'>
+ <repository location='http://projectusus.googlecode.com/svn/updates/'/>
+ </repositories>
+ </iu>
+ <iu id='com.android.ide.eclipse.gldebugger.feature.feature.group' name='Tracer for OpenGL ES' version='23.0.4.1468518'>
+ <repositories size='1'>
+ <repository location='https://dl-ssl.google.com/android/eclipse/'/>
</repositories>
</iu>
</ius>
diff --git a/main/project/libraries/.gitignore b/main/project/libraries/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/main/project/libraries/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/main/project/libraries/pom.xml b/main/project/libraries/pom.xml
new file mode 100644
index 0000000..b59d4af
--- /dev/null
+++ b/main/project/libraries/pom.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.cgeo</groupId>
+ <artifactId>library.check</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <name>c:geo dependency update check</name>
+
+ <description>This project checks or updates c:geo dependencies.
+ Run 'mvn validate' to see available dependency updates.
+ Run 'mvn install' to actually update to the latest releases. You may need to refresh your IDE afterwards.
+ </description>
+
+ <properties>
+ <AndroidAnnotationsVersion>3.2</AndroidAnnotationsVersion>
+
+ <ButterKnifeVersion>6.1.0</ButterKnifeVersion>
+
+ <CommonsCollections4Version>4.0</CommonsCollections4Version>
+ <CommonsIoVersion>2.4</CommonsIoVersion>
+ <CommonsLang3Version>3.3.2</CommonsLang3Version>
+
+ <FindbugsAnnotationsVersion>3.0.0</FindbugsAnnotationsVersion>
+
+ <JacksonAnnotationsVersion>2.5.1</JacksonAnnotationsVersion>
+ <JacksonCoreVersion>2.5.1</JacksonCoreVersion>
+ <JacksonDatabindVersion>2.5.1</JacksonDatabindVersion>
+
+ <RXAndroidVersion>0.24.0</RXAndroidVersion>
+ <RXJavaVersion>1.0.7</RXJavaVersion>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.androidannotations</groupId>
+ <artifactId>androidannotations</artifactId>
+ <version>${AndroidAnnotationsVersion}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.androidannotations</groupId>
+ <artifactId>androidannotations-api</artifactId>
+ <version>${AndroidAnnotationsVersion}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.jakewharton</groupId>
+ <artifactId>butterknife</artifactId>
+ <version>${ButterKnifeVersion}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-collections4</artifactId>
+ <version>${CommonsCollections4Version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>${CommonsLang3Version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>${CommonsIoVersion}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>annotations</artifactId>
+ <version>${FindbugsAnnotationsVersion}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>${JacksonAnnotationsVersion}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${JacksonCoreVersion}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${JacksonDatabindVersion}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.reactivex</groupId>
+ <artifactId>rxjava</artifactId>
+ <version>${RXJavaVersion}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.reactivex</groupId>
+ <artifactId>rxandroid</artifactId>
+ <version>${RXAndroidVersion}</version>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>versions-maven-plugin</artifactId>
+ <version>2.1</version>
+ <executions>
+ <execution>
+ <id>display-property-updates</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>display-property-updates</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>update-properties</id>
+ <phase>package</phase>
+ <goals>
+ <goal>update-properties</goal>
+ </goals>
+ <configuration>
+ <allowSnapshots>false</allowSnapshots>
+ <allowMajorUpdates>true</allowMajorUpdates>
+ <allowMinorUpdates>true</allowMinorUpdates>
+ <generateBackupPoms>true</generateBackupPoms>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.9</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/../../libs</outputDirectory>
+ <overWriteReleases>true</overWriteReleases>
+ <excludeTransitive>true</excludeTransitive>
+ </configuration>
+ </execution>
+ <execution>
+ <id>src-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <classifier>sources</classifier>
+ <outputDirectory>${basedir}/../../libs/src</outputDirectory>
+ <failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
+ <overWriteReleases>true</overWriteReleases>
+ <excludeTransitive>true</excludeTransitive>
+ </configuration>
+ </execution>
+ <execution>
+ <id>javadoc-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <classifier>javadoc</classifier>
+ <outputDirectory>${basedir}/../../libs/src</outputDirectory>
+ <failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
+ <overWriteReleases>true</overWriteReleases>
+ <excludeTransitive>true</excludeTransitive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- unfinished: update properties files of source and javadoc
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <id>write-properties-files</id>
+ <phase>package</phase>
+ <configuration>
+ <tasks>
+ </tasks>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ -->
+ </plugins>
+ </build>
+</project>
diff --git a/main/project/libraries/update-libs.sh b/main/project/libraries/update-libs.sh
index f2e9ced..4c66254 100755
--- a/main/project/libraries/update-libs.sh
+++ b/main/project/libraries/update-libs.sh
@@ -1,7 +1,14 @@
#! /bin/sh
#
-RXJAVA=0.19.6
+RXJAVA=1.0.8
+RXANDROID=0.24.0
+JACKSONCORE=2.5.1
+JACKSONDATABIND=2.5.1
+JACKSONANNOTATIONS=2.5.1
+COMMONSCOLLECTIONS4=4.0
+COMMONSLANG3=3.3.2
+COMMONSIO=2.4
cd $(git rev-parse --show-toplevel)/main/libs
@@ -27,7 +34,21 @@ fixgradle() {
sed -i "/def $var =/s/.*/def $var = '$version'/" ../build.gradle
}
-updatelib com/netflix/rxjava rxjava-core $RXJAVA
-updatelib com/netflix/rxjava rxjava-android $RXJAVA
-updatelib com/netflix/rxjava rxjava-async-util $RXJAVA
-fixgradle RXVersion $RXJAVA
+updatelib io/reactivex rxjava $RXJAVA
+fixgradle RXJavaVersion $RXJAVA
+updatelib io/reactivex rxandroid $RXANDROID
+fixgradle RXAndroidVersion $RXANDROID
+
+updatelib com/fasterxml/jackson/core jackson-core $JACKSONCORE
+fixgradle JacksonCoreVersion $JACKSONCORE
+updatelib com/fasterxml/jackson/core jackson-databind $JACKSONDATABIND
+fixgradle JacksonDatabindVersion $JACKSONDATABIND
+updatelib com/fasterxml/jackson/core jackson-annotations $JACKSONANNOTATIONS
+fixgradle JacksonAnnotationsVersion $JACKSONANNOTATIONS
+
+updatelib org/apache/commons commons-collections4 $COMMONSCOLLECTIONS4
+fixgradle CommonsCollections4Version $COMMONSCOLLECTIONS4
+updatelib org/apache/commons commons-lang3 $COMMONSLANG3
+fixgradle CommonsLang3Version $COMMONSLANG3
+updatelib commons-io commons-io $COMMONSIO
+fixgradle CommonsIoVersion $COMMONSIO
diff --git a/main/project/rawimages/new-idea-modified.svg b/main/project/rawimages/new-idea-modified.svg
new file mode 100644
index 0000000..71e0966
--- /dev/null
+++ b/main/project/rawimages/new-idea-modified.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ x="0px"
+ y="0px"
+ viewBox="4.5 -9.0 90.0 121.5"
+ enable-background="new 0 0 90 90"
+ xml:space="preserve"
+ height="100px"
+ width="100px"
+ id="svg2"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="new-idea-modified.svg"
+ inkscape:export-filename="/home/rainer/Desktop/dev/android/cgeo_os/c-geo-opensource/main/project/rawimages/ic_menu_hint.png"
+ inkscape:export-xdpi="39.369999"
+ inkscape:export-ydpi="39.369999"><metadata
+ id="metadata37"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs35" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1878"
+ inkscape:window-height="1060"
+ id="namedview33"
+ showgrid="false"
+ inkscape:zoom="2.36"
+ inkscape:cx="-0.42372881"
+ inkscape:cy="50"
+ inkscape:window-x="-2"
+ inkscape:window-y="-3"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" /><switch
+ id="switch4"
+ transform="translate(6.1779661,6.1779661)"><foreignObject
+ requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/"
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ id="foreignObject6" /><g
+ i:extraneous="self"
+ id="g8"><g
+ id="Слой_1"><g
+ id="g11"><path
+ d="M 39,68.1 C 23.9,68.1 11.7,55.2 11.7,39.3 11.7,23.4 23.9,10.5 39,10.5 c 15.1,0 27.3,12.9 27.3,28.8 0,15.9 -12.2,28.8 -27.3,28.8 z m 0,-52.6 c -12.3,0 -22.3,10.7 -22.3,23.8 0,13.1 10,23.8 22.3,23.8 12.3,0 22.3,-10.7 22.3,-23.8 0,-13.1 -10,-23.8 -22.3,-23.8 z"
+ id="path13"
+ inkscape:connector-curvature="0" /></g><g
+ id="g15"><path
+ d="M 2.8,89.7 C 2.5,89.7 2.2,89.6 1.9,89.5 0.6,89 0,87.5 0.5,86.3 3.6,78.5 8.9,72 15.8,67.3 l 1.5,-1 1.4,1.1 c 6.3,4.6 13.7,7.1 21.6,7.1 7.3,0 14.4,-2.2 20.4,-6.3 l 1.5,-1 1.4,1.1 c 6.3,4.6 11.1,10.9 14,18.1 0.5,1.3 -0.1,2.7 -1.4,3.2 -1.3,0.5 -2.7,-0.1 -3.2,-1.4 -2.3,-5.8 -6.1,-11 -10.9,-14.9 -6.5,4 -14,6.2 -21.7,6.2 -8.3,0 -16.2,-2.4 -23,-7 C 12,76.5 7.9,82 5.3,88.3 4.7,89.1 3.8,89.7 2.8,89.7 z"
+ id="path17"
+ inkscape:connector-curvature="0" /></g><g
+ id="g19"><path
+ d="M 81.6,37.5 H 74.5 C 73.7,37.5 73,36.8 73,36 c 0,-0.8 0.7,-1.5 1.5,-1.5 h 7.1 c 0.8,0 1.5,0.7 1.5,1.5 0,0.8 -0.7,1.5 -1.5,1.5 z"
+ id="path21"
+ inkscape:connector-curvature="0" /></g><g
+ id="g23"><path
+ d="m 79.3,31.9 h -2 c -2.7,0 -4.8,-2.2 -4.8,-4.8 V 22.4 C 68.9,20.3 67,17.1 67,13 67,6.4 72,1 78.1,1 c 6.1,0 11.1,5.4 11.1,12 0,3.8 -1.7,6.9 -5,9.1 v 5.1 c -0.1,2.5 -2.3,4.7 -4.9,4.7 z M 78,4.9 c -3.9,0 -7.1,3.6 -7.1,8 0,3 1.4,5 4.3,6.4 l 1.1,0.5 V 27 c 0,0.4 0.4,0.8 0.8,0.8 h 2 c 0.4,0 0.8,-0.4 0.8,-0.8 v -7.3 l 1,-0.6 c 2.7,-1.5 3.9,-3.4 3.9,-6.2 0.3,-4.4 -2.9,-8 -6.8,-8 z"
+ id="path25"
+ inkscape:connector-curvature="0" /></g></g><g
+ id="Слой_2" /><g
+ id="Слой_3" /></g></switch></svg> \ No newline at end of file
diff --git a/main/project/rawimages/noun_104277_cc.svg b/main/project/rawimages/noun_104277_cc.svg
new file mode 100644
index 0000000..cf0efbb
--- /dev/null
+++ b/main/project/rawimages/noun_104277_cc.svg
@@ -0,0 +1,26 @@
+<svg xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="4.5 -9.0 90.0 121.5" enable-background="new 0 0 90 90" xml:space="preserve" height="100px" width="100px">
+<switch>
+ <foreignObject requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/" x="0" y="0" width="1" height="1">
+ </foreignObject>
+ <g i:extraneous="self">
+ <g id="&#1057;&#1083;&#1086;&#1081;_1">
+ <g>
+ <path d="M39,68.1c-15.1,0-27.3-12.9-27.3-28.8S23.9,10.5,39,10.5c15.1,0,27.3,12.9,27.3,28.8S54.1,68.1,39,68.1z M39,15.5 c-12.3,0-22.3,10.7-22.3,23.8c0,13.1,10,23.8,22.3,23.8c12.3,0,22.3-10.7,22.3-23.8C61.3,26.2,51.3,15.5,39,15.5z"/>
+ </g>
+ <g>
+ <path d="M2.8,89.7c-0.3,0-0.6-0.1-0.9-0.2c-1.3-0.5-1.9-2-1.4-3.2c3.1-7.8,8.4-14.3,15.3-19l1.5-1l1.4,1.1 c6.3,4.6,13.7,7.1,21.6,7.1c7.3,0,14.4-2.2,20.4-6.3l1.5-1l1.4,1.1c6.3,4.6,11.1,10.9,14,18.1c0.5,1.3-0.1,2.7-1.4,3.2 c-1.3,0.5-2.7-0.1-3.2-1.4c-2.3-5.8-6.1-11-10.9-14.9c-6.5,4-14,6.2-21.7,6.2c-8.3,0-16.2-2.4-23-7c-5.4,4-9.5,9.5-12.1,15.8 C4.7,89.1,3.8,89.7,2.8,89.7z"/>
+ </g>
+ <g>
+ <path d="M81.6,37.5h-7.1c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5h7.1c0.8,0,1.5,0.7,1.5,1.5S82.4,37.5,81.6,37.5z"/>
+ </g>
+ <g>
+ <path d="M79.3,31.9h-2c-2.7,0-4.8-2.2-4.8-4.8v-4.7c-3.6-2.1-5.5-5.3-5.5-9.4c0-6.6,5-12,11.1-12s11.1,5.4,11.1,12 c0,3.8-1.7,6.9-5,9.1v5.1C84.1,29.7,81.9,31.9,79.3,31.9z M78,4.9c-3.9,0-7.1,3.6-7.1,8c0,3,1.4,5,4.3,6.4l1.1,0.5v7.2 c0,0.4,0.4,0.8,0.8,0.8h2c0.4,0,0.8-0.4,0.8-0.8v-7.3l1-0.6c2.7-1.5,3.9-3.4,3.9-6.2C85.1,8.5,81.9,4.9,78,4.9z"/>
+ </g>
+ </g>
+ <g id="&#1057;&#1083;&#1086;&#1081;_2">
+ </g>
+ <g id="&#1057;&#1083;&#1086;&#1081;_3">
+ </g>
+ </g>
+</switch>
+<text x="0.0" y="105.75" font-size="4.5" font-weight="bold" font-family="Helvetica Neue, Helvetica, Arial-Unicode, Arial, Sans-serif" fill="#000000">Created by Artem Korotkikh</text><text x="0.0" y="110.25" font-size="4.5" font-weight="bold" font-family="Helvetica Neue, Helvetica, Arial-Unicode, Arial, Sans-serif" fill="#000000">from the Noun Project</text></svg> \ No newline at end of file
diff --git a/main/res/drawable-hdpi/ic_menu_hint.png b/main/res/drawable-hdpi/ic_menu_hint.png
new file mode 100644
index 0000000..1b3c7ad
--- /dev/null
+++ b/main/res/drawable-hdpi/ic_menu_hint.png
Binary files differ
diff --git a/main/res/drawable-hdpi/ic_menu_mylocation_off.png b/main/res/drawable-hdpi/ic_menu_mylocation_off.png
new file mode 100644
index 0000000..d3e962f
--- /dev/null
+++ b/main/res/drawable-hdpi/ic_menu_mylocation_off.png
Binary files differ
diff --git a/main/res/drawable-hdpi/star_half.png b/main/res/drawable-hdpi/star_half.png
deleted file mode 100644
index 000208c..0000000
--- a/main/res/drawable-hdpi/star_half.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_barcode.png b/main/res/drawable-ldpi/ic_menu_barcode.png
deleted file mode 100644
index 3329f45..0000000
--- a/main/res/drawable-ldpi/ic_menu_barcode.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_filter.png b/main/res/drawable-ldpi/ic_menu_filter.png
deleted file mode 100644
index 11b728d..0000000
--- a/main/res/drawable-ldpi/ic_menu_filter.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_goto.png b/main/res/drawable-ldpi/ic_menu_goto.png
deleted file mode 100644
index d15ea3d..0000000
--- a/main/res/drawable-ldpi/ic_menu_goto.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_shopping.png b/main/res/drawable-ldpi/ic_menu_shopping.png
deleted file mode 100644
index e881d50..0000000
--- a/main/res/drawable-ldpi/ic_menu_shopping.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/ic_menu_trail.png b/main/res/drawable-ldpi/ic_menu_trail.png
deleted file mode 100644
index 2911566..0000000
--- a/main/res/drawable-ldpi/ic_menu_trail.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-ldpi/star_half.png b/main/res/drawable-ldpi/star_half.png
deleted file mode 100644
index 97fa464..0000000
--- a/main/res/drawable-ldpi/star_half.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-mdpi/ic_menu_hint.png b/main/res/drawable-mdpi/ic_menu_hint.png
new file mode 100644
index 0000000..e9cfcd6
--- /dev/null
+++ b/main/res/drawable-mdpi/ic_menu_hint.png
Binary files differ
diff --git a/main/res/drawable-mdpi/star_half.png b/main/res/drawable-mdpi/star_half.png
deleted file mode 100644
index 1ea9152..0000000
--- a/main/res/drawable-mdpi/star_half.png
+++ /dev/null
Binary files differ
diff --git a/main/res/drawable-xhdpi/ic_menu_hint.png b/main/res/drawable-xhdpi/ic_menu_hint.png
new file mode 100644
index 0000000..0c39096
--- /dev/null
+++ b/main/res/drawable-xhdpi/ic_menu_hint.png
Binary files differ
diff --git a/main/res/drawable-xxhdpi/ic_menu_hint.png b/main/res/drawable-xxhdpi/ic_menu_hint.png
new file mode 100644
index 0000000..c0c2ce3
--- /dev/null
+++ b/main/res/drawable-xxhdpi/ic_menu_hint.png
Binary files differ
diff --git a/main/res/drawable/star_rating.xml b/main/res/drawable/star_rating.xml
new file mode 100644
index 0000000..0d8a8e2
--- /dev/null
+++ b/main/res/drawable/star_rating.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+android:id/background"
+ android:drawable="@drawable/star_off" />
+ <item android:id="@+android:id/secondaryProgress"
+ android:drawable="@drawable/star_off" />
+ <item android:id="@+android:id/progress"
+ android:drawable="@drawable/star_on" />
+</layer-list> \ No newline at end of file
diff --git a/main/res/layout-land/coordinatesinput_dialog.xml b/main/res/layout-land/coordinatesinput_dialog.xml
index 202f1d3..001582b 100644
--- a/main/res/layout-land/coordinatesinput_dialog.xml
+++ b/main/res/layout-land/coordinatesinput_dialog.xml
@@ -14,7 +14,8 @@
<Spinner
android:id="@+id/spinnerCoordinateFormats"
android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ tools:listitem="@android:layout/simple_spinner_item" />
<TableLayout
android:id="@+id/coordTable"
@@ -156,6 +157,14 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/waypoint_cache_coordinates" />
+
+ <Button
+ android:id="@+id/clipboard"
+ style="@style/button_full"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/from_clipboard"
+ android:visibility="gone" />
</LinearLayout>
<Button
diff --git a/main/res/layout-v11/actionbar_maps.xml b/main/res/layout-v11/actionbar_maps.xml
index 3e72717..ee77673 100644
--- a/main/res/layout-v11/actionbar_maps.xml
+++ b/main/res/layout-v11/actionbar_maps.xml
@@ -1,7 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ style="@style/action_bar" >
- <!-- Empty layout, on 11+ we have a real action bar -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent" android:layout_height="match_parent">
+ <!-- Add the up chevron to the icon -->
-</merge> \ No newline at end of file
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/abc_ic_ab_back_holo_dark" />
+
+ <ImageView
+ style="@style/action_bar_action"
+ android:layout_marginLeft="-13dp"
+ android:onClick="navigateUp" />
+
+ <View style="@style/action_bar_separator" />
+
+ <TextView
+ android:id="@+id/actionbar_title"
+ style="@style/action_bar_title"
+ tools:ignore="InconsistentLayout" />
+
+ <ProgressBar
+ android:id="@+id/actionbar_progress"
+ style="@style/action_bar_progress"
+ android:visibility="gone"
+ tools:ignore="InconsistentLayout" />
+
+ <View style="@style/action_bar_separator" />
+
+ <FrameLayout style="@style/action_bar_action" >
+
+ <CheckBox
+ android:id="@+id/my_position"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:button="@drawable/ic_menu_myposition"
+ android:checked="false"
+ tools:ignore="InconsistentLayout" />
+ </FrameLayout>
+
+ <View style="@style/action_bar_separator" />
+
+ <ImageView
+ android:id="@+id/overflowActionBar"
+ style="@style/action_bar_action"
+ android:longClickable="true"
+ android:src="@drawable/abc_ic_menu_moreoverflow_normal_holo_dark" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout-v14/actionbar_maps.xml b/main/res/layout-v14/actionbar_maps.xml
new file mode 100644
index 0000000..7ee9b51
--- /dev/null
+++ b/main/res/layout-v14/actionbar_maps.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+ <!-- Empty layout, on 14+ we have a real and working action bar -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent" android:layout_height="match_parent">
+
+</merge> \ No newline at end of file
diff --git a/main/res/layout/about_changes_page.xml b/main/res/layout/about_changes_page.xml
index 544d338..04b5ff3 100644
--- a/main/res/layout/about_changes_page.xml
+++ b/main/res/layout/about_changes_page.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".AboutActivity$ChangeLogViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
@@ -35,6 +37,21 @@
android:textColor="?text_color"
android:textColorLink="?text_color_link"
android:textSize="12sp" />
+
+ <TextView
+ android:id="@+id/changelog_github"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="true"
+ android:text="@string/changelog_github"
+ android:textColor="?text_color_link"
+ android:textColorLink="?text_color_link"
+ android:textSize="12sp" />
</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/about_contributors_page.xml b/main/res/layout/about_contributors_page.xml
index 9a0955e..844cb34 100644
--- a/main/res/layout/about_contributors_page.xml
+++ b/main/res/layout/about_contributors_page.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".AboutActivity$ContributorsViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/about_help_page.xml b/main/res/layout/about_help_page.xml
index 0439e22..ed64b92 100644
--- a/main/res/layout/about_help_page.xml
+++ b/main/res/layout/about_help_page.xml
@@ -1,110 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".AboutActivity$HelpViewCreator" >
- <LinearLayout
- android:layout_width="fill_parent"
+ <TableLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical" >
+ android:paddingLeft="10dp" >
- <TextView
- android:id="@+id/faq"
+ <TableRow
+ android:id="@+id/tableRow1"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/faq"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/website"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/faq_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/faq"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/faq_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tableRow2"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/website"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/facebook"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/website_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/website"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/website_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tableRow3"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/facebook"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/twitter"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/facebook_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/facebook"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/facebook_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tableRow4"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/twitter"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/support"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/twitter_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/twitter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/twitter_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tableRow5"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/support"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/market"
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/support_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/support"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/support_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+
+ <TableRow
+ android:id="@+id/tableRow6"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="10dip"
- android:layout_marginRight="10dip"
- android:clickable="true"
- android:focusable="true"
- android:linksClickable="false"
- android:text="@string/market"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textSize="14sp" />
- </LinearLayout>
+ android:layout_height="wrap_content" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/market_title"
+ android:textColor="?text_color"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/market"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:clickable="true"
+ android:focusable="true"
+ android:linksClickable="false"
+ android:text="@string/market_link"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+ </TableRow>
+ </TableLayout>
</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/about_license_page.xml b/main/res/layout/about_license_page.xml
index b33f0f9..e91adf1 100644
--- a/main/res/layout/about_license_page.xml
+++ b/main/res/layout/about_license_page.xml
@@ -4,7 +4,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".AboutActivity$LicenseViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/about_system_page.xml b/main/res/layout/about_system_page.xml
new file mode 100644
index 0000000..0fd9624
--- /dev/null
+++ b/main/res/layout/about_system_page.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:padding="4dip"
+ tools:context=".AboutActivity$SystemViewCreator" >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <Button android:id="@+id/copy"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/copy_to_clipboard"
+ android:layout_gravity="center_horizontal"
+ android:padding="12dp" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:layout_margin="7dip"
+ android:linksClickable="true"
+ android:paddingLeft="3dip"
+ android:text="@string/about_system_include"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/system"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:layout_margin="7dip"
+ android:linksClickable="true"
+ android:paddingLeft="3dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textIsSelectable="true"
+ android:textSize="12sp" />
+ </LinearLayout>
+
+</ScrollView>
diff --git a/main/res/layout/about_version_page.xml b/main/res/layout/about_version_page.xml
index 80630e4..53f9927 100644
--- a/main/res/layout/about_version_page.xml
+++ b/main/res/layout/about_version_page.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".AboutActivity$VersionViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
@@ -83,6 +85,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
+ android:baselineAligned="false"
android:gravity="center_horizontal"
android:orientation="horizontal" >
diff --git a/main/res/layout/addresslist_activity.xml b/main/res/layout/addresslist_activity.xml
index 4fbe53c..57d13f2 100644
--- a/main/res/layout/addresslist_activity.xml
+++ b/main/res/layout/addresslist_activity.xml
@@ -3,7 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".AddressListActivity" >
<ListView
android:id="@android:id/list"
diff --git a/main/res/layout/addresslist_item.xml b/main/res/layout/addresslist_item.xml
index dac1768..aa04728 100644
--- a/main/res/layout/addresslist_item.xml
+++ b/main/res/layout/addresslist_item.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/button_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -9,7 +10,8 @@
android:paddingBottom="7dip"
android:paddingLeft="5dip"
android:paddingRight="5dip"
- android:paddingTop="7dip" >
+ android:paddingTop="7dip"
+ tools:context=".ui.AddressListAdapter" >
<TextView
android:id="@+id/label"
diff --git a/main/res/layout/attribute_descriptions.xml b/main/res/layout/attribute_descriptions.xml
deleted file mode 100644
index 1e67f72..0000000
--- a/main/res/layout/attribute_descriptions.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/attribute_descriptions"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/attribute_descriptions_textview"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:linksClickable="true"
- android:textColor="?text_color"
- android:textColorLink="?text_color_link"
- android:textIsSelectable="false"
- android:textSize="14sp" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/attribute_image.xml b/main/res/layout/attribute_image.xml
index f68aef4..75eff6a 100644
--- a/main/res/layout/attribute_image.xml
+++ b/main/res/layout/attribute_image.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/attribute_images"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ tools:context=".CacheDetailActivity$AttributeViewBuilder" >
<ImageView
android:id="@+id/attribute_image"
diff --git a/main/res/layout/authorization_activity.xml b/main/res/layout/authorization_activity.xml
index 2907286..6364ee2 100644
--- a/main/res/layout/authorization_activity.xml
+++ b/main/res/layout/authorization_activity.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".network.OAuthAuthorizationActivity" >
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/cache_information_item.xml b/main/res/layout/cache_information_item.xml
index 1b766e4..d213e56 100644
--- a/main/res/layout/cache_information_item.xml
+++ b/main/res/layout/cache_information_item.xml
@@ -34,17 +34,17 @@
android:textIsSelectable="false"
android:textSize="14sp" />
- <LinearLayout
+ <RatingBar
android:id="@+id/stars"
+ style="@style/cacheRatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
+ android:layout_gravity="center_horizontal"
android:layout_toRightOf="@+id/value"
android:baselineAligned="false"
android:gravity="center_vertical"
- android:orientation="horizontal"
- android:visibility="gone" >
- </LinearLayout>
+ android:visibility="gone" />
<TextView
android:id="@+id/addition"
diff --git a/main/res/layout/cachedetail_activity.xml b/main/res/layout/cachedetail_activity.xml
index d197bcd..b2e16a0 100644
--- a/main/res/layout/cachedetail_activity.xml
+++ b/main/res/layout/cachedetail_activity.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".CacheDetailActivity" >
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
diff --git a/main/res/layout/cachedetail_description_page.xml b/main/res/layout/cachedetail_description_page.xml
index dba6789..4fa342d 100644
--- a/main/res/layout/cachedetail_description_page.xml
+++ b/main/res/layout/cachedetail_description_page.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
+ android:layout_height="fill_parent"
+ tools:context=".CacheDetailActivity$DescriptionViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
@@ -134,6 +136,7 @@
android:id="@+id/edit_personalnote"
style="@style/button_small"
android:text="@string/cache_personal_note_edit" />
+
<Button
android:id="@+id/upload_personalnote"
style="@style/button_small"
diff --git a/main/res/layout/cachedetail_details_page.xml b/main/res/layout/cachedetail_details_page.xml
index 7b67846..7b48554 100644
--- a/main/res/layout/cachedetail_details_page.xml
+++ b/main/res/layout/cachedetail_details_page.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:scrollbars="none" >
+ android:scrollbars="none"
+ tools:context=".CacheDetailActivity$DetailsViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
@@ -25,23 +27,38 @@
android:id="@+id/attributes_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone" >
+ android:orientation="vertical" >
<View
style="@style/separator_horizontal"
android:layout_marginBottom="9dp"
android:layout_marginTop="9dp" />
- <!-- innerbox is only needed to define the paddings easily -->
+ <cgeo.geocaching.ui.WrappingGridView
+ android:id="@+id/attributes_grid"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:columnWidth="32dip"
+ android:horizontalSpacing="2dip"
+ android:numColumns="auto_fit"
+ android:paddingLeft="6dp"
+ android:paddingRight="6dp"
+ android:scrollbars="none"
+ android:stretchMode="none"
+ android:verticalSpacing="2dip" />
- <LinearLayout
- android:id="@+id/attributes_innerbox"
+ <TextView
+ android:id="@+id/attributes_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:layout_gravity="left"
+ android:linksClickable="true"
android:paddingLeft="6dp"
- android:paddingRight="6dp" />
+ android:paddingRight="6dp"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:textIsSelectable="false"
+ android:textSize="14sp" />
</LinearLayout>
<!-- Offline box -->
diff --git a/main/res/layout/cachedetail_images_page.xml b/main/res/layout/cachedetail_images_page.xml
index 2360dd0..cf26fe5 100644
--- a/main/res/layout/cachedetail_images_page.xml
+++ b/main/res/layout/cachedetail_images_page.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".CacheDetailActivity$ImagesViewCreator" >
<LinearLayout
android:id="@+id/spoiler_list"
diff --git a/main/res/layout/cachedetail_inventory_page.xml b/main/res/layout/cachedetail_inventory_page.xml
index a15cedd..c134a79 100644
--- a/main/res/layout/cachedetail_inventory_page.xml
+++ b/main/res/layout/cachedetail_inventory_page.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="?background_color"
android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay" >
+ android:scrollbarStyle="outsideOverlay"
+ tools:context=".CacheDetailActivity$InventoryViewCreator" >
</ListView> \ No newline at end of file
diff --git a/main/res/layout/cachedetail_waypoints_footer.xml b/main/res/layout/cachedetail_waypoints_footer.xml
index 58187c1..440363b 100644
--- a/main/res/layout/cachedetail_waypoints_footer.xml
+++ b/main/res/layout/cachedetail_waypoints_footer.xml
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/add_waypoint"
style="@style/button_full"
android:layout_margin="10dip"
- android:padding="10dip"
android:clickable="true"
- android:text="@string/cache_waypoints_add" />
-
+ android:padding="10dip"
+ android:text="@string/cache_waypoints_add"
+ tools:context=".CacheDetailActivity$WaypointsViewCreator" />
diff --git a/main/res/layout/cachedetail_waypoints_page.xml b/main/res/layout/cachedetail_waypoints_page.xml
index 8111210..dbf896a 100644
--- a/main/res/layout/cachedetail_waypoints_page.xml
+++ b/main/res/layout/cachedetail_waypoints_page.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="?background_color"
@@ -11,6 +12,7 @@
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:listSelector="?background_color"
- android:scrollbarStyle="outsideOverlay" >
+ android:scrollbarStyle="outsideOverlay"
+ tools:context=".CacheDetailActivity$WaypointsViewCreator" >
</ListView> \ No newline at end of file
diff --git a/main/res/layout/cachelist_spinneritem.xml b/main/res/layout/cachelist_spinneritem.xml
index 58e070e..fce9b88 100644
--- a/main/res/layout/cachelist_spinneritem.xml
+++ b/main/res/layout/cachelist_spinneritem.xml
@@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- android:orientation="vertical" android:layout_width="match_parent"
+ style="?attr/spinnerDropDownItemStyle"
+ android:layout_width="match_parent"
android:layout_height="?attr/dropdownListPreferredItemHeight"
- android:minHeight="?attr/dropdownListPreferredItemHeight"
android:layout_gravity="left|center_vertical"
- style="?attr/spinnerDropDownItemStyle"
- >
-
+ android:minHeight="?attr/dropdownListPreferredItemHeight"
+ android:orientation="vertical"
+ tools:context=".CacheListSpinnerAdapter" >
<TextView
android:id="@android:id/text1"
diff --git a/main/res/layout/cacheslist_activity.xml b/main/res/layout/cacheslist_activity.xml
index 561baa2..62d9861 100644
--- a/main/res/layout/cacheslist_activity.xml
+++ b/main/res/layout/cacheslist_activity.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".CacheListActivity" >
<include layout="@layout/filter_bar" />
@@ -33,6 +35,7 @@
android:fastScrollEnabled="true"
android:padding="0dip"
android:scrollbarStyle="outsideOverlay"
- android:visibility="gone" />
+ android:visibility="gone"
+ tools:listitem="@layout/cacheslist_item" />
</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/cacheslist_footer.xml b/main/res/layout/cacheslist_footer.xml
index ed2de18..ff323f4 100644
--- a/main/res/layout/cacheslist_footer.xml
+++ b/main/res/layout/cacheslist_footer.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/more_caches"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
@@ -13,4 +14,5 @@
android:singleLine="true"
android:text="@string/caches_no_cache"
android:textColor="@color/just_white"
- android:textSize="16sp" />
+ android:textSize="16sp"
+ tools:context=".CacheListActivity" />
diff --git a/main/res/layout/cacheslist_item.xml b/main/res/layout/cacheslist_item.xml
index 260b0d0..9c5ca28 100644
--- a/main/res/layout/cacheslist_item.xml
+++ b/main/res/layout/cacheslist_item.xml
@@ -5,7 +5,8 @@
android:id="@+id/one_cache"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="?background_color" >
+ android:background="?background_color"
+ tools:context=".ui.CacheListAdapter" >
<!-- selection mode checkbox -->
@@ -139,15 +140,23 @@
android:layout_marginBottom="1dip"
android:layout_marginTop="1dip" >
- <ImageView
+ <TextView
android:id="@+id/inventory"
android:layout_width="35dip"
android:layout_height="22dip"
android:layout_alignParentTop="true"
android:layout_gravity="center_vertical|center_horizontal"
android:background="?inventory"
+ android:drawableLeft="@drawable/trackable_all"
+ android:drawablePadding="-10sp"
+ android:gravity="center"
android:scaleType="center"
- android:src="@drawable/trackable_all" />
+ android:singleLine="true"
+ android:text=""
+ android:textColor="?text_color"
+ android:textIsSelectable="false"
+ android:textSize="12sp"
+ android:textStyle="bold" />
<TextView
android:id="@+id/favorite"
diff --git a/main/res/layout/compass_activity.xml b/main/res/layout/compass_activity.xml
index ca61cc3..f618d71 100644
--- a/main/res/layout/compass_activity.xml
+++ b/main/res/layout/compass_activity.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".CompassActivity" >
<LinearLayout
android:id="@+id/info1"
@@ -16,16 +18,20 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:text="@null"
android:textColor="?text_color"
- android:textSize="14sp" />
+ android:textSize="14sp"
+ tools:text="Destination coordinates" />
<TextView
android:id="@+id/cacheinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:text="@null"
android:textColor="?text_color"
- android:textSize="14sp" />
+ android:textSize="14sp"
+ tools:text="Cache information (D/T/S)" />
<RelativeLayout
android:layout_width="fill_parent"
@@ -40,7 +46,8 @@
android:layout_marginLeft="3dip"
android:text="@null"
android:textColor="?text_color"
- android:textSize="26sp" />
+ android:textSize="26sp"
+ tools:text="123°" />
<TextView
android:id="@+id/distance"
@@ -51,7 +58,8 @@
android:layout_marginRight="3dip"
android:text="@null"
android:textColor="?text_color"
- android:textSize="26sp" />
+ android:textSize="26sp"
+ tools:text="123 km" />
</RelativeLayout>
</LinearLayout>
diff --git a/main/res/layout/coordinatesinput_dialog.xml b/main/res/layout/coordinatesinput_dialog.xml
index 9b5cb8d..805d455 100644
--- a/main/res/layout/coordinatesinput_dialog.xml
+++ b/main/res/layout/coordinatesinput_dialog.xml
@@ -3,7 +3,8 @@
android:id="@+id/scroller"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:fillViewport="true" >
+ android:fillViewport="true"
+ tools:context=".ui.dialog.CoordinatesInputDialog" >
<LinearLayout
android:id="@+id/scroller_child"
@@ -14,7 +15,8 @@
<Spinner
android:id="@+id/spinnerCoordinateFormats"
android:layout_width="fill_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ tools:listitem="@android:layout/simple_spinner_item" />
<TableLayout
android:id="@+id/coordTable"
@@ -151,6 +153,14 @@
android:text="@string/waypoint_cache_coordinates" />
<Button
+ android:id="@+id/clipboard"
+ style="@style/button_full"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/from_clipboard"
+ android:visibility="gone" />
+
+ <Button
android:id="@+id/done"
style="@style/button_full"
android:layout_width="fill_parent"
diff --git a/main/res/layout/editwaypoint_activity.xml b/main/res/layout/editwaypoint_activity.xml
index c21e25d..c11ffea 100644
--- a/main/res/layout/editwaypoint_activity.xml
+++ b/main/res/layout/editwaypoint_activity.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".EditWaypointActivity" >
<LinearLayout
android:layout_width="fill_parent"
@@ -46,19 +48,22 @@
android:id="@+id/distanceUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:entries="@array/distance_units" />
- </LinearLayout>
+ android:entries="@array/distance_units"
+ tools:listitem="@android:layout/simple_spinner_item" />
- <AutoCompleteTextView
- android:id="@+id/name"
- style="@style/edittext_full"
- android:hint="@string/waypoint_name" />
+ </LinearLayout>
<Spinner
android:id="@+id/type"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:visibility="gone" />
+ android:visibility="gone"
+ tools:listitem="@android:layout/simple_spinner_item" />
+
+ <AutoCompleteTextView
+ android:id="@+id/name"
+ style="@style/edittext_full"
+ android:hint="@string/waypoint_name" />
<EditText
android:id="@+id/note"
diff --git a/main/res/layout/fieldnote_export_dialog.xml b/main/res/layout/fieldnote_export_dialog.xml
index 9859b0f..c76225c 100644
--- a/main/res/layout/fieldnote_export_dialog.xml
+++ b/main/res/layout/fieldnote_export_dialog.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:padding="3dip" >
+ android:padding="3dip"
+ tools:context=".export.FieldnoteExport" >
<TextView
android:layout_width="wrap_content"
diff --git a/main/res/layout/filter_activity.xml b/main/res/layout/filter_activity.xml
new file mode 100644
index 0000000..8858452
--- /dev/null
+++ b/main/res/layout/filter_activity.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ tools:context=".filter.FilterActivity" >
+
+ <ScrollView
+ android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <LinearLayout
+ android:id="@+id/filters"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ </LinearLayout>
+ </ScrollView>
+
+
+ <ExpandableListView
+ android:id="@+id/filterList"
+ android:layout_width="match_parent"
+ android:layout_height="fill_parent" >
+ </ExpandableListView>
+
+</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/filter_list_child.xml b/main/res/layout/filter_list_child.xml
new file mode 100644
index 0000000..7978269
--- /dev/null
+++ b/main/res/layout/filter_list_child.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:layout_marginTop="6dip"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
diff --git a/main/res/layout/fragment_edit_note.xml b/main/res/layout/fragment_edit_note.xml
index 1e9fbf9..893dc31 100644
--- a/main/res/layout/fragment_edit_note.xml
+++ b/main/res/layout/fragment_edit_note.xml
@@ -1,9 +1,11 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/edit_note"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".ui.EditNoteDialog" >
<EditText
android:id="@+id/note"
diff --git a/main/res/layout/gcvote_dialog.xml b/main/res/layout/gcvote_dialog.xml
new file mode 100644
index 0000000..221a8f5
--- /dev/null
+++ b/main/res/layout/gcvote_dialog.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+
+ <include layout="@layout/gcvote_rating_bar" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/gcvote_rating_bar.xml b/main/res/layout/gcvote_rating_bar.xml
new file mode 100644
index 0000000..87d4ef5
--- /dev/null
+++ b/main/res/layout/gcvote_rating_bar.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" >
+
+ <RatingBar
+ android:id="@+id/gcvoteRating"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:max="5"
+ android:numStars="5"
+ android:stepSize="0.5"
+ android:visibility="gone" />
+
+ <TextView
+ android:id="@+id/gcvoteLabel"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:padding="10dip"
+ android:text="@string/log_no_rating"
+ android:textColor="?text_color"
+ android:textSize="12sp"
+ android:visibility="gone" />
+
+</merge>
diff --git a/main/res/layout/gpx.xml b/main/res/layout/gpx.xml
index 4367f82..fc743bd 100644
--- a/main/res/layout/gpx.xml
+++ b/main/res/layout/gpx.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:background="?background_color"
+ tools:context=".files.AbstractFileListActivity" >
<Button
android:id="@+id/select_dir"
diff --git a/main/res/layout/gpx_export_dialog.xml b/main/res/layout/gpx_export_dialog.xml
index 9c97848..02e9134 100644
--- a/main/res/layout/gpx_export_dialog.xml
+++ b/main/res/layout/gpx_export_dialog.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:padding="3dip" >
+ android:padding="3dip"
+ tools:context=".export.GpxExport" >
<TextView
android:id="@id/info"
diff --git a/main/res/layout/gpx_item.xml b/main/res/layout/gpx_item.xml
index f0a0647..372bb9a 100644
--- a/main/res/layout/gpx_item.xml
+++ b/main/res/layout/gpx_item.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/button_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -9,7 +10,8 @@
android:paddingBottom="7dip"
android:paddingLeft="5dip"
android:paddingRight="5dip"
- android:paddingTop="7dip" >
+ android:paddingTop="7dip"
+ tools:context=".ui.GPXListAdapter" >
<TextView
android:id="@+id/filepath"
diff --git a/main/res/layout/grid_image.xml b/main/res/layout/grid_image.xml
new file mode 100644
index 0000000..4e145f5
--- /dev/null
+++ b/main/res/layout/grid_image.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="0dp"
+ android:scaleType="fitCenter"
+ android:src="@drawable/type_traditional"
+ tools:context=".filter.FilterActivity" >
+
+</ImageView> \ No newline at end of file
diff --git a/main/res/layout/image_item.xml b/main/res/layout/image_item.xml
index 3478444..5eae256 100644
--- a/main/res/layout/image_item.xml
+++ b/main/res/layout/image_item.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:gravity="center" />
+ android:gravity="center"
+ tools:context=".ui.ImagesList" />
diff --git a/main/res/layout/images_activity.xml b/main/res/layout/images_activity.xml
index 861fa7e..d32e9e5 100644
--- a/main/res/layout/images_activity.xml
+++ b/main/res/layout/images_activity.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".ImagesActivity" >
<include layout="@layout/cachedetail_images_page" />
diff --git a/main/res/layout/images_gridview.xml b/main/res/layout/images_gridview.xml
new file mode 100644
index 0000000..b3993af
--- /dev/null
+++ b/main/res/layout/images_gridview.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<GridView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/gridView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:columnWidth="80dp"
+ android:gravity="center"
+ android:horizontalSpacing="0dp"
+ android:numColumns="auto_fit"
+ android:stretchMode="spacingWidth"
+ android:verticalSpacing="0dp"
+ tools:listitem="@layout/grid_image" >
+
+</GridView>
diff --git a/main/res/layout/imageselect_activity.xml b/main/res/layout/imageselect_activity.xml
index 690baa2..59c90a4 100644
--- a/main/res/layout/imageselect_activity.xml
+++ b/main/res/layout/imageselect_activity.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".ImageSelectActivity" >
<LinearLayout
android:layout_width="fill_parent"
@@ -24,6 +26,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dip"
+ android:baselineAligned="false"
android:orientation="horizontal" >
<Button
@@ -76,7 +79,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:entries="@array/log_image_scales"
- android:prompt="@string/log_image_scale" />
+ android:prompt="@string/log_image_scale"
+ tools:listitem="@android:layout/simple_spinner_item" />
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/internal_browser.xml b/main/res/layout/internal_browser.xml
index 1e09ee0..cf38076 100644
--- a/main/res/layout/internal_browser.xml
+++ b/main/res/layout/internal_browser.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".activity.SimpleWebviewActivity" >
<WebView
- android:id="@+id/webview"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:id="@+id/webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/livemapinfo.xml b/main/res/layout/livemapinfo.xml
index 889febc..564ed00 100644
--- a/main/res/layout/livemapinfo.xml
+++ b/main/res/layout/livemapinfo.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/live_map_scroll"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".ui.dialog.LiveMapInfoDialogBuilder" >
<LinearLayout
android:layout_width="fill_parent"
@@ -18,7 +20,6 @@
android:text="@string/live_map_notification"
android:textColor="?text_color"
android:textSize="14sp" />
-
</LinearLayout>
</ScrollView> \ No newline at end of file
diff --git a/main/res/layout/logcache_activity.xml b/main/res/layout/logcache_activity.xml
index b01ea74..2e966d1 100644
--- a/main/res/layout/logcache_activity.xml
+++ b/main/res/layout/logcache_activity.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
android:orientation="vertical"
- android:padding="4dip" xmlns:tools="http://schemas.android.com/tools">
+ android:padding="4dip"
+ tools:context=".LogCacheActivity" >
<LinearLayout
android:layout_width="fill_parent"
@@ -20,6 +22,7 @@
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:baselineAligned="false"
android:orientation="horizontal" >
<Button
@@ -69,29 +72,9 @@
android:inputType="text"
android:singleLine="true"
tools:ignore="TextFields" />
-
</LinearLayout>
- <RatingBar
- android:id="@+id/gcvoteRating"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:max="5"
- android:numStars="5"
- android:stepSize="0.5"
- android:visibility="gone" />
-
- <TextView
- android:id="@+id/gcvoteLabel"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:padding="10dip"
- android:text="@string/log_no_rating"
- android:textColor="?text_color"
- android:textSize="12sp"
- android:visibility="gone" />
+ <include layout="@layout/gcvote_rating_bar" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/tweet_box"
diff --git a/main/res/layout/logcache_trackable_item.xml b/main/res/layout/logcache_trackable_item.xml
index 1eab116..72082ac 100644
--- a/main/res/layout/logcache_trackable_item.xml
+++ b/main/res/layout/logcache_trackable_item.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:orientation="horizontal"
android:paddingBottom="10dip"
android:paddingLeft="10dip"
- android:paddingRight="10dip" >
+ android:paddingRight="10dip"
+ tools:context=".LogCacheActivity" >
<LinearLayout
android:id="@+id/info"
diff --git a/main/res/layout/logs_item.xml b/main/res/layout/logs_item.xml
index 6ce20bb..b362d9e 100644
--- a/main/res/layout/logs_item.xml
+++ b/main/res/layout/logs_item.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="3dip"
- android:paddingTop="3dip" >
+ android:paddingTop="3dip"
+ tools:context=".ui.logs.LogsViewCreator$1" >
<TextView
android:id="@+id/author"
diff --git a/main/res/layout/logs_page.xml b/main/res/layout/logs_page.xml
index 11f7855..e168be5 100644
--- a/main/res/layout/logs_page.xml
+++ b/main/res/layout/logs_page.xml
@@ -12,6 +12,7 @@
android:headerDividersEnabled="false"
android:listSelector="?background_color"
android:scrollbarStyle="outsideOverlay"
+ tools:context=".ui.logs.LogsViewCreator"
tools:listitem="@layout/logs_item" >
</ListView> \ No newline at end of file
diff --git a/main/res/layout/logtrackable_activity.xml b/main/res/layout/logtrackable_activity.xml
index 2a901ea..66fa016 100644
--- a/main/res/layout/logtrackable_activity.xml
+++ b/main/res/layout/logtrackable_activity.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".LogTrackableActivity" >
<LinearLayout
android:layout_width="fill_parent"
@@ -14,6 +16,7 @@
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:baselineAligned="false"
android:orientation="horizontal" >
<Button
diff --git a/main/res/layout/main_activity.xml b/main/res/layout/main_activity.xml
index d2bd025..474565f 100644
--- a/main/res/layout/main_activity.xml
+++ b/main/res/layout/main_activity.xml
@@ -4,7 +4,8 @@
android:id="@+id/mainscreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layout_gravity="center" >
+ android:layout_gravity="center"
+ tools:context=".MainActivity" >
<fragment
android:id="@+id/status"
diff --git a/main/res/layout/main_activity_connectorstatus.xml b/main/res/layout/main_activity_connectorstatus.xml
index 33c4d79..6c334aa 100644
--- a/main/res/layout/main_activity_connectorstatus.xml
+++ b/main/res/layout/main_activity_connectorstatus.xml
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
style="@style/location_current"
- android:text="@string/init_login_popup_working" />
+ android:text="@string/init_login_popup_working"
+ tools:context=".MainActivity$1" />
diff --git a/main/res/layout/map_google.xml b/main/res/layout/map_google.xml
index 85f550a..85fee7a 100644
--- a/main/res/layout/map_google.xml
+++ b/main/res/layout/map_google.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
-
-
+ android:orientation="vertical"
+ tools:context=".maps.google.v1.GoogleMapProvider" >
<include layout="@layout/actionbar_maps" />
diff --git a/main/res/layout/map_mapsforge.xml b/main/res/layout/map_mapsforge.xml
index c44a3ee..a559545 100644
--- a/main/res/layout/map_mapsforge.xml
+++ b/main/res/layout/map_mapsforge.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".maps.mapsforge.MapsforgeMapProvider" >
<include layout="@layout/actionbar_maps" />
diff --git a/main/res/layout/map_mapsforge_old.xml b/main/res/layout/map_mapsforge_old.xml
deleted file mode 100644
index daa5f74..0000000
--- a/main/res/layout/map_mapsforge_old.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <include layout="@layout/actionbar_maps" />
-
- <include layout="@layout/filter_bar" />
-
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
-
- <TextView
- android:id="@+id/number"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="5dip"
- android:background="@drawable/icon_bcg"
- android:ellipsize="marquee"
- android:gravity="center_horizontal"
- android:lines="1"
- android:paddingLeft="5dip"
- android:paddingRight="5dip"
- android:scrollHorizontally="true"
- android:singleLine="true"
- android:textColor="@color/text_icon"
- android:textSize="12sp"
- android:visibility="gone" />
-
- <view
- android:id="@+id/mfmap_old"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- class="cgeo.geocaching.maps.mapsforge.v024.MapsforgeMapView024"
- android:clickable="true"
- android:enabled="true"
- android:keepScreenOn="true" />
- </RelativeLayout>
-
-</LinearLayout> \ No newline at end of file
diff --git a/main/res/layout/mapfile_item.xml b/main/res/layout/mapfile_item.xml
index c665894..dd17f69 100644
--- a/main/res/layout/mapfile_item.xml
+++ b/main/res/layout/mapfile_item.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mapfile_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -9,7 +10,8 @@
android:paddingBottom="7dip"
android:paddingLeft="5dip"
android:paddingRight="5dip"
- android:paddingTop="7dip" >
+ android:paddingTop="7dip"
+ tools:context=".ui.FileSelectionListAdapter" >
<TextView
android:id="@+id/mapfilepath"
diff --git a/main/res/layout/navigateanypoint_activity.xml b/main/res/layout/navigateanypoint_activity.xml
index 3305d56..caec2f4 100644
--- a/main/res/layout/navigateanypoint_activity.xml
+++ b/main/res/layout/navigateanypoint_activity.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".NavigateAnyPointActivity" >
<ListView
android:id="@+id/historyList"
diff --git a/main/res/layout/navigateanypoint_header.xml b/main/res/layout/navigateanypoint_header.xml
index caf2e48..a52f55e 100644
--- a/main/res/layout/navigateanypoint_header.xml
+++ b/main/res/layout/navigateanypoint_header.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:weightSum="1" >
+ android:weightSum="1"
+ tools:context=".NavigateAnyPointActivity" >
<RelativeLayout style="@style/separator_horizontal_layout" >
@@ -61,7 +63,9 @@
android:id="@+id/distanceUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:entries="@array/distance_units" />
+ android:entries="@array/distance_units"
+ tools:listitem="@android:layout/simple_spinner_item" />
+
</LinearLayout>
<RelativeLayout style="@style/separator_horizontal_layout" >
diff --git a/main/res/layout/popup.xml b/main/res/layout/popup.xml
index de94d18..436c7d8 100644
--- a/main/res/layout/popup.xml
+++ b/main/res/layout/popup.xml
@@ -5,7 +5,7 @@
android:layout_height="fill_parent"
android:background="?background_color_transparent"
android:orientation="vertical"
- tools:context=".CachePopup">
+ tools:context=".CachePopupFragment" >
<include layout="@layout/actionbar_popup" />
<ScrollView
diff --git a/main/res/layout/preference_info_icon.xml b/main/res/layout/preference_info_icon.xml
index 4de0a15..597e400 100644
--- a/main/res/layout/preference_info_icon.xml
+++ b/main/res/layout/preference_info_icon.xml
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:src="?attr/settings_info_icon" />
+ android:layout_height="match_parent"
+ android:src="?attr/settings_info_icon"
+ tools:context=".settings.InfoPreference" />
diff --git a/main/res/layout/recaptcha_dialog.xml b/main/res/layout/recaptcha_dialog.xml
index 66ad4ef..16e9bb8 100644
--- a/main/res/layout/recaptcha_dialog.xml
+++ b/main/res/layout/recaptcha_dialog.xml
@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".connector.gc.RecaptchaHandler" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:baselineAligned="false"
android:gravity="center_horizontal"
android:orientation="horizontal" >
@@ -27,7 +30,6 @@
android:layout_gravity="center_vertical"
android:scaleType="centerInside"
android:src="@drawable/ic_menu_refresh" />
-
</LinearLayout>
<EditText
diff --git a/main/res/layout/search_activity.xml b/main/res/layout/search_activity.xml
index 894c461..902c707 100644
--- a/main/res/layout/search_activity.xml
+++ b/main/res/layout/search_activity.xml
@@ -5,7 +5,8 @@
android:layout_height="fill_parent"
android:background="?background_color"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".SearchActivity" >
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/simple_dir_chooser.xml b/main/res/layout/simple_dir_chooser.xml
index 167b2ec..ca7c6c8 100644
--- a/main/res/layout/simple_dir_chooser.xml
+++ b/main/res/layout/simple_dir_chooser.xml
@@ -4,7 +4,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".files.SimpleDirChooser" >
<LinearLayout
android:id="@+id/headerLayout"
@@ -39,6 +40,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
+ android:baselineAligned="false"
android:orientation="horizontal"
android:paddingTop="10dip" >
diff --git a/main/res/layout/simple_dir_item.xml b/main/res/layout/simple_dir_item.xml
index e268943..2abce4c 100644
--- a/main/res/layout/simple_dir_item.xml
+++ b/main/res/layout/simple_dir_item.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ tools:context=".files.SimpleDirChooser" >
<CheckBox
android:id="@+id/CheckBox"
diff --git a/main/res/layout/simple_way_point.xml b/main/res/layout/simple_way_point.xml
index 88f76e7..333bb9d 100644
--- a/main/res/layout/simple_way_point.xml
+++ b/main/res/layout/simple_way_point.xml
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout1"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ tools:context=".NavigateAnyPointActivity$DestinationHistoryAdapter" >
<ImageView
android:id="@+id/imageView1"
diff --git a/main/res/layout/star_image.xml b/main/res/layout/star_image.xml
deleted file mode 100644
index 919fedb..0000000
--- a/main/res/layout/star_image.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="12dip"
- android:layout_height="12dip"
- android:layout_gravity="center"
- android:layout_margin="1dip"
- android:gravity="center"
- android:scaleType="fitXY"
- android:src="@drawable/star_off" />
diff --git a/main/res/layout/staticmaps_activity.xml b/main/res/layout/staticmaps_activity.xml
index c8806b4..3ca336e 100644
--- a/main/res/layout/staticmaps_activity.xml
+++ b/main/res/layout/staticmaps_activity.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".StaticMapsActivity" >
<LinearLayout
android:id="@+id/maps_list"
diff --git a/main/res/layout/staticmaps_activity_item.xml b/main/res/layout/staticmaps_activity_item.xml
index 6b76192..8600246 100644
--- a/main/res/layout/staticmaps_activity_item.xml
+++ b/main/res/layout/staticmaps_activity_item.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map_image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -7,4 +8,5 @@
android:layout_marginBottom="10dip"
android:gravity="center"
android:padding="3dip"
- android:scaleType="fitCenter" />
+ android:scaleType="fitCenter"
+ tools:context=".StaticMapsActivity" />
diff --git a/main/res/layout/status.xml b/main/res/layout/status.xml
index ef2a57a..76f9a8d 100644
--- a/main/res/layout/status.xml
+++ b/main/res/layout/status.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/status"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/helper_bcg"
- android:visibility="invisible" >
+ android:visibility="invisible"
+ tools:context=".StatusFragment" >
<ImageView
android:id="@+id/status_icon"
diff --git a/main/res/layout/template_preference_dialog.xml b/main/res/layout/template_preference_dialog.xml
index c5fc548..343cc5f 100644
--- a/main/res/layout/template_preference_dialog.xml
+++ b/main/res/layout/template_preference_dialog.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="8dp" >
+ android:padding="8dp"
+ tools:context=".settings.TemplateTextPreference" >
<EditText
android:id="@+id/signature_dialog_text"
diff --git a/main/res/layout/trackable_details_view.xml b/main/res/layout/trackable_details_view.xml
index 07f4e4e..e2c162e 100644
--- a/main/res/layout/trackable_details_view.xml
+++ b/main/res/layout/trackable_details_view.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:padding="4dip" >
+ android:padding="4dip"
+ tools:context=".TrackableActivity$DetailsViewCreator" >
<LinearLayout
android:layout_width="fill_parent"
diff --git a/main/res/layout/trackable_image.xml b/main/res/layout/trackable_image.xml
index 89955bc..8a55cb7 100644
--- a/main/res/layout/trackable_image.xml
+++ b/main/res/layout/trackable_image.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/trackable_image"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="3dip"
android:gravity="center"
- android:scaleType="center" />
+ android:scaleType="center"
+ tools:context=".TrackableActivity$DetailsViewCreator" />
diff --git a/main/res/layout/usefulapps_activity.xml b/main/res/layout/usefulapps_activity.xml
index 7abb212..8ecea23 100644
--- a/main/res/layout/usefulapps_activity.xml
+++ b/main/res/layout/usefulapps_activity.xml
@@ -4,7 +4,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".UsefulAppsActivity" >
<ListView
android:id="@+id/apps_list"
diff --git a/main/res/layout/usefulapps_item.xml b/main/res/layout/usefulapps_item.xml
index 70e7baf..1207ef7 100644
--- a/main/res/layout/usefulapps_item.xml
+++ b/main/res/layout/usefulapps_item.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/app_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="10dip"
android:descendantFocusability="blocksDescendants"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".UsefulAppsActivity" >
<RelativeLayout style="@style/separator_horizontal_layout" >
@@ -23,6 +25,7 @@
android:layout_marginBottom="5dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
+ android:baselineAligned="false"
android:orientation="horizontal" >
<ImageView
diff --git a/main/res/layout/waypoint_item.xml b/main/res/layout/waypoint_item.xml
index 4148dab..7b3c33a 100644
--- a/main/res/layout/waypoint_item.xml
+++ b/main/res/layout/waypoint_item.xml
@@ -8,7 +8,8 @@
android:descendantFocusability="blocksDescendants"
android:longClickable="true"
android:orientation="vertical"
- android:paddingTop="9dp" >
+ android:paddingTop="9dp"
+ tools:context=".CacheDetailActivity$WaypointsViewCreator$1" >
<RelativeLayout
android:layout_width="fill_parent"
@@ -97,4 +98,4 @@
style="@style/separator_horizontal"
android:layout_marginTop="9dp" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/main/res/layout/waypoint_popup.xml b/main/res/layout/waypoint_popup.xml
index 287fc3a..9a566ee 100644
--- a/main/res/layout/waypoint_popup.xml
+++ b/main/res/layout/waypoint_popup.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?background_color_transparent"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ tools:context=".WaypointPopupFragment" >
- <include layout="@layout/actionbar_popup" />
+ <include layout="@layout/actionbar_popup" />
<ScrollView
android:id="@+id/details_list_box"
diff --git a/main/res/menu/abstract_logging_activity.xml b/main/res/menu/abstract_logging_activity.xml
index aeb6720..9c91399 100644
--- a/main/res/menu/abstract_logging_activity.xml
+++ b/main/res/menu/abstract_logging_activity.xml
@@ -32,6 +32,11 @@
<menu /> <!-- filled dynamically -->
</item>
<item
+ android:id="@+id/menu_repeat_last"
+ android:title="@string/log_repeat"
+ app:showAsAction="ifRoom|withText">
+ </item>
+ <item
android:id="@+id/save"
android:icon="@drawable/ic_menu_save"
android:title="@string/log_save"
diff --git a/main/res/menu/cache_list_context.xml b/main/res/menu/cache_list_context.xml
index c086709..86fd6f6 100644
--- a/main/res/menu/cache_list_context.xml
+++ b/main/res/menu/cache_list_context.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_default_navigation"
@@ -21,37 +21,37 @@
<item
android:id="@+id/menu_log_visit_offline"
android:icon="@drawable/ic_menu_edit"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_menu_visit_offline">
+ android:title="@string/cache_menu_visit_offline"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_log_visit"
android:icon="@drawable/ic_menu_edit"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_menu_visit">
+ android:title="@string/cache_menu_visit"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_drop_cache"
- app:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_menu_delete"
- android:title="@string/cache_offline_drop">
+ android:title="@string/cache_offline_drop"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_move_to_list"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_menu_move_list">
+ android:title="@string/cache_menu_move_list"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_refresh"
- app:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_menu_refresh"
- android:title="@string/cache_menu_refresh">
+ android:title="@string/cache_menu_refresh"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_store_cache"
- app:showAsAction="ifRoom|withText"
android:icon="@drawable/ic_menu_save"
- android:title="@string/cache_offline_store">
+ android:title="@string/cache_offline_store"
+ app:showAsAction="ifRoom|withText">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/cache_list_options.xml b/main/res/menu/cache_list_options.xml
index 7c933c0..19a6882 100644
--- a/main/res/menu/cache_list_options.xml
+++ b/main/res/menu/cache_list_options.xml
@@ -53,12 +53,12 @@
android:visible="false">
</item>
<item
- android:id="@+id/submenu_cache_list_app"
+ android:id="@+id/menu_cache_list_app_provider"
+ android:actionProviderClass="cgeo.geocaching.apps.cachelist.ListNavigationSelectionActionProvider"
android:icon="@drawable/ic_menu_goto"
android:title="@string/caches_on_map"
- android:visible="false">
- <menu>
- </menu>
+ android:visible="false"
+ app:actionProviderClass="cgeo.geocaching.apps.cachelist.ListNavigationSelectionActionProvider">
</item>
<item
android:id="@+id/menu_create_list"
@@ -108,15 +108,18 @@
</item>
<item
android:id="@+id/menu_delete_events"
- android:title="@string/caches_delete_events">
+ android:title="@string/caches_delete_events"
+ android:visible="false">
</item>
<item
android:id="@+id/menu_clear_offline_logs"
- android:title="@string/caches_clear_offlinelogs">
+ android:title="@string/caches_clear_offlinelogs"
+ android:visible="false">
</item>
<item
android:id="@+id/menu_remove_from_history"
- android:title="@string/cache_clear_history">
+ android:title="@string/cache_clear_history"
+ android:visible="false">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/cache_options.xml b/main/res/menu/cache_options.xml
index 20ee9cd..f6ac51c 100644
--- a/main/res/menu/cache_options.xml
+++ b/main/res/menu/cache_options.xml
@@ -20,18 +20,21 @@
android:id="@+id/menu_log_visit_offline"
android:icon="@drawable/ic_menu_edit"
android:title="@string/cache_menu_visit_offline"
+ android:visible="false"
app:showAsAction="ifRoom">
</item>
<item
android:id="@+id/menu_log_visit"
android:icon="@drawable/ic_menu_edit"
android:title="@string/cache_menu_visit"
+ android:visible="false"
app:showAsAction="ifRoom">
</item>
<item
android:id="@+id/menu_calendar"
android:icon="@drawable/ic_menu_my_calendar"
android:title="@string/cache_menu_event"
+ android:visible="false"
app:showAsAction="ifRoom">
</item>
<item
@@ -68,11 +71,29 @@
app:showAsAction="ifRoom">
</item>
<item
+ android:id="@+id/menu_gcvote"
+ android:title="@string/cache_menu_vote"
+ android:visible="false"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
android:id="@+id/menu_share"
android:icon="@drawable/ic_menu_share"
android:title="@string/cache_menu_share"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider"
app:showAsAction="ifRoom">
</item>
-
+ <item
+ android:id="@+id/menu_checker"
+ android:title="@string/cache_menu_checker"
+ android:visible="false"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_ignore"
+ android:title="@string/cache_menu_ignore"
+ android:visible="false"
+ app:showAsAction="ifRoom">
+ </item>
+
</menu> \ No newline at end of file
diff --git a/main/res/menu/compass_activity_options.xml b/main/res/menu/compass_activity_options.xml
index 30861dd..742ebad 100644
--- a/main/res/menu/compass_activity_options.xml
+++ b/main/res/menu/compass_activity_options.xml
@@ -3,6 +3,12 @@
xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
+ android:id="@+id/menu_hint"
+ android:icon="@drawable/ic_menu_hint"
+ android:title="@string/cache_hint"
+ app:showAsAction="ifRoom|withText">
+ </item>
+ <item
android:id="@+id/menu_map"
android:icon="@drawable/ic_menu_mapmode"
android:title="@string/caches_on_map"
@@ -24,9 +30,18 @@
<item
android:id="@+id/menu_select_destination"
android:icon="@drawable/ic_menu_myplaces"
+ android:orderInCategory="999"
android:title="@string/destination_select"
+ android:visible="false"
app:showAsAction="ifRoom|withText">
- <menu /> <!-- filled dynamically -->
+ <menu>
+ <item
+ android:id="@+id/menu_compass_cache"
+ android:orderInCategory="999"
+ android:title="@string/cache"
+ android:visible="false">
+ </item>
+ </menu>
</item>
<item
android:id="@+id/menu_compass_sensor"
@@ -43,7 +58,7 @@
android:id="@+id/menu_compass_sensor_magnetic"
android:title="@string/use_compass">
</item>
- </group>
+ </group>
</menu>
</item>
diff --git a/main/res/menu/details_context.xml b/main/res/menu/details_context.xml
index 0bfb1a5..12afc22 100644
--- a/main/res/menu/details_context.xml
+++ b/main/res/menu/details_context.xml
@@ -10,8 +10,8 @@
</item>
<item
android:id="@+id/menu_cache_share_field"
- android:title="@string/cache_share_field"
android:icon="@drawable/ic_menu_share"
+ android:title="@string/cache_share_field"
app:showAsAction="ifRoom">
</item>
<item
diff --git a/main/res/menu/filter_options.xml b/main/res/menu/filter_options.xml
new file mode 100644
index 0000000..60733a6
--- /dev/null
+++ b/main/res/menu/filter_options.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
+
+ <item
+ android:id="@+id/menu_reset_filter"
+ android:icon="@drawable/ic_menu_delete"
+ android:title="@string/caches_filter_clear"
+ app:showAsAction="ifRoom|withText">
+ </item>
+
+</menu> \ No newline at end of file
diff --git a/main/res/menu/images_list_context.xml b/main/res/menu/images_list_context.xml
index 8d3869b..8f3d6b6 100644
--- a/main/res/menu/images_list_context.xml
+++ b/main/res/menu/images_list_context.xml
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/image_open_file"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_image_open_file">
+ android:title="@string/cache_image_open_file"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/image_open_browser"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_image_open_browser">
+ android:title="@string/cache_image_open_browser"
+ app:showAsAction="ifRoom|withText">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/logging_ui.xml b/main/res/menu/logging_ui.xml
index 921b350..7c41c6f 100644
--- a/main/res/menu/logging_ui.xml
+++ b/main/res/menu/logging_ui.xml
@@ -1,18 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_log_visit_offline"
android:icon="@drawable/ic_menu_edit"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_menu_visit_offline">
+ android:title="@string/cache_menu_visit_offline"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_log_visit"
android:icon="@drawable/ic_menu_edit"
- app:showAsAction="ifRoom|withText"
- android:title="@string/cache_menu_visit">
+ android:title="@string/cache_menu_visit"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/main_activity_options.xml b/main/res/menu/main_activity_options.xml
index b17080b..d556cdb 100644
--- a/main/res/menu/main_activity_options.xml
+++ b/main/res/menu/main_activity_options.xml
@@ -1,50 +1,51 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto" >
-
- <!-- TODO: use ic_action_search -->
- <item
- android:id="@+id/menu_gosearch"
- style="@style/action_bar_action"
- android:icon="@drawable/abc_ic_search"
- android:title="@string/search_bar_hint"
- app:actionViewClass="android.support.v7.widget.SearchView"
- app:showAsAction="collapseActionView|always"/>
- <item
- android:id="@+id/menu_history"
- android:icon="@drawable/ic_menu_recent_history"
- android:title="@string/menu_history"
- app:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/menu_pocket_queries"
- android:icon="@drawable/ic_menu_account_list"
- android:title="@string/menu_pocket_queries"
- app:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/ic_menu_preferences"
- android:title="@string/menu_settings"
- app:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/menu_helpers"
- android:icon="@drawable/ic_menu_shopping"
- android:title="@string/menu_helpers"
- app:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/menu_scan"
- android:icon="@drawable/ic_menu_barcode"
- android:title="@string/menu_scan_geo"
- app:showAsAction="ifRoom">
- </item>
- <item
- android:id="@+id/menu_about"
- android:icon="@drawable/ic_menu_info_details"
- android:title="@string/menu_about"
- app:showAsAction="ifRoom">
- </item>
-
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
+
+ <!-- TODO: use ic_action_search -->
+ <item
+ android:id="@+id/menu_gosearch"
+ style="@style/action_bar_action"
+ android:icon="@drawable/abc_ic_search"
+ android:title="@string/search_bar_hint"
+ app:actionViewClass="android.support.v7.widget.SearchView"
+ app:showAsAction="collapseActionView|always"/>
+ <item
+ android:id="@+id/menu_history"
+ android:icon="@drawable/ic_menu_recent_history"
+ android:title="@string/menu_history"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_pocket_queries"
+ android:icon="@drawable/ic_menu_account_list"
+ android:title="@string/menu_pocket_queries"
+ android:visible="false"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_menu_preferences"
+ android:title="@string/menu_settings"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_helpers"
+ android:icon="@drawable/ic_menu_shopping"
+ android:title="@string/menu_helpers"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_scan"
+ android:icon="@drawable/ic_menu_barcode"
+ android:title="@string/menu_scan_geo"
+ app:showAsAction="ifRoom">
+ </item>
+ <item
+ android:id="@+id/menu_about"
+ android:icon="@drawable/ic_menu_info_details"
+ android:title="@string/menu_about"
+ app:showAsAction="ifRoom">
+ </item>
+
</menu> \ No newline at end of file
diff --git a/main/res/menu/map_activity.xml b/main/res/menu/map_activity.xml
index 9559560..27e3840 100644
--- a/main/res/menu/map_activity.xml
+++ b/main/res/menu/map_activity.xml
@@ -26,6 +26,21 @@
android:icon="@drawable/ic_menu_refresh"
android:showAsAction="ifRoom|withText"
android:title="@string/map_live_disable"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
+ </item>
+ <item
+ android:id="@+id/menu_hint"
+ android:icon="@drawable/ic_menu_hint"
+ android:title="@string/cache_hint"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
+ </item>
+ <item
+ android:id="@+id/menu_compass"
+ android:icon="@drawable/ic_menu_compass"
+ android:title="@string/compass_title"
+ android:visible="false"
app:showAsAction="ifRoom|withText">
</item>
<item
@@ -70,12 +85,14 @@
android:icon="@drawable/ic_menu_preferences"
android:showAsAction="ifRoom|withText"
android:title="@string/map_theme_select"
+ android:visible="false"
app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/submenu_strategy"
android:icon="@drawable/ic_menu_preferences"
- android:title="@string/map_strategy">
+ android:title="@string/map_strategy"
+ android:visible="false">
<menu>
<group
android:id="@+id/menu_group_strategy"
diff --git a/main/res/menu/navigate_any_point_activity_options.xml b/main/res/menu/navigate_any_point_activity_options.xml
index d4e4b9e..be9f589 100644
--- a/main/res/menu/navigate_any_point_activity_options.xml
+++ b/main/res/menu/navigate_any_point_activity_options.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_default_navigation"
diff --git a/main/res/menu/search_activity_options.xml b/main/res/menu/search_activity_options.xml
index 300be94..ed84ebe 100644
--- a/main/res/menu/search_activity_options.xml
+++ b/main/res/menu/search_activity_options.xml
@@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_search_own_caches"
android:icon="@drawable/ic_menu_myplaces"
android:title="@string/search_own_caches"
- app:showAsAction="ifRoom|withText"
- >
+ app:showAsAction="ifRoom|withText">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/static_maps_activity_options.xml b/main/res/menu/static_maps_activity_options.xml
index fb98f54..fdd7800 100644
--- a/main/res/menu/static_maps_activity_options.xml
+++ b/main/res/menu/static_maps_activity_options.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_refresh"
android:icon="@drawable/ic_menu_refresh"
- app:showAsAction="ifRoom"
- android:title="@string/cache_offline_refresh">
+ android:title="@string/cache_offline_refresh"
+ app:showAsAction="ifRoom">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/trackable_activity.xml b/main/res/menu/trackable_activity.xml
index 5bcd706..4b952d5 100644
--- a/main/res/menu/trackable_activity.xml
+++ b/main/res/menu/trackable_activity.xml
@@ -1,18 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/menu_log_touch"
android:icon="@drawable/ic_menu_edit"
- app:showAsAction="ifRoom|withText"
- android:title="@string/trackable_log_touch">
+ android:title="@string/trackable_log_touch"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
</item>
<item
android:id="@+id/menu_browser_trackable"
android:icon="@drawable/ic_menu_info_details"
- app:showAsAction="ifRoom|withText"
- android:title="@string/trackable_browser_open">
+ android:title="@string/trackable_browser_open"
+ android:visible="false"
+ app:showAsAction="ifRoom|withText">
</item>
</menu> \ No newline at end of file
diff --git a/main/res/menu/waypoint_options.xml b/main/res/menu/waypoint_options.xml
index 7df48f8..93333ed 100644
--- a/main/res/menu/waypoint_options.xml
+++ b/main/res/menu/waypoint_options.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
+
<item
android:id="@+id/menu_waypoint_reset_cache_coords"
android:title="@string/waypoint_reset_cache_coords">
@@ -30,4 +30,5 @@
android:id="@+id/menu_waypoint_caches_around"
android:title="@string/cache_menu_around">
</item>
-</menu>
+
+</menu> \ No newline at end of file
diff --git a/main/res/values-ca/strings.xml b/main/res/values-ca/strings.xml
index e2d2c8f..934164c 100644
--- a/main/res/values-ca/strings.xml
+++ b/main/res/values-ca/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Visitat</string>
<string name="log_tb_drop">Deixat</string>
<string name="log_tb_changeall">Canvia-ho tot</string>
- <string name="log_save">Desa</string>
+ <string name="log_save">Guarda-ho fora de línia</string>
<string name="log_saving">S\'està enviant el registre…</string>
<string name="log_saving_and_uploading">S\'està enviant el registre i pujant la imatge…</string>
<string name="log_clear">Esborra</string>
<string name="log_post_not_possible">S\'està carregant la pàgina del registre…</string>
+ <string name="log_date_future_not_allowed">No estan permesos els registres amb data futura.</string>
<string name="log_add">Afegeix</string>
+ <string name="log_repeat">Repeteix l\'últim registre</string>
<string name="log_no_rating">Sense puntuació</string>
<string name="log_stars_1_description">Pobre</string>
<string name="log_stars_15_description">Bastant pobre</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Contrasenya d\'accés:</string>
<string name="log_hint_log_password">Introduïu la contrasenya d\'accés</string>
<string name="log_oc_team_comment">Comentari de l\'equip OC</string>
+ <string name="log_your_saved_log">El registre que heu desat</string>
<string-array name="log_image_scales">
<item>Sense escala</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">No hi ha desada cap informació d\'accés</string>
<string name="err_login_failed_toast">El c:geo no pot iniciar la sessió. El c:geo treballa fora línia amb els catxés desats. Comproveu la configuració de la connexió o activeu la connexió a Internet.</string>
<string name="err_unknown">Error desconegut</string>
+ <string name="err_unknown_address">c:geo no ha pogut assignar aquesta adreça a una ubicació existent</string>
<string name="err_comm">S\'ha produït un error de comunicació desconegut</string>
<string name="err_missing_auth">No s\'ha definit nom d\'usuari i/o contrasenya.</string>
<string name="err_wrong">La informació d\'accés és incorrecta</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">S\'ha produït un error a l\'adquirir una imatge.</string>
<string name="err_tb_display">El c:geo no pot mostrar el traçable que volíeu. És realment un traçable?</string>
<string name="err_tb_details_open">El c:geo no pot obrir els detalls del traçable.</string>
- <string name="err_tb_forgot_saw">El c:geo no recorda quin traçable heu vist.</string>
<string name="err_tb_find">El c:geo no pot trobar el traçable</string>
<string name="err_tb_find_that">El c:geo no pot trobar aquest traçable.</string>
<string name="err_waypoint_cache_unknown">El c:geo no sap a quin catxé voleu afegir la fita.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">El c:geo no pot reconèixer on ets.</string>
<string name="err_point_no_position_given_title">Cal informació</string>
<string name="err_point_no_position_given">Ompliu la latitud i la longitud o la distància i la direcció. També podeu omplir els quatre camps.</string>
- <string name="err_point_curr_position_unavailable">El c:geo encara no té les coordenades actuals. Espereu una estona…</string>
<string name="err_point_bear_and_dist_title">Necessiteu ajuda?</string>
<string name="err_point_bear_and_dist">Ompliu el rumb i la distància. El rumb son angles del 0º al 360º respecte al Nord. La distància no necessita unitats.</string>
<string name="err_log_load_data">El c:geo no pot carregar les dades necessàries per registrar la visita.</string>
<string name="err_log_load_data_again">El c:geo no pot carregar les dades necessàries per registrar la visita. Torneu a intentar-ho.</string>
<string name="err_log_load_data_still">El c:geo encara està carregant les dades necessàries per enviar el registre. Si us plau, espereu una estona més.</string>
- <string name="err_log_post_failed">Sembla que el vostre registre no s\'ha publicat. Comproveu-ho a geocaching.com.</string>
- <string name="err_log_post_failed_ec">Sembla que el registre no s\'ha publicat. Comproveu-ho a Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Sembla que la imatge de registre no ha estat guardada. Comproveu-ho a Geocaching.com.</string>
+ <string name="err_log_post_failed">El registre no s\'ha publicat. Comproveu la memòria del lloc web d\'origen.</string>
+ <string name="err_logimage_post_failed">La imatge de registre no s\'ha pujat. Comproveu la memòria del lloc web d\'origen.</string>
<string name="err_search_address_forgot">El c:geo ha oblidat l\'adreça que intentaves trobar.</string>
<string name="err_parse_lat">El c:geo no pot calcular la latitud.</string>
<string name="err_parse_lon">El c:geo no pot calcular la longitud.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Xarxa</string>
<string name="loc_fused">Combinat</string>
<string name="loc_low_power">Bateria baixa</string>
+ <string name="loc_home">Coordenades de casa</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Intentant ubicar</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Propers</string>
<string name="advanced_search_button">Cerca</string>
<string name="stored_caches_button">Desats</string>
- <string name="any_button">Vés a…</string>
+ <string name="any_button">Vés a</string>
<string name="unknown_scan">No s\'ha trobat cap geocodi en el resultat de l\'exploració.</string>
<string name="caches_no_cache">Aquí no hi ha catxés</string>
<string name="caches_more_caches">Carrega més catxés</string>
@@ -263,15 +265,22 @@
<string name="caches_sort_finds">Trobats</string>
<string name="caches_sort_state">Estat</string>
<string name="caches_sort_storage">Data d\'emmagatzemat al dispositiu</string>
+ <string name="caches_sort_eventdate">Data de la trobada</string>
<string name="caches_select_mode">Mode seleccionar</string>
<string name="caches_select_mode_exit">Surt del mode seleccionar</string>
<string name="caches_select_invert">Inverteix la selecció</string>
<string name="caches_nearby">Propers</string>
<string name="caches_manage">Administra</string>
<string name="caches_remove_all">Suprimeix-los tots</string>
- <string name="caches_remove_all_confirm">Voleu suprimir tots els %s catxés de la llista actual?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Voleu suprimir aquest catxé de la llista actual?</item>
+ <item quantity="other">Voleu suprimir tots els %d catxés de la llista actual?</item>
+ </plurals>
<string name="caches_remove_selected">Suprimeix els seleccionats</string>
- <string name="caches_remove_selected_confirm">Voleu suprimir del dispositiu els %s catxés seleccionats?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Voleu suprimir aquest catxé del dispositiu?</item>
+ <item quantity="other">Voleu suprimir els %d catxés seleccionats del dispositiu?</item>
+ </plurals>
<string name="caches_remove_progress">S\'estan eliminant els catxés</string>
<string name="caches_delete_events">Elimina trobades passades</string>
<string name="caches_refresh_selected">Actualitza els seleccionats</string>
@@ -291,13 +300,18 @@
<string name="caches_filter_track">Amb traçables</string>
<string name="caches_filter_clear">Neteja els filtres</string>
<string name="caches_filter_modified">Amb les coordenades modificades</string>
+ <string name="caches_filter_offline_log">Amb registre fora de línia</string>
<string name="caches_filter_origin">Origen</string>
<string name="caches_filter_distance">Distància</string>
<string name="caches_filter_personal_note">Amb una nota personal</string>
<string name="caches_filter_popularity">Preferits</string>
<string name="caches_filter_popularity_ratio">Preferits [%]</string>
+ <string name="caches_filter_personal_data">Amb dades personals</string>
+ <string name="caches_filter_rating">Amb puntuació</string>
+ <string name="caches_filter_own_rating">Amb puntuació pròpia</string>
<string name="caches_removing_from_history">S\'està eliminant de l\'historial…</string>
<string name="caches_clear_offlinelogs">Neteja els registres fora de línea</string>
+ <string name="caches_clear_offlinelogs_message">Voleu esborrar els registres fora de línia?</string>
<string name="caches_clear_offlinelogs_progress">S\'estan netejant els registres fora línia</string>
<string name="list_menu_create">Crea una llista nova</string>
<string name="list_menu_drop">Elimina la llista actual</string>
@@ -320,13 +334,17 @@
<string name="list_not_available">La llista ja no està disponible, s\'està canviant a la llista estàndard</string>
<string name="about_version">Versió</string>
<string name="about_changelog">Historial de canvis</string>
+ <string name="about_system">Sistema</string>
<string name="about_donate">Donatiu</string>
<string name="about_donation_more">Donatiu\nal desenvolupament</string>
<string name="about_contributors">Col·laboradors</string>
<string name="about_license">Llicència</string>
<string name="about_apache_license"><a href="">Llicència Apache, versió 2.0</a></string>
<string name="about_help">Ajuda</string>
+ <string name="about_system_include">Si us plau incloure la següent informació de sistema quan envieu un informe d\'error o demanar més informació sobre c:geo:</string>
+ <string name="changelog_github">Llista de tots els canvis</string>
<string name="settings_title_services">Serveis</string>
+ <string name="settings_summary_services">Configureu la informació del compte d\'usuari i l\'accés a serveis opcionals.</string>
<string name="settings_title_appearance">Aparença</string>
<string name="settings_title_cachedetails">Detalls del catxé</string>
<string name="settings_title_offlinedata">Dades fora de línia</string>
@@ -373,6 +391,9 @@
<string name="settings_activate_oc_uk">Activa</string>
<string name="init_oc_uk_description">Autoritza al c:geo a opencaching.org.uk per buscar catxés i accedir/filtrar els teus catxés trobats.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Per poder puntuar un catxé, cal seguir les instruccions a GCVote.com i introduir aquí la contrasenya del GCVote.</string>
+ <string name="err_gcvote_send_rating">Hi ha un error al enviar la puntuació, comproveu la contrasenya de GCVote a les opcions o deixeu-ho buit.</string>
+ <string name="gcvote_sent">Votació enviada correctament</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activa</string>
<string name="init_username">Nom d\'usuari</string>
@@ -443,6 +464,8 @@
<string name="init_backup_success">La base de dades del c:geo s\'ha copiat amb èxit a:</string>
<string name="init_backup_failed">Ha fallat la còpia de seguretat de la base de dades de c:geo.</string>
<string name="init_backup_unnecessary">La base de dades està buida, no cal fer una còpia de seguretat.</string>
+ <string name="backup_confirm_overwrite">Voleu sobreescriure la còpia de seguretat existent de %s?</string>
+ <string name="restore_confirm_overwrite">Voleu sobreescriure %s al dispositiu amb la còpia de seguretat?</string>
<string name="init_restore_success">La restauració s\'ha completat.</string>
<string name="init_restore_failed">Ha fallat la restauració.</string>
<string name="init_restore_running">S\'està restaurant la base de dades dels catxés…</string>
@@ -604,6 +627,7 @@
</plurals>
<string name="cache_waypoints_add">Afegeix una fita</string>
<string name="cache_hint">Pista</string>
+ <string name="cache_hint_not_available">No hi ha cap pista disponible</string>
<string name="cache_logs">Llibre de registre</string>
<string name="cache_logs_friends_and_own">Registres dels amics o propis</string>
<string name="cache_dialog_loading_details">S\'està carregant els detalls del catxé…</string>
@@ -643,9 +667,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Obre al navegador</string>
<string name="cache_menu_visit">Registra visita</string>
- <string name="cache_menu_visit_offline">Registra visita fora de línia</string>
+ <string name="cache_menu_visit_offline">Registra fora de línia amb un sol clic</string>
<string name="cache_menu_spoilers">Imatges d\'ajuda</string>
<string name="cache_menu_around">Catxés propers</string>
+ <string name="around">Al voltant de %s</string>
<string name="cache_menu_event">Afegeix al calendari</string>
<string name="cache_menu_details">Detalls</string>
<string name="cache_menu_refresh">Actualitza</string>
@@ -655,6 +680,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Vota</string>
+ <string name="cache_menu_checker">Obre el Geochecker</string>
+ <string name="cache_menu_ignore">Ignora el catxé</string>
<string name="cache_status">Estat</string>
<string name="cache_status_offline_log">Registre desat</string>
<string name="cache_status_found">Trobat</string>
@@ -740,6 +768,7 @@
<string name="waypoint_note">Nota</string>
<string name="waypoint_visited">Visitat</string>
<string name="waypoint_save">Desa</string>
+ <string name="waypoint_cancel_edit">Cancel•la</string>
<string name="waypoint_loading">S\'està carregant la fita…</string>
<string name="waypoint_do_not_touch_cache_coordinates">No s\'ha fet cap canvi a les coordenades del catxé</string>
<string name="waypoint_set_as_cache_coords">Estableix com a coordenades del catxé al c:geo</string>
@@ -764,6 +793,8 @@
<string name="search_clear_history">Esborra l\'historial</string>
<string name="search_history_cleared">S\'ha esborrat l\'historial</string>
<string name="waypoint_coordinate_formats_plain">Senzill</string>
+ <string name="from_clipboard">Des del porta-retalls</string>
+ <string name="copy_to_clipboard">Copia al porta-retalls</string>
<string name="visit_tweet">Envia aquest \"trobat\" al Twitter</string>
<string name="map_map">Mapa</string>
<string name="map_live">Mapa en viu</string>
@@ -868,7 +899,7 @@
<string name="helper_contacts_description">Us permet obrir un contacte (de la llibreta de contactes) directament des d\'una entrada del registre, així podeu demanar ajuda als amics més fàcilment.</string>
<string name="helper_sendtocgeo_description">Send to c:geo és una extensió del navegador <strong>per al vostre ordinador</strong>. Quan navegueu per geocaching.com podreu enviar catxés des del navegador directament al vostre telèfon amb un clic de botó.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Aplicació simple que mostra mapes en línia i us permet descarregar-los directament pel mode fora de línia (només mapes raster). També suporta la gravació de rutes, manipulació de punts d\'interès i moltes altres funcions útils.</string>
+ <string name="helper_locus_description">Aplicació de navegació a l\'aire lliure per al vostre telèfon o tauleta. Podeu veure mapes topogràfics fora de línia, seguir una ruta, trobar geocatxés, utilitzar una guia de veu i molt més.</string>
<string name="helper_gpsstatus_title">Estat del GPS</string>
<string name="helper_gpsstatus_description">Podeu utilitzar el radar en aquesta aplicació conjuntament amb el c:geo. També ofereix moltes altres informacions relacionades amb el GPS.</string>
<string name="helper_bluetoothgps_title">GPS Bluetooth</string>
@@ -1120,13 +1151,15 @@
<string name="attribute_offset_cache_no">No és un catxé offset</string>
<string name="quote">Per fer el geocatxing més fàcil, per fer els usuaris més dropos.</string>
<string name="powered_by">Carnero</string>
- <string name="support">Suport: <a href="">support@cgeo.org</a></string>
- <string name="website">Lloc web: <a href=""> cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">Pàgina del c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">El c:geo a Google Play</a></string>
+ <string name="support_title">Ajut</string>
+ <string name="website_title">Lloc web</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">Pàgina del c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href=""> c:geo a Google Play</a></string>
<string name="about_twitter">Voleu que <b>el c:geo</b> publiqui un nou estatus al Twitter cada vegada que registreu un catxé?</string>
- <string name="faq">PMF: <a href=""> faq.cgeo.org</a></string>
+ <string name="faq_title">Preguntes freqüents</string>
<string name="status_new_release" tools:ignore="UnusedResources">Nova versió disponible.\nCliqueu per instal·lar-la.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nova versió nightly build disponible.\nCliqueu per instal·lar-la.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Nova versió candidate disponible.\nCliqueu per instal·lar-la.</string>
@@ -1171,7 +1204,7 @@
<item quantity="one">%s preferit</item>
<item quantity="other">%s preferits</item>
</plurals>
- <string name="percent_favorite_points">% \ preferits</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% preferits</string>
<string name="cgeo_shortcut">Drecera del c:geo</string>
<string name="create_shortcut">Crea una drecera</string>
<string name="send">Envia</string>
@@ -1181,6 +1214,8 @@
<string name="showcase_main_text">Ara el c:geo posa elements del menú a la barra de títol al igual que altres aplicacions modernes. Alguns elements s\'amaguen darrere el símbol de punts. Premeu el botó de forma llarga per veure la seva descripció.</string>
<string name="showcase_cachelist_title">Llista de canvis</string>
<string name="showcase_cachelist_text">Es pot canviar entre les diferents llistes fent un clic al nom de la llista actual.</string>
+ <string name="showcase_compass_hint_title">Mostrar la pista</string>
+ <string name="showcase_compass_hint_text">Aquest element de menú nou podria donar una idea on trobar l\'amagatall - li mostra la pista, si està disponible.</string>
<string name="confirm_log_title">Tipus de registre poc habitual</string>
<string name="confirm_log_message">Voleu registrar \'%s\'. N\'esteu segurs?</string>
</resources>
diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml
index 9ab2d11..e677227 100644
--- a/main/res/values-cs/strings.xml
+++ b/main/res/values-cs/strings.xml
@@ -8,14 +8,14 @@
<string name="about">O aplikaci</string>
<string name="latitude">Zeměpisná šířka</string>
<string name="longitude">Zeměpisná délka</string>
- <string name="settings_titlebar">c:geo Nastavení</string>
+ <string name="settings_titlebar">Nastavení c:geo</string>
<string name="all_types">Všechny typy keší</string>
<string name="traditional">TradiÄní keÅ¡</string>
<string name="multi">Multi keš</string>
<string name="mystery">Mystery keš</string>
- <string name="letterbox">Dopisní schránka</string>
- <string name="event">Keš události</string>
- <string name="mega">Keš Mega-události</string>
+ <string name="letterbox">Letterbox keš</string>
+ <string name="event">Událost</string>
+ <string name="mega">Mega-událost</string>
<string name="giga">Giga event</string>
<string name="earth">Earthcache</string>
<string name="cito">Událost Cache In Trash Out</string>
@@ -73,12 +73,14 @@
<string name="log_tb_visit">Navštíveno</string>
<string name="log_tb_drop">Nechat zde</string>
<string name="log_tb_changeall">Změnit vše</string>
- <string name="log_save">Uložit</string>
+ <string name="log_save">Uložit offline</string>
<string name="log_saving">Odesílání Logu…</string>
<string name="log_saving_and_uploading">Odesílání Logu a nahrávání obrázku…</string>
<string name="log_clear">VyÄistit</string>
<string name="log_post_not_possible">NaÄítání stránky s Logovacím formulářem…</string>
+ <string name="log_date_future_not_allowed">Log s nadcházejícím datem není povolen.</string>
<string name="log_add">Přidat</string>
+ <string name="log_repeat">Opakovat poslední log</string>
<string name="log_no_rating">Bez hodnocení</string>
<string name="log_stars_1_description">Slabá</string>
<string name="log_stars_15_description">Docela slabá</string>
@@ -106,6 +108,7 @@
<string name="log_password_title">Logovací heslo:</string>
<string name="log_hint_log_password">Zadej své logovací heslo</string>
<string name="log_oc_team_comment">Komentář týmu OC</string>
+ <string name="log_your_saved_log">Tvé uložené logy</string>
<string-array name="log_image_scales">
<item>Bez měřítka</item>
<item>512 px</item>
@@ -123,6 +126,7 @@
<string name="err_login">Nejsou uloženy žádné přihlašovací údaje</string>
<string name="err_login_failed_toast">Nelze se přihlásit. c:geo bude pracovat Offline s uloženými informacemi. Zkontroluj nastavení přihlašování a připojení k Internetu.</string>
<string name="err_unknown">Neznámá chyba</string>
+ <string name="err_unknown_address">c:geo nedokázal tuto adresu najít na mapě</string>
<string name="err_comm">Neznámá komunikaÄní chyba</string>
<string name="err_missing_auth">Nenastaveno žádné přihlašovací jméno/heslo.</string>
<string name="err_wrong">Chybné přihlašovací údaje</string>
@@ -157,7 +161,6 @@
<string name="err_acquire_image_failed">Získání obrázku selhalo.</string>
<string name="err_tb_display">c:geo nemůže zobrazit sledovatelný předmět. Je to opravdu sledovatelný předmět?</string>
<string name="err_tb_details_open">c:geo nemůže otevřít podrobnosti ke sledovatelnému předmětu.</string>
- <string name="err_tb_forgot_saw">c:geo zapomělo, který sledovatelný předmět jsi prohlížel/a.</string>
<string name="err_tb_find">c:geo nemůže najít sledovatelný předmět.</string>
<string name="err_tb_find_that">c:geo nemůže najít tento sledovatelný předmět.</string>
<string name="err_waypoint_cache_unknown">c:geo neví k jaké keši chceš přidat bod trasy.</string>
@@ -165,15 +168,13 @@
<string name="err_point_unknown_position">c:geo nedokáže zjistit tvou polohu.</string>
<string name="err_point_no_position_given_title">Popis je vyžadován</string>
<string name="err_point_no_position_given">Vyplň alespoň zemÄ›pisnou šířku a délku nebo vzdálenost a smÄ›r. MůžeÅ¡ také vyplnit vÅ¡echna ÄtyÅ™i pole.</string>
- <string name="err_point_curr_position_unavailable">c:geo stále nemá aktuální souÅ™adnice. Prosím, chvilku poÄkej…</string>
<string name="err_point_bear_and_dist_title">Potřebuješ poradit?</string>
<string name="err_point_bear_and_dist">Vyplň směr i vzdálenost. Směr je úhel 0 až 360 stupňů vzhledem k severu. Vzdálenost s nebo bez jednotek.</string>
<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_post_failed">Zdá se, že tvůj Log nebyl odeslán. Prosím, zkontroluj to na Geocaching.com.</string>
- <string name="err_log_post_failed_ec">Zdá se, že tvůj Log nebyl odeslán. Prosím, zkontroluj to na Extremcaching.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_log_post_failed">Zdá se, že tvůj log nebyl správně zveřejněn. Prosím, zkontroluj ho přímo na webové stránce keše.</string>
+ <string name="err_logimage_post_failed">Zdá se, že obrázek u logu nebyl správně odeslán. Prosím, zkontroluj to přímo na webové stránce keše.</string>
<string name="err_search_address_forgot">c:geo zapomnělo hledanou adresu.</string>
<string name="err_parse_lat">c:geo nemůže dopoÄítat zemÄ›pisnou šířku.</string>
<string name="err_parse_lon">c:geo nemůže dopoÄítat zemÄ›pisnou délku.</string>
@@ -210,13 +211,14 @@
<string name="loc_net">Síť</string>
<string name="loc_fused">Kombinovaný</string>
<string name="loc_low_power">Nízká spotřeba</string>
+ <string name="loc_home">Souřadnice domova</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Zjišťování pozice</string>
<string name="loc_no_addr">Neznámá adresa</string>
<string name="loc_gps_disabled">GPS zakázáno</string>
<string name="menu_centerposition">Vycentrovat na mou polohu</string>
- <string name="menu_about">O programu</string>
+ <string name="menu_about">O aplikaci</string>
<string name="menu_helpers">Pomocné programy</string>
<string name="menu_settings">Nastavení</string>
<string name="menu_history">Historie</string>
@@ -228,7 +230,7 @@
<string name="caches_nearby_button">Nejbližší</string>
<string name="advanced_search_button">Hledání</string>
<string name="stored_caches_button">Uložené</string>
- <string name="any_button">Cíl</string>
+ <string name="any_button">Přejít</string>
<string name="unknown_scan">Ve výsledku skenu nenalezen žádný geokód.</string>
<string name="caches_no_cache">Žádná keš</string>
<string name="caches_more_caches">NaÄíst další keÅ¡e</string>
@@ -240,7 +242,7 @@
<plurals name="caches_eta_mins">
<item quantity="one">%d minuta</item>
<item quantity="few">%d minuty</item>
- <item quantity="other">%d minuty</item>
+ <item quantity="other">%d minut</item>
</plurals>
<string name="caches_store_offline">Uložit pro offline</string>
<string name="caches_store_selected">Uložit vybrané</string>
@@ -263,15 +265,24 @@
<string name="caches_sort_finds">PoÄtu nálezů</string>
<string name="caches_sort_state">Stavu</string>
<string name="caches_sort_storage">Data uložení do zařízení</string>
+ <string name="caches_sort_eventdate">Datum události</string>
<string name="caches_select_mode">Mód výběru</string>
<string name="caches_select_mode_exit">Opustit mód výběru</string>
<string name="caches_select_invert">Invertovat výběr</string>
<string name="caches_nearby">Blízké</string>
<string name="caches_manage">Správa</string>
<string name="caches_remove_all">Odstranit vše</string>
- <string name="caches_remove_all_confirm">Opravdu chceš smazat všechny keše (%s) z tohoto seznamu?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Opravdu chceš smazat tuto keš z aktuálního seznamu?</item>
+ <item quantity="few">Opravdu chceš smazat všechny keše (%d) ze seznamu?</item>
+ <item quantity="other">Opravdu chceš smazat všechny keše (%d) ze seznamu?</item>
+ </plurals>
<string name="caches_remove_selected">Odstranit vybrané</string>
- <string name="caches_remove_selected_confirm">Opravdu chceš smazat vybrané keše (%s) z přístroje?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Opravdu chceš tuto keš odstranit z tvého zařízení?</item>
+ <item quantity="few">Opravdu chceš odstranit vybrané keše (%d) z tvého zařízení?</item>
+ <item quantity="other">Opravdu chceš odstranit vybrané keše (%d) z tvého zařízení?</item>
+ </plurals>
<string name="caches_remove_progress">Odstraňování keší</string>
<string name="caches_delete_events">Vymazat staré události</string>
<string name="caches_refresh_selected">Aktualizovat vybrané</string>
@@ -291,13 +302,18 @@
<string name="caches_filter_track">Se sledovatelnými předměty</string>
<string name="caches_filter_clear">Vymazat filtry</string>
<string name="caches_filter_modified">S upravenými souřadnicemi</string>
+ <string name="caches_filter_offline_log">S offline logy</string>
<string name="caches_filter_origin">Původ keše</string>
<string name="caches_filter_distance">Vzdálenost</string>
<string name="caches_filter_personal_note">S osobní poznámkou</string>
<string name="caches_filter_popularity">Oblíbené</string>
<string name="caches_filter_popularity_ratio">Oblíbené [%]</string>
+ <string name="caches_filter_personal_data">S osobními údaji</string>
+ <string name="caches_filter_rating">S hodnocením</string>
+ <string name="caches_filter_own_rating">S vlastním hodnocením</string>
<string name="caches_removing_from_history">Čištění Historie…</string>
<string name="caches_clear_offlinelogs">Smazat offline Logy</string>
+ <string name="caches_clear_offlinelogs_message">Opravdu chceš vymazat offline logy?</string>
<string name="caches_clear_offlinelogs_progress">Mazání offline logů</string>
<string name="list_menu_create">Vytvořit nový seznam</string>
<string name="list_menu_drop">Smazat aktuální seznam</string>
@@ -311,7 +327,7 @@
<string name="list_dialog_create_ok">Nový seznam byl vytvořen</string>
<string name="list_dialog_create_err">c:geo nedokázalo vytvořit nový seznam</string>
<string name="list_dialog_remove_title">Odstranit seznam</string>
- <string name="list_dialog_remove_description">Chceš odstranit aktuální seznam keší? Všechny zbývající keše budou přesunuty do seznamu \"Uložené\".</string>
+ <string name="list_dialog_remove_description">Chceš odstranit aktuální seznam keší? Všechny zbývající keše budou přesunuty do seznamu „Uložené“.</string>
<string name="list_dialog_remove">Odstranit</string>
<string name="list_dialog_remove_ok">Seznam byl odstraněn</string>
<string name="list_dialog_remove_err">c:geo nedokázalo odstranit aktuální seznam</string>
@@ -320,13 +336,17 @@
<string name="list_not_available">Seznam již není dostupný, přepínání na výchozí seznam</string>
<string name="about_version">Verze</string>
<string name="about_changelog">Změny</string>
+ <string name="about_system">Systém</string>
<string name="about_donate">Podpora vývoje</string>
<string name="about_donation_more">Podpořit\nvývoj</string>
<string name="about_contributors">Přispívající</string>
<string name="about_license">Licence</string>
<string name="about_apache_license"><a href=""> licence Apache, verze 2.0</a></string>
<string name="about_help">Nápověda</string>
+ <string name="about_system_include">PÅ™i odesílání hlášení o chybÄ› nebo žádosti o další informace uveÄte prosím následující systémové informace:</string>
+ <string name="changelog_github">Seznam všech změn</string>
<string name="settings_title_services">Služby</string>
+ <string name="settings_summary_services">Nastavení uživatelského úÄtu a přístupu k volitelným službám.</string>
<string name="settings_title_appearance">Vzhled</string>
<string name="settings_title_cachedetails">Detaily keše</string>
<string name="settings_title_offlinedata">Offline zdroje</string>
@@ -374,6 +394,9 @@
<string name="settings_activate_oc_uk">Aktivovat</string>
<string name="init_oc_uk_description">Autorizovat c:geo pro hledání keší a přístup/filtrování tvých nalezených keší služby opencaching.org.uk.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Pokud chceš hodnotit keše, je třeba postupovat dle pokynů na GCVote.com a zadat sem své heslo.</string>
+ <string name="err_gcvote_send_rating">Chyba při odesílání hodnocení, zkontroluj GCVote heslo v nastavení nebo ho nech prázdné.</string>
+ <string name="gcvote_sent">Hlas úspěšně odeslán</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Povolit</string>
<string name="init_username">Uživatelské jméno</string>
@@ -444,6 +467,8 @@
<string name="init_backup_success">Databáze c:geo byla úspěšně zkopírována do souboru</string>
<string name="init_backup_failed">Zálohování databáze c:geo selhalo.</string>
<string name="init_backup_unnecessary">Databáze je prázdná, takže není třeba zálohovat.</string>
+ <string name="backup_confirm_overwrite">Opravdu chceš přesat existující zálohu z %s?</string>
+ <string name="restore_confirm_overwrite">Chceš přepsat %s na svém zařízení zálohou?</string>
<string name="init_restore_success">Obnova dokonÄena.</string>
<string name="init_restore_failed">Obnova selhala.</string>
<string name="init_restore_running">Obnovování databáze keší…</string>
@@ -451,7 +476,7 @@
<string name="init_backup_last">Dostupná záloha z</string>
<string name="init_backup_last_no">Nenalezen žádný soubor se zálohou.</string>
<string name="settings_info_offline_maps_title">Info o Offline mapách</string>
- <string name="settings_info_offline_maps">c:geo podporuje používání offline map. Mapy si můžeš stáhnout z Mapsforge a nebo si vytvořit vlastní z dat Open Street Map (OSM). Aby bylo možné offline mapy používat, musíš nejprve zvolit místo jejich uložení.</string>
+ <string name="settings_info_offline_maps">c:geo podporuje používání offline mapových podkladů, které si můžeš stáhnout z Mapsforge a nebo si vytvořit vlastní z dat Open Street Map (OSM). Aby bylo možné offline mapy používat, musíš nejprve zvolit místo jejich umístění (volba „Složka s offline mapami“).</string>
<string name="settings_info_themes_title">Info o stylech mapy</string>
<string name="settings_info_themes">c:geo podporuje vlastní styly pro offline mapy. Ty mohou být použity pro zmÄ›nu barevného stylu mapy (napÅ™. noÄní mapa), pro zvýraznÄ›ní důležitých objektů (jako jsou napÅ™. cykloztezky) nebo pro urÄení šířky Äar.</string>
<string name="init_mapsource_select">Vyber mapový zdroj</string>
@@ -533,7 +558,7 @@
<string name="init_sendToCgeo">Poslat do c:geo</string>
<string name="settings_info_send2cgeo_title">Info o funkci send2c:geo</string>
<string name="init_sendToCgeo_name">Název tvého zařízení</string>
- <string name="init_sendToCgeo_description">Funkce <b>Send2c:geo</b> umožňuje stahovat keÅ¡e přímo ze stránky Geocaching.com pomocí speciálního doplňku pro webové prholížeÄe. PÅ™ed registrací zkoukni <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Pokud chceÅ¡ používat funkci send2c:geo, musíš se zaregistrovat. c:geo může samozÅ™ejmÄ› pracovat normálnÄ› i bez registrace této funkce.</string>
+ <string name="init_sendToCgeo_description">Funkce <b>Send2c:geo</b> umožňuje stahovat keÅ¡e přímo ze stránky Geocaching.com pomocí speciálního doplňku pro webové prohlížeÄe. PÅ™ed registrací zkoukni <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Pokud chceÅ¡ používat funkci send2c:geo, musíš se zaregistrovat. Aplikace c:geo může samozÅ™ejmÄ› pracovat normálnÄ› i bez registrace této funkce.</string>
<string name="init_sendToCgeo_register">Požádat o registraci</string>
<string name="init_sendToCgeo_registering">Registrace tvého zařízení pro funkci Poslat do c:geo…</string>
<string name="init_sendToCgeo_register_ok">Registrace úspěšnÄ› dokonÄena. PIN kód je ####. Použij ho na stránce c:geo pro pÅ™idání zařízení do tvého prohlížeÄe.</string>
@@ -546,7 +571,7 @@
<string name="auth_again">Znovu autorizovat</string>
<string name="auth_dialog_waiting">Čekání na %s…</string>
<string name="auth_explain_short">Následující proces umožní <b>c:geu</b> přístup k %s.</string>
- <string name="auth_explain_long">Stisknutím tlaÄítka \"Autorizovat c:geo\" bude proces zahájen. Tento proces otevÅ™e webový prohlížeÄ se stránkou %s. Na této stránce se pÅ™ihlaÅ¡ a povol <b>c:geu</b> pÅ™istupovat k tvému úÄtu. To je vÅ¡e.</string>
+ <string name="auth_explain_long">Stisknutím tlaÄítka „Autorizovat c:geo“ bude proces zahájen. Tento proces otevÅ™e webový prohlížeÄ se stránkou %s. Na této stránce se pÅ™ihlaÅ¡ a povol <b>c:geu</b> pÅ™istupovat k tvému úÄtu. To je vÅ¡e.</string>
<string name="auth_dialog_completed_twitter">c:geo nyní může posílat zprávy na Tvůj Twitter.</string>
<string name="auth_ocde">Opencaching.de</string>
<string name="auth_ocpl">opencaching.pl</string>
@@ -555,6 +580,11 @@
<string name="auth_ocro">opencaching.ro</string>
<string name="auth_ocuk">opencaching.org.uk</string>
<string name="auth_dialog_completed_oc">c:geo je nyní autorizováno pro interakce s %s.</string>
+ <plurals name="cache_counts">
+ <item quantity="one">Jedna keš</item>
+ <item quantity="few">%1$d keše</item>
+ <item quantity="other">%1$d keší</item>
+ </plurals>
<string name="cache_offline">Offline</string>
<string name="cache_offline_refresh">Obnovit</string>
<string name="cache_offline_drop">Smazat</string>
@@ -603,6 +633,7 @@
</plurals>
<string name="cache_waypoints_add">Přidat Bod trasy</string>
<string name="cache_hint">Nápověda</string>
+ <string name="cache_hint_not_available">Nápověda není dostupná</string>
<string name="cache_logs">Logbook</string>
<string name="cache_logs_friends_and_own">Moje logy a logy přátel</string>
<string name="cache_dialog_loading_details">NaÄítání detailů keÅ¡e…</string>
@@ -642,9 +673,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Otevřít v prohlížeÄí</string>
<string name="cache_menu_visit">Zalogovat návštěvu</string>
- <string name="cache_menu_visit_offline">Zapsat návštěvu (offline)</string>
+ <string name="cache_menu_visit_offline">Rychlý offline log</string>
<string name="cache_menu_spoilers">Obrázky</string>
<string name="cache_menu_around">Keš v okolí</string>
+ <string name="around">V okolí %s</string>
<string name="cache_menu_event">Přidat do kalendáře</string>
<string name="cache_menu_details">Detaily</string>
<string name="cache_menu_refresh">Obnovit</string>
@@ -654,6 +686,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Hlasovat</string>
+ <string name="cache_menu_checker">Otevřít Geocheck</string>
+ <string name="cache_menu_ignore">Ignorovat keš</string>
<string name="cache_status">Stav</string>
<string name="cache_status_offline_log">Připravený Log</string>
<string name="cache_status_found">Nalezena</string>
@@ -739,6 +774,7 @@
<string name="waypoint_note">Poznámka</string>
<string name="waypoint_visited">Navštíven</string>
<string name="waypoint_save">Uložit</string>
+ <string name="waypoint_cancel_edit">Zrušit</string>
<string name="waypoint_loading">NaÄítání bodu trasy…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Neměnit souřadnice keše</string>
<string name="waypoint_set_as_cache_coords">Nastavit jako souřadnice keše v c:geo</string>
@@ -763,6 +799,8 @@
<string name="search_clear_history">Vymazat historii</string>
<string name="search_history_cleared">Historie vymazána</string>
<string name="waypoint_coordinate_formats_plain">Prostý</string>
+ <string name="from_clipboard">Ze schránky</string>
+ <string name="copy_to_clipboard">Kopírovat do schránky</string>
<string name="visit_tweet">Oznámit nález na Twitteru</string>
<string name="map_map">Mapa</string>
<string name="map_live">Aktivní mapa</string>
@@ -785,7 +823,7 @@
<string name="map_strategy_fast">Rychlá</string>
<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_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 v aplikaci na stránce „O aplikaci“.</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>
@@ -867,7 +905,7 @@
<string name="helper_contacts_description">Umožňuje otevřít vizitku (z tvého seznamu kontaktů) přímo z logu keše, můžeš tak snadněji kontaktovat kamarády o pomoc.</string>
<string name="helper_sendtocgeo_description">Poslat do c:geo (Send2c:geo) je rozšíření prohlížeÄe <strong>pro tvůj poÄítaÄ</strong>. Umožňuje zaslání keÅ¡e do tvého mobilního zařízení jediným klepnutím, přímo z prohlížeÄe, pÅ™i procházení webu Geocaching.com.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">JednoduÅ¡e použitelná aplikace zobrazující Online mapy a dovolující je přímo stahovat pro Offline použití (pouze rastrové mapy). Také podporuje záznam trasy, zpracování bodů zájmu a další užiteÄné funkce.</string>
+ <string name="helper_locus_description">Outdoorová navigace pro telefon Äi tablet. Prohlížení offline topo map, záznam trasy, lov geokeší, hlasová navigace a mnohem více.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Můžeš použít radar z této aplikace pro c:geo. Také podporuje další funkce spojené s používáním GPS.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1117,15 +1155,17 @@
<string name="attribute_survey_marker_no">Není v blízkosti měřiÄské znaÄky</string>
<string name="attribute_offset_cache_yes">Offset keš</string>
<string name="attribute_offset_cache_no">Není to Offset keš</string>
- <string name="quote">UÄinit Geocaching lehÄí a uživatelé línÄ›jší.</string>
+ <string name="quote">UÄinit Geocaching lehÄí a uživatele línÄ›jší.</string>
<string name="powered_by">carnero</string>
- <string name="support">Podpora: <a href="">support@cgeo.org</a></string>
- <string name="website">Stránka: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">Stránka c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo na Google Play</a></string>
+ <string name="support_title">Podpora</string>
+ <string name="website_title">Webové stránky</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">stránka c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo na Google Play</a></string>
<string name="about_twitter">Má <b>c:geo</b> publikovat nový status na Twitteru vždy, když zaloguješ keš?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Dostupné nové vydání.\nKlepni pro instalaci.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Dostupné nové \"noÄní sestavení\"\nKlepni pro instalaci.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Dostupný nový kandidát na vydání.\nKlepni pro instalaci.</string>
@@ -1140,13 +1180,43 @@
<string name="tts_stopped">ŘeÄ ukonÄena</string>
<string name="err_tts_lang_not_supported">PÅ™evod textu na Å™eÄ není pro tento jazyk k dispozici.</string>
<string name="tts_one_kilometer">jeden kilometr</string>
+ <plurals name="tts_kilometers">
+ <item quantity="one">%s kilometr</item>
+ <item quantity="few">%s kilometry</item>
+ <item quantity="other">%s kilometrů</item>
+ </plurals>
<string name="tts_one_meter">jeden metr</string>
+ <plurals name="tts_meters">
+ <item quantity="one">%s metr</item>
+ <item quantity="few">%s metry</item>
+ <item quantity="other">%s metrů</item>
+ </plurals>
<string name="tts_one_mile">jedna míle</string>
+ <plurals name="tts_miles">
+ <item quantity="one">%s míle</item>
+ <item quantity="few">%s míle</item>
+ <item quantity="other">%s mil</item>
+ </plurals>
<string name="tts_one_foot">jedna stopa</string>
+ <plurals name="tts_feet">
+ <item quantity="one">%s stopa</item>
+ <item quantity="few">%s stopy</item>
+ <item quantity="other">%s stop</item>
+ </plurals>
<string name="tts_one_oclock">jedna hodina</string>
<string name="tts_oclock">%s hodin</string>
<string name="clipboard_copy_ok">Zkopírováno do schránky</string>
- <string name="percent_favorite_points">%\ oblíbené</string>
+ <plurals name="days_ago">
+ <item quantity="one">vÄera</item>
+ <item quantity="few">před %d dny</item>
+ <item quantity="other">před %d dny</item>
+ </plurals>
+ <plurals name="favorite_points">
+ <item quantity="one">%s oblíbená</item>
+ <item quantity="few">%s oblíbené</item>
+ <item quantity="other">%s oblíbených</item>
+ </plurals>
+ <string name="more_than_percent_favorite_points">&gt; %d%% oblíbených položek</string>
<string name="cgeo_shortcut">c:geo zástupce</string>
<string name="create_shortcut">Vytvořit zástupce</string>
<string name="send">Odeslat</string>
@@ -1156,6 +1226,8 @@
<string name="showcase_main_text">c:geo nyní umísÅ¥uje položky menu v záhlaví jako ostatní moderní aplikace. NÄ›které položky jsou skryty za symbolem tří teÄek. Dlouhým stiskem tlaÄítka zobrazíš jeho popis.</string>
<string name="showcase_cachelist_title">Přepínání seznamů</string>
<string name="showcase_cachelist_text">Mezi seznamy s keškami můžeš přepínat klepnutím na název seznamu.</string>
+ <string name="showcase_compass_hint_title">Zobrazit nápovědu</string>
+ <string name="showcase_compass_hint_text">Tato nová položka vám může poradit, kde kešku hledat - zobrazuje nápovědu, pokud je k dispozici.</string>
<string name="confirm_log_title">Neobvyklý typ logu</string>
<string name="confirm_log_message">Opravdu chceš zalogovat „%s“?</string>
</resources>
diff --git a/main/res/values-da/strings.xml b/main/res/values-da/strings.xml
index 5f4a061..7939498 100644
--- a/main/res/values-da/strings.xml
+++ b/main/res/values-da/strings.xml
@@ -9,8 +9,8 @@
<string name="about">Om c:geo</string>
<string name="latitude">Breddegrad</string>
<string name="longitude">Længdegrad</string>
- <string name="settings_titlebar">c:geo Indstillinger</string>
- <string name="all_types">Alle Cache typer</string>
+ <string name="settings_titlebar">c:geo indstillinger</string>
+ <string name="all_types">Alle cachetyper</string>
<string name="traditional">Traditionel cache</string>
<string name="multi">Multi-cache</string>
<string name="mystery">Ukendt cache</string>
@@ -71,15 +71,17 @@
<string name="log_retractlisting">Retract Listing</string>
<string name="log_marked_missing">Markeret som mangler</string>
<string name="log_tb_nothing">Gør intet</string>
- <string name="log_tb_visit">Besøg</string>
+ <string name="log_tb_visit">Besøgt</string>
<string name="log_tb_drop">Læg her</string>
<string name="log_tb_changeall">Ændr alle</string>
- <string name="log_save">Gem</string>
+ <string name="log_save">Gem offline</string>
<string name="log_saving">Sender logbesked…</string>
<string name="log_saving_and_uploading">Sender logbesked og billede…</string>
<string name="log_clear">Fjern</string>
<string name="log_post_not_possible">Indlæser logside…</string>
+ <string name="log_date_future_not_allowed">Logdatoer, der ligger i fremtiden, er ikke tilladt.</string>
<string name="log_add">Tilføj</string>
+ <string name="log_repeat">Gentag sidste logbesked</string>
<string name="log_no_rating">Ingen vurdering</string>
<string name="log_stars_1_description">DÃ¥rlig</string>
<string name="log_stars_15_description">Temmelig dårlig</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Adgangskode til log:</string>
<string name="log_hint_log_password">Skriv adgangskode til log</string>
<string name="log_oc_team_comment">OC Hold-meddelelse</string>
+ <string name="log_your_saved_log">Dine gemte log</string>
<string-array name="log_image_scales">
<item>Ingen skalering</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Loginoplysninger mangler</string>
<string name="err_login_failed_toast">c:geo kan ikke logge ind. c:geo fungerer offline med gemte cacher. Kontrollér login-indstillingerne eller aktivér din Internetforbindelse.</string>
<string name="err_unknown">Ukendt fejl</string>
+ <string name="err_unknown_address">c:geo kunne ikke tilknytte denne adresse til en eksisterende placering</string>
<string name="err_comm">Ukendt forbindelsesfejl</string>
<string name="err_missing_auth">Intet brugernavn og/eller password konfigureret.</string>
<string name="err_wrong">Fejl i login</string>
@@ -132,10 +136,10 @@
<string name="err_unvalidated_account">Du skal først validere din konto på geocaching.com.</string>
<string name="err_unpublished">Den forespurgte cache er ikke frigivet.</string>
<string name="err_premium_only">Denne cache er kun tilgængelig for Geocaching.com Premium-medlemmer.</string>
- <string name="err_detail_open">Beklager, c:geo kan ikke indlæse cachedetaljer.</string>
+ <string name="err_detail_open">c:geo kan ikke indlæse cachedetaljer.</string>
<string name="err_detail_cache">Beklager, c:geo kan ikke vise denne cache.</string>
- <string name="err_detail_cache_find">Beklager, c:geo kan ikke vise denne cache</string>
- <string name="err_detail_cache_find_some">Beklager, c:geo kan ikke vise denne cache.</string>
+ <string name="err_detail_cache_find">c:geo kan ikke finde geocachen</string>
+ <string name="err_detail_cache_find_some">c:geo kan ikke finde denne denne geocache.</string>
<string name="err_detail_cache_find_any">c:geo kan ikke finde nogen geocacher.</string>
<string name="err_detail_google_maps_limit_reached">c: geo kunne ikke hente statisk kort. Måske er det tilladte maksimum for Google Maps API forespørgsler overskredet.</string>
<string name="err_detail_no_spoiler">c:geo fandt ingen spoilerbilleder til denne cache.</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Optagelse af et billede mislykkedes.</string>
<string name="err_tb_display">c:geo kan ikke vise den forespurgte Trackable. Er det virkelig en Trackable?</string>
<string name="err_tb_details_open">c:geo kan ikke åbne Trackable-detaljer.</string>
- <string name="err_tb_forgot_saw">c:geo glemte hvilken Trackable du så.</string>
<string name="err_tb_find">c:geo kan ikke finde den forespurgte Trackable</string>
<string name="err_tb_find_that">c:geo kan ikke finde den forespurgte Trackable.</string>
<string name="err_waypoint_cache_unknown">c: geo ved ikke hvilken cache, du ønsker at tilføje et waypoint til.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c: geo kan ikke bestemme din placering.</string>
<string name="err_point_no_position_given_title">Oplysninger mangler</string>
<string name="err_point_no_position_given">Udfyld mindst breddegrad og længdegrad eller afstand og pejling. Du kan også udfylde alle fire felter.</string>
- <string name="err_point_curr_position_unavailable">c: geo har endnu ikke bestemt din position. Vent venligst…</string>
<string name="err_point_bear_and_dist_title">Har du brug for hjælp?</string>
<string name="err_point_bear_and_dist">Udfyld både pejling og afstand. Pejlingen er en kompasvinkel mellem 0 og 360 grader i forhold til nord. Afstanden kræver ikke enheder.</string>
<string name="err_log_load_data">c: geo kan ikke indlæse de data, der kræves for at logge besøget.</string>
<string name="err_log_load_data_again">c: geo kan ikke indlæse de data, der kræves for at logge besøget. Forsøger igen.</string>
<string name="err_log_load_data_still">c:geo forsøger stadig at indlæse de data, som kræves for at sende logbeskeden. Vent venligst.</string>
- <string name="err_log_post_failed">Din logbesked blev muligvis ikke blev gemt korrekt. Kontrollér venligst på geocaching.com.</string>
- <string name="err_log_post_failed_ec">Din logbesked blev muligvis ikke blev gemt korrekt. Kontrollér venligst på extremecaching.com.</string>
- <string name="err_logimage_post_failed">Dit logbeskedbillede blev muligvis ikke gemt korrekt. Kontrollér venligst på geocaching.com.</string>
+ <string name="err_log_post_failed">Din logbesked blev muligvis ikke uploadet. Kontrollér logbeskeden på geocachens hjemmeside.</string>
+ <string name="err_logimage_post_failed">Dit logbillede blev muligvis ikke uploadet korrekt. Kontrollér billedet på geocachens hjemmeside.</string>
<string name="err_search_address_forgot">c: geo glemte den adresse, du forsøgte at finde.</string>
<string name="err_parse_lat">c:geo kan ikke forstå den indtastede breddegrad.</string>
<string name="err_parse_lon">c:geo kan ikke forstå den indtastede længdegrad.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Netværk</string>
<string name="loc_fused">Kombineret</string>
<string name="loc_low_power">Lavt strømforbrug</string>
+ <string name="loc_home">Hjemmeposition</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Bestemmer position</string>
@@ -263,15 +265,18 @@
<string name="caches_sort_finds">Fund</string>
<string name="caches_sort_state">Status</string>
<string name="caches_sort_storage">Dato for lagring på enhed</string>
+ <string name="caches_sort_eventdate">Eventdato</string>
<string name="caches_select_mode">Markér</string>
<string name="caches_select_mode_exit">Afslut markering</string>
<string name="caches_select_invert">Omvend markering</string>
<string name="caches_nearby">I nærheden</string>
<string name="caches_manage">Administrér</string>
<string name="caches_remove_all">Fjern alle</string>
- <string name="caches_remove_all_confirm">Vil du fjerne alle %s cacher fra den aktuelle liste?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Vil du fjerne denne cache fra den aktuelle liste?</item>
+ <item quantity="other">Ønsker du at fjerne alle %d cacher fra den aktuelle liste?</item>
+ </plurals>
<string name="caches_remove_selected">Fjern valgte</string>
- <string name="caches_remove_selected_confirm">Vil du fjerne de valgte %s cacher fra din enhed?</string>
<string name="caches_remove_progress">Fjerner cacher</string>
<string name="caches_delete_events">Slet tidligere begivenheder</string>
<string name="caches_refresh_selected">Genindlæs valgte</string>
@@ -291,13 +296,18 @@
<string name="caches_filter_track">Med Trackables</string>
<string name="caches_filter_clear">Nulstil filtre</string>
<string name="caches_filter_modified">Med ændret position</string>
+ <string name="caches_filter_offline_log">Med offline log</string>
<string name="caches_filter_origin">Kilde</string>
<string name="caches_filter_distance">Afstand</string>
<string name="caches_filter_personal_note">Med personlig note</string>
<string name="caches_filter_popularity">Favoritter</string>
<string name="caches_filter_popularity_ratio">Favoritter [%]</string>
+ <string name="caches_filter_personal_data">Med personlige data</string>
+ <string name="caches_filter_rating">Med vurdering</string>
+ <string name="caches_filter_own_rating">Med egen vurdering</string>
<string name="caches_removing_from_history">Fjerner fra historik…</string>
<string name="caches_clear_offlinelogs">Fjern offline logbeskeder</string>
+ <string name="caches_clear_offlinelogs_message">Vil du fjerne offline logbeskeder?</string>
<string name="caches_clear_offlinelogs_progress">Fjerner offline logbeskeder</string>
<string name="list_menu_create">Opret ny liste</string>
<string name="list_menu_drop">Fjern aktuelle liste</string>
@@ -320,13 +330,17 @@
<string name="list_not_available">Listen er ikke længere tilgængelig, skifter til standard liste</string>
<string name="about_version">Version</string>
<string name="about_changelog">Ændringslog</string>
+ <string name="about_system">System</string>
<string name="about_donate">Donér</string>
<string name="about_donation_more">Donér\nudvikling</string>
<string name="about_contributors">Bidragsydere</string>
<string name="about_license">Licens</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Hjælp</string>
+ <string name="about_system_include">Vedhæft følgende systemoplysninger når du sender en fejlrapport eller beder om yderligere oplysninger om c:geo:</string>
+ <string name="changelog_github">Liste over alle ændringer</string>
<string name="settings_title_services">Tjenester</string>
+ <string name="settings_summary_services">Konfigurér oplysninger om brugerkonto og adgang til valgfrie tjenester.</string>
<string name="settings_title_appearance">Udseende</string>
<string name="settings_title_cachedetails">Cachedetaljer</string>
<string name="settings_title_offlinedata">Offline data</string>
@@ -364,6 +378,9 @@
<string name="settings_activate_oc_uk">Aktivér</string>
<string name="init_oc_uk_description">Giv c:geo tilladelse til at søge efter cacher samt tilgå og filtrere dine fundne cacher på opencaching.org.uk.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">For at kunne bedømme en cache skal du følge instruktionerne på GCVote.com og angive dit password til GCVote her.</string>
+ <string name="err_gcvote_send_rating">Fejl under afsendelse af bedømmelse. Kontrollér eller fjern GCVote password under Indstillinger.</string>
+ <string name="gcvote_sent">Stemme blev afsendt</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktivér</string>
<string name="init_username">Brugernavn</string>
@@ -434,6 +451,8 @@
<string name="init_backup_success">Database blev kopieret til:</string>
<string name="init_backup_failed">Backup af database fejlede.</string>
<string name="init_backup_unnecessary">Databasen er tom og det er ikke nødvendigt at tage backup.</string>
+ <string name="backup_confirm_overwrite">Vil du overskrive den eksisterende backup fra %s?</string>
+ <string name="restore_confirm_overwrite">Vil du overskrive %s på din enhed med denne backup?</string>
<string name="init_restore_success">Gendannelse fuldført.</string>
<string name="init_restore_failed">Gendannelse fejlede.</string>
<string name="init_restore_running">Gendanner cache-database…</string>
@@ -590,6 +609,7 @@
</plurals>
<string name="cache_waypoints_add">Tilføj waypoint</string>
<string name="cache_hint">Hint</string>
+ <string name="cache_hint_not_available">Intet hint tilgængeligt</string>
<string name="cache_logs">Logbog</string>
<string name="cache_logs_friends_and_own">Venners/egne logbeskeder</string>
<string name="cache_dialog_loading_details">Indlæser cachedetaljer…</string>
@@ -629,9 +649,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Ã…bn i browser</string>
<string name="cache_menu_visit">Log besøg</string>
- <string name="cache_menu_visit_offline">Log besøg offline</string>
+ <string name="cache_menu_visit_offline">Hurtig offline logbesked</string>
<string name="cache_menu_spoilers">Spoilerbilleder</string>
<string name="cache_menu_around">Cacher i nærheden</string>
+ <string name="around">I nærheden af %s</string>
<string name="cache_menu_event">Tilføj til kalender</string>
<string name="cache_menu_details">Detaljer</string>
<string name="cache_menu_refresh">Genindlæs</string>
@@ -640,6 +661,9 @@
<string name="cache_menu_whereyougo">WhereYouGo</string>
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Stem</string>
+ <string name="cache_menu_checker">Ã…ben Geochecker</string>
+ <string name="cache_menu_ignore">Ignorér cache</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Log gemt</string>
<string name="cache_status_found">Fundet</string>
@@ -725,6 +749,7 @@
<string name="waypoint_note">Note</string>
<string name="waypoint_visited">Besøgt</string>
<string name="waypoint_save">Gem</string>
+ <string name="waypoint_cancel_edit">Annullér</string>
<string name="waypoint_loading">Indlæser waypoint…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Ingen ændringer i cacheposition</string>
<string name="waypoint_set_as_cache_coords">Sæt som cacheposition i c:geo</string>
@@ -749,6 +774,8 @@
<string name="search_clear_history">Slet historik</string>
<string name="search_history_cleared">Historik slettet</string>
<string name="waypoint_coordinate_formats_plain">Simpel</string>
+ <string name="from_clipboard">Fra udklipsholder</string>
+ <string name="copy_to_clipboard">Kopiér til upklipsholder</string>
<string name="visit_tweet">Post fund på Twitter</string>
<string name="map_map">Kort</string>
<string name="map_live">Live-kort</string>
@@ -853,7 +880,7 @@
<string name="helper_contacts_description">Giver dig mulighed for at åbne kontaktside (fra dine kontakter) direkte fra en logbesked, så du let kan kontakte dine venner.</string>
<string name="helper_sendtocgeo_description">Send2c:geo (send til c:geo) er en browserudvidelse <strong>til din PC</strong>. Med send2c:geo kan du sende cacher direkte fra din browser til c:geo på din Android-enhed ved blot at klikke på en knap i din browser.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Simpel og brugervenlig app, som viser online kort og giver dig mulighed for at downloade dem direkte til offline tilstand (gælder kun raster-kort). Understøtter også optagelse af GPS-spor, administration af interessepunkter og mange andre anvendelige funktioner.</string>
+ <string name="helper_locus_description">Udendørs navigationsapp til din telefon eller tablet. Vis topografiske kort offline, track din rute, find geocacher, brug stemmeguide og meget mere.</string>
<string name="helper_gpsstatus_title">GPS-status</string>
<string name="helper_gpsstatus_description">Du kan bruger radaren i denne app sammen med c:geo. Appen giver desuden en mængde GPS-relateret information.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -933,7 +960,7 @@
<string name="attribute_abandonedbuilding_no">Ikke forladt bygning</string>
<string name="attribute_hike_short_yes">Kort gåtur (under 1 km)</string>
<string name="attribute_hike_short_no">Ikke kort gåtur</string>
- <string name="attribute_hike_med_yes">Mellemlang gåtur (1-10 km)</string>
+ <string name="attribute_hike_med_yes">Mellemlang gåtur (1–10 km)</string>
<string name="attribute_hike_med_no">Ikke mellemlang gåtur</string>
<string name="attribute_hike_long_yes">Lang gåtur (over 10 km)</string>
<string name="attribute_hike_long_no">Ikke lang gåtur</string>
@@ -1104,12 +1131,15 @@
<string name="attribute_offset_cache_yes">Offset-cache</string>
<string name="attribute_offset_cache_no">Ikke en offset-cache</string>
<string name="quote">To make geocaching easier, to make users lazier.</string>
- <string name="support">Support: <a href="mailto:support@cgeo.org">support@cgeo.org</a></string>
- <string name="website">Hjemmeside: <a href="http://cgeo.org/">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="http://twitter.com/android_gc">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo på Google Play</a></string>
+ <string name="support_title">Support</string>
+ <string name="website_title">Websted</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">c:geo webside</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo på Google Play</a></string>
<string name="about_twitter">Skal <b>c:geo</b> sende status til Twitter hver gang du logger en cache?</string>
+ <string name="faq_title">Ofte stillede spørgsmål</string>
<string name="status_new_release" tools:ignore="UnusedResources">Ny udgave er tilgængelig.\nKlik for at installere.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nyt nightly build af c:geo er tilgængelig.\nKlik for at installere.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Ny release kandidat af c:geo er tilgængelig.\nKlik for at installere.</string>
@@ -1150,7 +1180,7 @@
<item quantity="one">%s favorit</item>
<item quantity="other">%s favoritter</item>
</plurals>
- <string name="percent_favorite_points">%% favoritter</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoritter</string>
<string name="cgeo_shortcut">c:geo genvej</string>
<string name="create_shortcut">Opret genvej</string>
<string name="send">Send</string>
@@ -1160,6 +1190,8 @@
<string name="showcase_main_text">Som i andre moderne apps er menupunkter i c:geo nu placeret i titellinien. Nogle menupunkter er skjult og bliver først vist når du trykker på knappen med tre prikker. Et langt tryk på et menupunkt åbner en beskrivelse af menupunktet.</string>
<string name="showcase_cachelist_title">Skift af liste</string>
<string name="showcase_cachelist_text">Du kan skifte mellem dine lister ved at trykke på listens titel.</string>
+ <string name="showcase_compass_hint_title">Vis tip</string>
+ <string name="showcase_compass_hint_text">Dette nye menupunkt kan give dig en idé om hvor man kan finde cachen - det viser tippet, hvis det er tilgængelig.</string>
<string name="confirm_log_title">Usædvanlig logtype</string>
<string name="confirm_log_message">Du er ved at logge \"%s\". Er du sikker?</string>
</resources>
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index f764e94..d2c4078 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -74,12 +74,19 @@
<string name="log_tb_visit">Besucht</string>
<string name="log_tb_drop">Abgelegt</string>
<string name="log_tb_changeall">Alle ändern</string>
- <string name="log_save">Speichern</string>
+ <string name="log_tb_grabbed">Woanders mitgenommen</string>
+ <string name="log_tb_note">Notiz</string>
+ <string name="log_tb_discovered">Gesehen</string>
+ <string name="log_tb_archived">Archiviert</string>
+ <string name="log_save">Offline speichern</string>
<string name="log_saving">Log wird gesendet…</string>
<string name="log_saving_and_uploading">Log und Bild werden gesendet…</string>
<string name="log_clear">Leeren</string>
<string name="log_post_not_possible">Lade Log-Seite…</string>
+ <string name="log_post_geocode_missing">Geocode fehlt…</string>
+ <string name="log_date_future_not_allowed">Logs in der Zukunft sind nicht erlaubt.</string>
<string name="log_add">Hinzufügen</string>
+ <string name="log_repeat">Verwende das letzte Log erneut</string>
<string name="log_no_rating">Keine Bewertung</string>
<string name="log_stars_1_description">Schlecht</string>
<string name="log_stars_15_description">Lohnt sich nicht</string>
@@ -107,6 +114,7 @@
<string name="log_password_title">Log-Passwort:</string>
<string name="log_hint_log_password">Log-Passwort eingeben</string>
<string name="log_oc_team_comment">OC Team Bemerkung</string>
+ <string name="log_your_saved_log">Dein gespeichertes Log</string>
<string-array name="log_image_scales">
<item>Keine Skalierung</item>
<item>512 px</item>
@@ -120,13 +128,15 @@
<string name="err_none">OK</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>
+ <string name="err_server_ec">Verbindung zu extremcaching.com konnte nicht hergestellt werden. Server ist nicht verfügbar oder keine Internet-Verbindung vorhanden.</string>
+ <string name="err_server_gk">Verbindung zu geokrety.org konnte nicht hergestellt werden. Server ist nicht verfügbar oder keine Internet-Verbindung vorhanden.</string>
<string name="err_login">Keine Anmeldedaten gespeichert.</string>
<string name="err_login_failed_toast">c:geo konnte sich nicht einloggen und arbeitet im Offline-Modus. Bitte die Login-Daten in den Einstellungen überprüfen oder eine Internetverbindung herstellen.</string>
<string name="err_unknown">Unbekannter Fehler</string>
+ <string name="err_unknown_address">c:geo konnte keine Koordinaten für diese Adresse ermitteln</string>
<string name="err_comm">Unbekannter Kommunikationsfehler</string>
<string name="err_missing_auth">Benutzername oder Passwort nicht gesetzt.</string>
- <string name="err_wrong">Falsche Anmeldedaten</string>
+ <string name="err_wrong">Benutzername und/oder Passwort falsch</string>
<string name="err_maintenance">Geocaching.com wird zur Zeit gewartet, bitte später erneut versuchen. c:geo arbeitet im Offline-Modus.</string>
<string name="err_license">Die Geocaching.com Nutzungsbedingungen wurden nicht akzeptiert. c:geo kann deshalb keine Koordinaten laden.</string>
<string name="err_unvalidated_account">Die Logindaten müssen zuerst auf Geocaching.com validiert werden.</string>
@@ -158,7 +168,7 @@
<string name="err_acquire_image_failed">Erstellen eines Fotos ist fehlgeschlagen.</string>
<string name="err_tb_display">c:geo kann den gewünschten Trackable nicht anzeigen. Ist es wirklich einer?</string>
<string name="err_tb_details_open">c:geo konnte die Details des Trackables nicht öffnen.</string>
- <string name="err_tb_forgot_saw">c:geo hat vergessen, welcher Trackable gesehen wurde.</string>
+ <string name="err_tb_not_loggable">Dieser Trackable ist nicht logbar.</string>
<string name="err_tb_find">c:geo findet den Trackable nicht</string>
<string name="err_tb_find_that">c:geo konnte diesen Trackable nicht finden.</string>
<string name="err_waypoint_cache_unknown">c:geo weiß nicht, zu welchem Cache der Wegpunkt hinzugefügt werden soll.</string>
@@ -166,15 +176,17 @@
<string name="err_point_unknown_position">c:geo konnte den aktuellen Standort nicht bestimmen.</string>
<string name="err_point_no_position_given_title">Info benötigt</string>
<string name="err_point_no_position_given">Mindestens Längen- und Breitengrad oder Entfernung und Richtung angeben. Auch alle Angaben sind möglich.</string>
- <string name="err_point_curr_position_unavailable">c:geo hat noch keine aktuelle Koordinaten. Bitte einen Moment warten…</string>
<string name="err_point_bear_and_dist_title">Hilfe benötigt?</string>
<string name="err_point_bear_and_dist">Angaben zu Richtung und Entfernung sind notwendig. Richtung: 0 bis 360 Grad relativ zum Norden. Die Entfernung benötigt keine Bezeichnung der Einheiten. </string>
<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_post_failed">c:geo konnte den Log nicht absenden. Bitte auf geocaching.com überprüfen.</string>
+ <string name="err_log_post_missing_tracking_code">Tracking-Code fehlt.</string>
+ <string name="err_log_post_missing_coordinates">Koordinaten fehlen.</string>
+ <string name="err_log_post_failed">Der Log-Eintrag wurde scheinbar nicht gesendet. Bitte auf der betreffenden Geocaching-Webseite prüfen.</string>
<string name="err_log_post_failed_ec">c:geo konnte den Log nicht absenden. Bitte auf Extremcaching.com überprüfen.</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>
+ <string name="err_log_post_failed_gk">c:geo konnte den Log nicht absenden. Bitte auf GeoKrety.org überprüfen.</string>
+ <string name="err_logimage_post_failed">Das Log-Bild wurde scheinbar nicht hochgeladen. Bitte auf der betreffenden Geocaching-Webseite prüfen.</string>
<string name="err_search_address_forgot">c:geo hat die Adresse vergessen, die gesucht wurde.</string>
<string name="err_parse_lat">c:geo konnte den Breitengrad nicht verarbeiten.</string>
<string name="err_parse_lon">c:geo konnte den Längengrad nicht verarbeiten.</string>
@@ -211,6 +223,7 @@
<string name="loc_net">Netzwerk</string>
<string name="loc_fused">Kombiniert</string>
<string name="loc_low_power">Energiesparmodus</string>
+ <string name="loc_home">Heimkoordinaten</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">SAT</string>
<string name="loc_trying">Lokalisierung</string>
@@ -229,7 +242,7 @@
<string name="caches_nearby_button">In der Nähe</string>
<string name="advanced_search_button">Suche</string>
<string name="stored_caches_button">Gespeichert</string>
- <string name="any_button">Ãœberall</string>
+ <string name="any_button">Gehe zu</string>
<string name="unknown_scan">Konnte keinen Geocode im Scan finden.</string>
<string name="caches_no_cache">Kein Cache</string>
<string name="caches_more_caches">Mehr Caches laden</string>
@@ -263,15 +276,22 @@
<string name="caches_sort_finds">Funde</string>
<string name="caches_sort_state">Status</string>
<string name="caches_sort_storage">Speicherdatum</string>
+ <string name="caches_sort_eventdate">Event-Datum</string>
<string name="caches_select_mode">Auswahlmodus</string>
<string name="caches_select_mode_exit">Auswahlmodus beenden</string>
<string name="caches_select_invert">Auswahl invertieren</string>
<string name="caches_nearby">In der Nähe</string>
<string name="caches_manage">Verwalten</string>
<string name="caches_remove_all">Alle löschen</string>
- <string name="caches_remove_all_confirm">Sollen alle %s Caches gelöscht werden?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Soll der Cache von dieser Liste gelöscht werden?</item>
+ <item quantity="other">Sollen alle %d Caches von dieser Liste gelöscht werden?</item>
+ </plurals>
<string name="caches_remove_selected">Ausgewählte löschen</string>
- <string name="caches_remove_selected_confirm">Sollen die %s Caches gelöscht werden?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Soll dieser Cache gelöscht werden?</item>
+ <item quantity="other">Sollen die %d ausgewählten Caches gelöscht werden?</item>
+ </plurals>
<string name="caches_remove_progress">Entferne Caches…</string>
<string name="caches_delete_events">Vergangene Events löschen</string>
<string name="caches_refresh_selected">Ausgewählte aktualisieren</string>
@@ -291,13 +311,18 @@
<string name="caches_filter_track">Mit Trackables</string>
<string name="caches_filter_clear">Filter zurücksetzen</string>
<string name="caches_filter_modified">Mit geänderten Koordinaten</string>
+ <string name="caches_filter_offline_log">Mit Offline-Log</string>
<string name="caches_filter_origin">Herkunft</string>
<string name="caches_filter_distance">Entfernung</string>
<string name="caches_filter_personal_note">Mit persönlicher Notiz</string>
<string name="caches_filter_popularity">Favoriten</string>
<string name="caches_filter_popularity_ratio">Favoriten [%]</string>
+ <string name="caches_filter_personal_data">Mit eigenen Informationen</string>
+ <string name="caches_filter_rating">Mit Bewertung</string>
+ <string name="caches_filter_own_rating">Mit eigener Bewertung</string>
<string name="caches_removing_from_history">Lösche aus Verlauf…</string>
<string name="caches_clear_offlinelogs">Offline-Logs löschen</string>
+ <string name="caches_clear_offlinelogs_message">Möchtest du die Offline-Logs löschen?</string>
<string name="caches_clear_offlinelogs_progress">Lösche Offline-Logs</string>
<string name="list_menu_create">Neue Liste</string>
<string name="list_menu_drop">Aktuelle Liste löschen</string>
@@ -320,13 +345,17 @@
<string name="list_not_available">Liste nicht mehr vorhanden, wechsele zur Standardliste</string>
<string name="about_version">Version</string>
<string name="about_changelog">Änderungen</string>
+ <string name="about_system">System</string>
<string name="about_donate">Spenden</string>
<string name="about_donation_more">Spenden für\nEntwicklung</string>
<string name="about_contributors">Mitwirkende</string>
<string name="about_license">Lizenz</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Hilfe</string>
+ <string name="about_system_include">Bitte die folgende Systeminformation bei jedem Fehlerbericht oder bei Informationsanfragen zu c:geo mitsenden:</string>
+ <string name="changelog_github">Liste aller Änderungen</string>
<string name="settings_title_services">Dienste</string>
+ <string name="settings_summary_services">Konfiguriere Zugangsdaten und den Zugriff auf optionale Dienste.</string>
<string name="settings_title_appearance">Erscheinungsbild</string>
<string name="settings_title_cachedetails">Cache-Details</string>
<string name="settings_title_offlinedata">Offline-Daten</string>
@@ -370,9 +399,13 @@
<string name="init_oc_ro">Opencaching.ro</string>
<string name="settings_activate_oc_ro">Aktivieren</string>
<string name="init_oc_ro_description">Autorisiere c:geo auf opencaching.ro zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string>
+ <string name="init_oc_uk">Opencaching.org.uk</string>
<string name="settings_activate_oc_uk">Aktivieren</string>
<string name="init_oc_uk_description">Autorisiere c:geo auf opencaching.org.uk zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Um einen Cache bewerten zu können, folge der Anleitung auf gcvote.com und gib das GCVote-Passwort anschließend hier ein.</string>
+ <string name="err_gcvote_send_rating">Fehler beim Senden der Bewertung. Prüfe das GCVote-Passwort in den Einstellungen oder lösche es.</string>
+ <string name="gcvote_sent">Bewertung erfolgreich gesendet</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktivieren</string>
<string name="init_username">Benutzername</string>
@@ -443,6 +476,8 @@
<string name="init_backup_success">Datenbank von c:geo wurde erfolgreich kopiert nach:</string>
<string name="init_backup_failed">Sicherung der Datenbank von c:geo fehlgeschlagen.</string>
<string name="init_backup_unnecessary">Datenbank ist leer, keine Sicherung notwendig.</string>
+ <string name="backup_confirm_overwrite">Möchtest du das existierende Backup vom %s überschreiben?</string>
+ <string name="restore_confirm_overwrite">Möchtest du %s auf deinem Gerät mit dem Backup überschreiben?</string>
<string name="init_restore_success">Wiederherstellung fertig.</string>
<string name="init_restore_failed">Wiederherstellung fehlgeschlagen.</string>
<string name="init_restore_running">Wiederherstellung der Cache-Datenbank…</string>
@@ -492,8 +527,8 @@
<string name="init_maintenance_directories_note">c:geo speichert Bilder, Log-Bilder und weitere Dateien zu einem Cache in einem separaten Verzeichnis. In manchen Fällen (z.B. bei Sichern und Wiederherstellen der Datenbank) kann dieses Verzeichnis unnötige Daten enthalten, die gelöscht werden können.</string>
<string name="init_maintenance_directories">Verwaiste Daten löschen</string>
<string name="init_location">Positionierung</string>
- <string name="init_location_note">Auf Geräten mit GooglePlay-Diensten kann c:geo automatisch eine bessere Positions-Bestimmung nutzen. Allerdings kann dann kein externer Bluetooth GPS-Empfänger verwendet werden. Weiterhin kann damit ein Energiesparmodus ohne GPS genutzt werden, wenn hohe Genauigkeit nicht unbedingt erforderlich ist.</string>
- <string name="init_location_googleplayservices">GooglePlay-Dienst nutzen</string>
+ <string name="init_location_note">Auf Geräten mit Google Play-Diensten kann c:geo automatisch eine bessere Positions-Bestimmung nutzen. Allerdings kann dann kein externer Bluetooth GPS-Empfänger verwendet werden. Weiterhin kann damit ein Energiesparmodus ohne GPS genutzt werden, wenn hohe Genauigkeit nicht unbedingt erforderlich ist.</string>
+ <string name="init_location_googleplayservices">Google Play-Dienst nutzen</string>
<string name="init_low_power">Energiesparmodus</string>
<string name="init_low_power_note">Der Energiesparmodus vermeidet die Verwendung von GPS und Gyroskop, wenn eine hochgenaue Position nicht unbedingt notwendig ist. Nachteil ist eine längere Zeit bis zum GPS-Fix.</string>
<string name="init_low_power_mode">Energiesparmodus aktivieren</string>
@@ -504,6 +539,8 @@
<string name="init_hardware_acceleration_note">Mittels Hardwarebeschleunigung werden grafische Elemente schneller auf den Bildschirm dargestellt. Jedoch enthält das Android auf manchen Geräten Fehler, die zu verschwommenem Text (meistens bei fettgedruckten Zeichen) führen können. in diesen Fällen sollte die Hardwarebeschleunigung deaktiviert werden.</string>
<string name="init_hardware_acceleration">Hardwarebeschleunigung aktivieren</string>
<string name="settings_open_website">Webseite öffnen</string>
+ <string name="settings_open_geokrety_register">Öffne Registrierungs-Seite auf GeoKrety.org</string>
+ <string name="settings_open_geokretymap_website">Öffne GeokretyMap.org Webseite</string>
<string name="settings_settings">Einstellungen</string>
<string name="settings_information">Information</string>
<string name="settings_twitter_cache_message">Nachricht für gefundenen Cache</string>
@@ -549,6 +586,10 @@
<string name="auth_dialog_completed_twitter">c:geo ist nun autorisiert, Tweets bei Twitter zu erstellen.</string>
<string name="auth_ocde">opencaching.de</string>
<string name="auth_ocpl">opencaching.pl</string>
+ <string name="auth_ocnl">opencaching.nl</string>
+ <string name="auth_ocus">opencaching.us</string>
+ <string name="auth_ocro">opencaching.ro</string>
+ <string name="auth_ocuk">opencaching.org.uk</string>
<string name="auth_dialog_completed_oc">c:geo ist nun autorisiert, Caches zu laden und auf %s zu loggen.</string>
<plurals name="cache_counts">
<item quantity="one">Ein Cache</item>
@@ -601,6 +642,7 @@
</plurals>
<string name="cache_waypoints_add">Wegpunkt hinzufügen</string>
<string name="cache_hint">Hinweis</string>
+ <string name="cache_hint_not_available">Kein Hinweis verfügbar</string>
<string name="cache_logs">Logbuch</string>
<string name="cache_logs_friends_and_own">Logbuch (Freunde/Eigene)</string>
<string name="cache_dialog_loading_details">Lade Cache-Details…</string>
@@ -640,9 +682,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Im Browser öffnen</string>
<string name="cache_menu_visit">Besuch loggen</string>
- <string name="cache_menu_visit_offline">Besuch offline loggen</string>
+ <string name="cache_menu_visit_offline">Offline loggen</string>
<string name="cache_menu_spoilers">Hinweisbild</string>
<string name="cache_menu_around">Caches im Umkreis</string>
+ <string name="around">In der Nähe von %s</string>
<string name="cache_menu_event">Zum Kalender hinzufügen</string>
<string name="cache_menu_details">Details</string>
<string name="cache_menu_refresh">Aktualisieren</string>
@@ -652,6 +695,10 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble Smartwatch</string>
+ <string name="cache_menu_android_wear">Android Wear</string>
+ <string name="cache_menu_vote">Bewerten</string>
+ <string name="cache_menu_checker">Öffne Geochecker</string>
+ <string name="cache_menu_ignore">Cache ignorieren</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Gespeicherter Log</string>
<string name="cache_status_found">Gefunden</string>
@@ -737,6 +784,7 @@
<string name="waypoint_note">Notiz</string>
<string name="waypoint_visited">Besucht</string>
<string name="waypoint_save">Speichern</string>
+ <string name="waypoint_cancel_edit">Abbrechen</string>
<string name="waypoint_loading">Lade Wegpunkt…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Cache-Koordinaten nicht ändern</string>
<string name="waypoint_set_as_cache_coords">Als Cache-Koordinaten lokal setzen</string>
@@ -761,6 +809,8 @@
<string name="search_clear_history">Verlauf löschen</string>
<string name="search_history_cleared">Verlauf gelöscht</string>
<string name="waypoint_coordinate_formats_plain">Schlicht</string>
+ <string name="from_clipboard">Aus der Zwischenablage</string>
+ <string name="copy_to_clipboard">In Zwischenablage kopieren</string>
<string name="visit_tweet">Diesen Eintrag auf Twitter veröffentlichen</string>
<string name="map_map">Karte</string>
<string name="map_live">Live-Karte</string>
@@ -802,7 +852,7 @@
<string name="search_hbu_prefill">Besitzer</string>
<string name="search_hbu_button">Suche mit Besitzername</string>
<string name="search_tb">Trackable</string>
- <string name="search_tb_hint">Trackingnummer</string>
+ <string name="search_tb_hint">Tracking-Code</string>
<string name="search_tb_button">Suche nach Trackable</string>
<string name="search_destination">Ziel</string>
<string name="search_direction_rel">Vom aktuellen Standort</string>
@@ -819,7 +869,7 @@
<string name="trackable_goal">Derzeitiges Ziel</string>
<string name="trackable_details">Ãœber diesen Trackable</string>
<string name="trackable_image">Foto</string>
- <string name="trackable_code">TB-Code</string>
+ <string name="trackable_code">Tracking-Code</string>
<string name="trackable_name">Name</string>
<string name="trackable_type">Typ</string>
<string name="trackable_owner">Eigentümer</string>
@@ -834,6 +884,9 @@
<string name="trackable_distance">Zurückgelegte Strecke</string>
<string name="trackable_touch">Trackable-Aktion</string>
<string name="trackable_not_activated">Trackable nicht aktiviert</string>
+ <string name="trackable_travelbug">Travelbug</string>
+ <string name="trackable_geokrety">Geokrety</string>
+ <string name="trackable_swaggie">Swaggie</string>
<string name="geokret_type_traditional">Traditionell</string>
<string name="geokret_type_book_or_media">Buch oder elektronisches Medium</string>
<string name="geokret_type_human">Mensch</string>
@@ -865,7 +918,7 @@
<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_sendtocgeo_description">Send to c:geo ist eine Browsererweiterung <strong>für Ihren PC</strong>. Beim Durchsuchen von geocaching.com können Sie Caches mit einem Klick im Browser direkt an Ihr Smartphone übermitteln.</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_locus_description">Outdoor Navigations-App für dein Handy oder Tablet. Verwende topografische Karten offline, zeichne Tracks von deinen Touren auf, suche Geocaches, benutze Sprachführung und vieles mehr.</string>
<string name="helper_gpsstatus_title">GPS-Status</string>
<string name="helper_gpsstatus_description">Das Radar dieser App kann in c:geo verwendet und zusätzlich viele GPS-bezogene Informationen abgerufen werden.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1117,13 +1170,15 @@
<string name="attribute_offset_cache_no">Kein Offset Cache</string>
<string name="quote">Um Geocachen einfacher zu machen, um es Anwendern bequemer zu machen.</string>
<string name="powered_by">carnero</string>
- <string name="support">Support: <a href="">support@cgeo.org</a></string>
- <string name="website">Webseite: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo auf Google Play</a></string>
+ <string name="support_title">Support</string>
+ <string name="website_title">Webseite</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">Seite von c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo bei Google Play</a></string>
<string name="about_twitter">Soll jeder neue Fund auf Twitter veröffentlicht werden, wenn er über <b>c:geo</b> geloggt wird?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQs</string>
<string name="status_new_release" tools:ignore="UnusedResources">Neuer Release verfügbar.\nKlicken zum Installieren.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Neuer Nightly Build verfügbar.\nKlicken zum Installieren.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Neuer Release Candidate verfügbar.\nKlicken zum Installieren.</string>
@@ -1168,7 +1223,7 @@
<item quantity="one">%s Favorit</item>
<item quantity="other">%s Favoriten</item>
</plurals>
- <string name="percent_favorite_points">% Favoriten</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% Favoriten</string>
<string name="cgeo_shortcut">c:geo Shortcut</string>
<string name="create_shortcut">Shortcut erstellen</string>
<string name="send">Senden</string>
@@ -1178,6 +1233,21 @@
<string name="showcase_main_text">c:geo nutzt nun die Titelzeile für Menü-Optionen wie in anderen modernen Apps. Einige Menüpunkte sind dabei hinter der Drei-Punkt Schaltfläche versteckt. Ein langer Druck auf eine Schaltfläche zeigt die Bedeutung.</string>
<string name="showcase_cachelist_title">Liste wechseln</string>
<string name="showcase_cachelist_text">Du kannst zwischen deinen Listen wechseln, indem du auf den Titel der Liste klickst.</string>
+ <string name="showcase_compass_hint_title">Zeige den Hint</string>
+ <string name="showcase_compass_hint_text">Diese neue Option könnte dir helfen den Cache zu finden - sie zeigt den Hint an, wenn es einen gibt.</string>
<string name="confirm_log_title">Ungewöhnlicher Log-Typ</string>
<string name="confirm_log_message">Du möchtest \'%s\' loggen. Bist du dir sicher?</string>
+ <string name="init_geokrety">Geokrety.org</string>
+ <string name="init_geokrety_login">EInloggen auf GeoKrety.org</string>
+ <string name="init_connectorGeokretyActive">Geokrety Trackables</string>
+ <string name="init_summary_geokrety">Lädt Trackables von Geokrety.org</string>
+ <string name="init_summary_geokrety_cache">Verbessert die Ladezeit.</string>
+ <string name="init_summary_geokrety_account">Kein Konto konfiguriert.</string>
+ <string name="init_summary_geokrety_not_anonymous">Loggen aus c:geo kann nicht anonym erfolgen. Bitte registrieren.</string>
+ <string name="init_geokrety_register_ok">Login erfolgreich</string>
+ <string name="init_geokrety_register_fail">Login fehlgeschlagen</string>
+ <string name="init_geokrety_get_secid">API-Schlüssel abrufen</string>
+ <string name="init_geokrety_description">Speichere deinen API-SChlüssel in c:geo um das Loggen von GeoKrety zu vereinfachen</string>
+ <string name="init_geokrety_cache_description">GeokretyMap.org stellt zwischengespeicherte Daten für GeoKrety-Trackables zur Verfügung. Die Daten sind möglichweise nicht auf dem neuesten Stand!\nPositionen: ~30min.\nBeschreibungen: ~24h.</string>
+ <string name="init_geokrety_cache">Benutze zwischengespeicherte Daten</string>
</resources>
diff --git a/main/res/values-es/strings.xml b/main/res/values-es/strings.xml
index ef02630..c6c28ff 100644
--- a/main/res/values-es/strings.xml
+++ b/main/res/values-es/strings.xml
@@ -2,45 +2,45 @@
<!--Generated by crowdin.com-->
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">c:geo</string>
- <string name="cache">Escondite</string>
- <string name="detail">Detalle</string>
+ <string name="cache">Caché</string>
+ <string name="detail">Detalles</string>
<string name="search">Buscar</string>
- <string name="helpers">¿Qué instalar?</string>
+ <string name="helpers">Programas útiles</string>
<string name="about">Sobre c:geo</string>
<string name="latitude">Latitud</string>
<string name="longitude">Longitud</string>
<string name="settings_titlebar">c:geo Ajustes</string>
- <string name="all_types">Todos los escondites</string>
- <string name="traditional">Tradicionales</string>
- <string name="multi">Multis</string>
- <string name="mystery">Desconocidos/Mistery</string>
- <string name="letterbox">Buzón híbrido</string>
- <string name="event">Eventos</string>
- <string name="mega">Mega-Eventos</string>
- <string name="giga">Caché Giga-Evento</string>
- <string name="earth">Educativos (Earth)</string>
+ <string name="all_types">Todos los cachés</string>
+ <string name="traditional">Tradicional</string>
+ <string name="multi">Multi</string>
+ <string name="mystery">Mistery</string>
+ <string name="letterbox">Letterbox híbrido</string>
+ <string name="event">Evento</string>
+ <string name="mega">Mega Evento</string>
+ <string name="giga">Giga Evento</string>
+ <string name="earth">Earthcaché</string>
<string name="cito">Eventos Limpieza(CITO)</string>
- <string name="webcam">Webcams</string>
- <string name="virtual">Virtuales</string>
+ <string name="webcam">Webcam</string>
+ <string name="virtual">Virtual</string>
<string name="wherigo">Wherigo</string>
- <string name="lostfound">Eventos Perdidos y Encontrados</string>
+ <string name="lostfound">Evento Lost &amp; Found</string>
<string name="ape">Proyecto APE</string>
<string name="gchq">Groundspeak HQ</string>
- <string name="gps">Exhibición de escondites GPS</string>
+ <string name="gps">Exhibición de cachés GPS</string>
<string name="block">Groundspeak Block Party</string>
<string name="unknown">De tipo desconocido</string>
- <string name="cache_size_micro">micro</string>
- <string name="cache_size_small">pequeño</string>
- <string name="cache_size_regular">normal</string>
- <string name="cache_size_large">grande</string>
- <string name="cache_size_other">otro</string>
- <string name="cache_size_virtual">virtual</string>
- <string name="cache_size_notchosen">no elegido</string>
- <string name="cache_size_unknown">desconocido</string>
+ <string name="cache_size_micro">Micro</string>
+ <string name="cache_size_small">Pequeño</string>
+ <string name="cache_size_regular">Normal</string>
+ <string name="cache_size_large">Grande</string>
+ <string name="cache_size_other">Otro</string>
+ <string name="cache_size_virtual">Virtual</string>
+ <string name="cache_size_notchosen">No elegido</string>
+ <string name="cache_size_unknown">Desconocido</string>
<string name="cache_size_nano">Nano</string>
<string name="cache_size_very_large">Muy grande</string>
<string name="wp_final">Ubicación final</string>
- <string name="wp_stage">Etapa de multi escondite</string>
+ <string name="wp_stage">Etapa de un Multicaché</string>
<string name="wp_puzzle">Preguntar a contestar</string>
<string name="wp_pkg">Zona de aparcamiento</string>
<string name="wp_trailhead">Sendero</string>
@@ -56,7 +56,7 @@
<string name="log_attended">Asistí</string>
<string name="log_retrieved">Recogido</string>
<string name="log_placed">Depositado</string>
- <string name="log_grabbed">Recogido de alguna parte</string>
+ <string name="log_grabbed">Cogido de otro sitio</string>
<string name="log_movecollection">Mover a la colección</string>
<string name="log_moveinventory">Mover al inventario</string>
<string name="log_maintained">Mantenimiento efectuado</string>
@@ -68,18 +68,23 @@
<string name="log_discovered">Descubierto</string>
<string name="log_reviewer">Nota del revisor</string>
<string name="log_submit_for_review">Enviar para revisión</string>
- <string name="log_retractlisting">Retirar ficha del escondite</string>
+ <string name="log_retractlisting">Retirar ficha</string>
<string name="log_marked_missing">Marcado como perdido</string>
<string name="log_tb_nothing">No hacer nada</string>
<string name="log_tb_visit">Visitado</string>
<string name="log_tb_drop">Dejar aquí</string>
<string name="log_tb_changeall">Cambiar todo</string>
- <string name="log_save">Guardar</string>
- <string name="log_saving">Enviando registo…</string>
+ <string name="log_tb_note">Nota</string>
+ <string name="log_tb_discovered">Descubierto</string>
+ <string name="log_tb_archived">Archivado</string>
+ <string name="log_save">Guardar sin conexión</string>
+ <string name="log_saving">Enviando registro…</string>
<string name="log_saving_and_uploading">Enviando registro y subiendo imagen…</string>
<string name="log_clear">Limpiar</string>
<string name="log_post_not_possible">Cargando página de registro…</string>
+ <string name="log_date_future_not_allowed">No se permiten registros con fechas futuras.</string>
<string name="log_add">Añadir</string>
+ <string name="log_repeat">Repetir el último registro</string>
<string name="log_no_rating">Sin puntuación</string>
<string name="log_stars_1_description">malísimo</string>
<string name="log_stars_15_description">muy malo</string>
@@ -107,6 +112,7 @@
<string name="log_password_title">Contraseña:</string>
<string name="log_hint_log_password">Introduzca su contraseña</string>
<string name="log_oc_team_comment">Comentario equipo OC</string>
+ <string name="log_your_saved_log">Tu registro guardado</string>
<string-array name="log_image_scales">
<item>Sin redimensionar</item>
<item>512 px</item>
@@ -121,74 +127,78 @@
<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_server_ec">Imposible conectar a Extremcaching.com. La página web puede estar caída o su conexión a Internet no funciona.</string>
+ <string name="err_server_gk">No se pudo contactar con Geokrety.org. El sitio web puede estar caído o la conexión a internet no funciona.</string>
<string name="err_login">No hay información de acceso guardada</string>
- <string name="err_login_failed_toast">c:geo no puede iniciar sesión. c:geo puede funcionar sin conexión con los caches que hayan sido almacenados. Comprueba las opciones de inicio de sesión o active la conexión a internet.</string>
+ <string name="err_login_failed_toast">c:geo no puede iniciar sesión. c:geo puede funcionar sin conexión con los cachés que hayan sido almacenados. Comprueba las opciones de inicio de sesión o active la conexión a internet.</string>
<string name="err_unknown">Error desconocido</string>
+ <string name="err_unknown_address">c:geo no ha podido ubicar en el mapa esta dirección</string>
<string name="err_comm">Error de comunicación desconocido</string>
<string name="err_missing_auth">Falta nombre de usuario o contraseña.</string>
<string name="err_wrong">Información de acceso errónea</string>
<string name="err_maintenance">Geocaching.com no está disponible debido a labores de mantenimiento. c:geo puede funcionar sin conexión con los caches que hayan sido almacenados previamente.</string>
- <string name="err_license">El usuario no ha aceptado las condiciones de Geocaching.com license agreement, por lo que c:geo no puede cargar las coordenadas de los escondites.</string>
+ <string name="err_license">No has aceptado las condiciones del acuerdo de licencia de Geocaching.com, por lo que c:geo no puede cargar las coordenadas de los cachés.</string>
<string name="err_unvalidated_account">Antes debe validar su cuenta en la página web Geocaching.com.</string>
<string name="err_unpublished">El caché solicitado aún no ha sido publicado.</string>
<string name="err_premium_only">Este caché solo está disponible para los miembros Premium de Geocaching.com.</string>
- <string name="err_detail_open">Lo siento, c:geo no puede abrir los detalles del escondite.</string>
- <string name="err_detail_cache">Lo siento, c:geo no puee mostrar el escondite que quieres. ¿Segur que es un geocache?</string>
- <string name="err_detail_cache_find">Lo siento, c:geo no puede encontrar escondites</string>
- <string name="err_detail_cache_find_some">Lo siento, c:geo no puede encontrar ese escondite.</string>
- <string name="err_detail_cache_find_any">Lo siento, c:geo no puede encontrar algunos escondites.</string>
+ <string name="err_detail_open">c:geo no puede abrir los detalles del caché.</string>
+ <string name="err_detail_cache">c:geo no puede mostrar el caché que quieres. ¿Seguro que es un geocaché?</string>
+ <string name="err_detail_cache_find">c:geo no puede encontrar ningún caché</string>
+ <string name="err_detail_cache_find_some">c:geo no puede encontrar ese caché.</string>
+ <string name="err_detail_cache_find_any">c:geo no puede encontrar ningún caché.</string>
<string name="err_detail_google_maps_limit_reached">c:geo no ha podido descargar los mapas estáticos. Quizá haya alcanzado el límite de uso del API de Google Maps.</string>
- <string name="err_detail_no_spoiler">c:geo no ha encontrado imágenes/pista para este escondite.</string>
- <string name="err_detail_no_map_static">c:geo no ha encontrado mapas estáticos para este escondite.</string>
- <string name="err_detail_not_load_map_static">Lo siento, c:geo no ha podido cargar mapas estáticos.</string>
+ <string name="err_detail_no_spoiler">c:geo no ha encontrado imágenes/pista para este caché.</string>
+ <string name="err_detail_no_map_static">c:geo no ha encontrado mapas estáticos para este caché.</string>
+ <string name="err_detail_not_load_map_static">c:geo no ha podido cargar los mapas estáticos.</string>
<string name="err_detail_still_working">Todavía hay otra tarea en ejecución.</string>
- <string name="err_watchlist_still_managing">Seguir gestionando tu lista de seguimiento.</string>
+ <string name="err_watchlist_still_managing">Todavía gestionando tu lista de seguimiento.</string>
<string name="err_watchlist_failed">Error al cambiar la lista de seguimiento.</string>
<string name="err_application_no">c:geo no encuentra ninguna aplicación válida.</string>
- <string name="err_auth_initialize">Lo siento, c:geo no ha podido iniciar el proceso de autorización.</string>
+ <string name="err_auth_initialize">c:geo no ha podido iniciar el proceso de autorización.</string>
<string name="err_auth_process">El proceso de autorización ha fallado.</string>
- <string name="err_cannot_log_visit">c:geo no tiene información suficiente para registrar la visita. Inténtalo de nuevo con más detalles sobre el escondite.</string>
- <string name="err_download_fail">Lo siento, c:geo no ha podido descargar escondites a causa de </string>
- <string name="err_dwld_details_failed">Lo siento, c:geo no ha podido descargar los detalles del escondite.</string>
- <string name="err_load_descr_failed">Lo siento, c:geo no ha podido cargar la descripción.</string>
- <string name="err_location_unknown">c:geo no conoce la ubicación del escondite.</string>
+ <string name="err_cannot_log_visit">c:geo no puede registrar tu visita. Inténtalo desde la pantalla de detalles del caché.</string>
+ <string name="err_download_fail">c:geo no ha podido descargar cachés.</string>
+ <string name="err_dwld_details_failed">c:geo no ha podido descargar los detalles del caché.</string>
+ <string name="err_load_descr_failed">c:geo no ha podido cargar la descripción.</string>
+ <string name="err_location_unknown">c:geo no conoce la ubicación del caché.</string>
<string name="err_missing_device_name">Debes indicar un nombre de dispositivo antes de registrarte.</string>
<string name="err_favorite_failed">Falló el cambio de estado de favorito.</string>
<string name="err_select_logimage_failed">No se pudo seleccionar una imagen para el registro.</string>
<string name="err_acquire_image_failed">No se pudo obtener una imagen.</string>
- <string name="err_tb_display">\"Lo siento, c:geo no puede mostrar el rastreable que buscas. ¿Es realmente rastreable?</string>
- <string name="err_tb_details_open">Lo siento, c:geo no puede abrir los detalles del rastreable.</string>
- <string name="err_tb_forgot_saw">Lo siento, c:geo ha olvidado qué rastreable has visto.</string>
- <string name="err_tb_find">Lo siento, c:geo no encuentra el rasteable</string>
- <string name="err_tb_find_that">Lo siento, c:geo no encuentra ese rastreable.</string>
- <string name="err_waypoint_cache_unknown">Lo siento, c:geo no sabe a qué escondite quieres añadir un punto de referencia.</string>
- <string name="err_waypoint_add_failed">Lo siento, c:geo no ha podido añadir tu punto de referencia.</string>
- <string name="err_point_unknown_position">Lo siento, c:geo n puedo identificar donde estás.</string>
+ <string name="err_tb_display">c:geo no puede mostrar el rastreable que buscas. ¿Es realmente un rastreable?</string>
+ <string name="err_tb_details_open">c:geo no puede abrir los detalles del rastreable.</string>
+ <string name="err_tb_not_loggable">Este rastreable no se puede registrar.</string>
+ <string name="err_tb_find">c:geo no encuentra el rasteable</string>
+ <string name="err_tb_find_that">c:geo no encuentra ese rastreable.</string>
+ <string name="err_waypoint_cache_unknown">c:geo no sabe a qué caché quieres añadir un punto de referencia.</string>
+ <string name="err_waypoint_add_failed">c:geo falló al añadir tu punto de referencia.</string>
+ <string name="err_point_unknown_position">c:geo no puede reconocer dónde estás.</string>
<string name="err_point_no_position_given_title">Información obligatoria</string>
<string name="err_point_no_position_given">Rellena como mínimo latitud y longitud o distancia y orientación. También puedes rellenar los cuatro campos.</string>
- <string name="err_point_curr_position_unavailable">c:geo sigue sin obtener las coordenadas actuales. Espera un poco mas…</string>
<string name="err_point_bear_and_dist_title">¿Necesitas ayuda?</string>
<string name="err_point_bear_and_dist">Rellena ambos, orientación y distancia. La orientación es un ángulo de 0 a 360 grados relativo al norte. Distancia con o sin unidades.</string>
- <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_post_failed">Lo siento, c:geo no ha podido enviar el registro.</string>
- <string name="err_log_post_failed_ec">Parece ser que su registro no ha sido publicado. Por favor compruébelo en Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Parece que su imagen de registro no se ha enviado al servidor. Compruébelo en Geocaching.com.</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>
- <string name="err_parse_lon">Lo siento, c:geo no puede procesar la longitud.</string>
- <string name="err_parse_dist">Lo siento, c:geo can\'t no puede procesar la distancia.</string>
+ <string name="err_log_load_data">c:geo no puede cargar los datos necesarios para registrar la visita.</string>
+ <string name="err_log_load_data_again">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 caché. Debes esperar un poquito más.</string>
+ <string name="err_log_post_missing_tracking_code">Falta el código rastreable.</string>
+ <string name="err_log_post_missing_coordinates">Faltan las coordenadas.</string>
+ <string name="err_log_post_failed">Parece que tu registro no ha sido publicado. Compruébalo en la página original del caché.</string>
+ <string name="err_log_post_failed_ec">Parece que su registro no ha sido publicado. Por favor compruébalo en Extremcaching.com.</string>
+ <string name="err_log_post_failed_gk">Parece que su registro no ha sido publicado. Por favor compruébalo en geokrety.org.</string>
+ <string name="err_logimage_post_failed">Parece que tu imagen no se ha subido. Compruébalo en la página original del caché.</string>
+ <string name="err_search_address_forgot">c:geo ha olvidado la dirección que buscabas.</string>
+ <string name="err_parse_lat">c:geo no puede procesar la latitud.</string>
+ <string name="err_parse_lon">c:geo no puede procesar la longitud.</string>
+ <string name="err_parse_dist">c:geo no puede procesar la distancia.</string>
<string name="err_parse_lat_lon">c:geo no ha podido interpretar la latitud o la longitud.</string>
<string name="warn_save_nothing">No hay nada para guardar.</string>
- <string name="warn_no_cache_coord">No hay escondite con coordenadas.</string>
+ <string name="warn_no_cache_coord">No hay cachés con coordenadas.</string>
<string name="warn_no_coordinates">No se han dado coordenadas.</string>
<string name="warn_no_keyword">No se ha indicado ninguna palabra clave.</string>
<string name="warn_no_username">No se ha indicado nombre de usuario.</string>
<string name="warn_search_help_title">¿Necesitas ayuda?</string>
<string name="warn_search_help_address">\"Rellena la dirección o el nombre del lugar. Por ejemplo usa la dirección \"Gran Vía 100, Vigo, España\", nombre de la ciudad \"Pontevedra\" o nombra a algo como \"Lagunas de Ruidera\".</string>
- <string name="warn_search_help_gccode">Indica el código del escondite. Por ejemplo \"GC1VCAZ\".</string>
- <string name="warn_search_help_keyword">Escribe algo que se suponga que está contenido en el nombre del escondite que buscas.</string>
+ <string name="warn_search_help_gccode">Indica el código del caché. Por ejemplo \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Escribe todo o parte del nombre del caché. Por ejemplo \"Caché nocturno\".</string>
<string name="warn_search_help_user">Escribe el nombre de usuario de Geocaching.com.</string>
<string name="warn_search_help_tb">Escribe el código del rastreable. Por ejemplo \"TB29QMZ\".</string>
<string name="warn_log_text_fill">Escribe algún texto de registro.</string>
@@ -199,8 +209,8 @@
<string name="warn_rendertheme_missing">No se ha encontrado el esquema de colores del mapa.</string>
<string name="warn_pocket_query_select">No ha seleccionado ninguna Pocket Query.</string>
<string name="warn_no_pocket_query_found">No se ha encontrado ninguna Pocket Query en Geocaching.com.</string>
- <string name="info_log_posted">c:geo registro enviado sin problemas.</string>
- <string name="info_log_saved">c:geo guardado sin problemas.</string>
+ <string name="info_log_posted">c:geo envió el registro sin problemas.</string>
+ <string name="info_log_saved">c:geo guardó el registro sin problemas.</string>
<string name="info_log_cleared">Registro borrado.</string>
<string name="info_log_type_changed">¡El tipo de registro ha sido cambiado!</string>
<string name="info_select_logimage_cancelled">La selección de imagen o captura ha sido cancelada.</string>
@@ -211,6 +221,7 @@
<string name="loc_net">Red</string>
<string name="loc_fused">Combinado</string>
<string name="loc_low_power">Ahorro de energía</string>
+ <string name="loc_home">Coordenadas de casa</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Intentando ubicar</string>
@@ -220,58 +231,65 @@
<string name="menu_about">Sobre c:geo</string>
<string name="menu_helpers">Programas útiles</string>
<string name="menu_settings">Ajustes</string>
- <string name="menu_history">Historia</string>
+ <string name="menu_history">Historial</string>
<string name="menu_filter">Filtro</string>
<string name="menu_scan_geo">Escánear geocódigo</string>
- <string name="menu_pocket_queries">Pocket queries</string>
+ <string name="menu_pocket_queries">Pocket Queries</string>
<string name="menu_scan_description">c:geo puede escanear geocódigos que están impresos como código QR. La aplicación necesaria no está instalada. ¿Quiere abrir Google Play para instalarlo?</string>
<string name="live_map_button">Mapa</string>
<string name="caches_nearby_button">Cercanos</string>
<string name="advanced_search_button">Buscar</string>
<string name="stored_caches_button">Guardados</string>
- <string name="any_button">Manual</string>
+ <string name="any_button">Ir a</string>
<string name="unknown_scan">No se ha encontrado ningún geocódigo en la imagen.</string>
- <string name="caches_no_cache">Ningún escondite</string>
- <string name="caches_more_caches">Buscar mas</string>
- <string name="caches_more_caches_no">No hay mas escondites</string>
- <string name="caches_more_caches_loading">Cargando escondites…</string>
+ <string name="caches_no_cache">Ningún caché</string>
+ <string name="caches_more_caches">Cargar más cachés</string>
+ <string name="caches_more_caches_no">No hay más cachés</string>
+ <string name="caches_more_caches_loading">Cargando cachés…</string>
<string name="caches_more_caches_currently">actualmente</string>
- <string name="caches_downloading">Descargando escondites…\nFaltan: </string>
+ <string name="caches_downloading">Descargando cachés…\nFaltan: </string>
<string name="caches_eta_ltm">Menos de un minuto</string>
<plurals name="caches_eta_mins">
<item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
</plurals>
<string name="caches_store_offline">Usar sin conexión luego</string>
- <string name="caches_store_selected">Almacenamiento seleccionado</string>
+ <string name="caches_store_selected">Guardar seleccionados</string>
<string name="caches_history">Historial</string>
<string name="caches_on_map">Ver en mapa</string>
<string name="caches_sort">Ordenar</string>
- <string name="caches_sort_distance">distancia</string>
- <string name="caches_sort_difficulty">dificultad</string>
- <string name="caches_sort_terrain">terreno</string>
- <string name="caches_sort_size">tamaño</string>
+ <string name="caches_sort_distance">Distancia</string>
+ <string name="caches_sort_difficulty">Dificultad</string>
+ <string name="caches_sort_terrain">Terreno</string>
+ <string name="caches_sort_size">Tamaño</string>
<string name="caches_sort_favorites">Favoritos</string>
<string name="caches_sort_favorites_ratio">Favoritos [%]</string>
- <string name="caches_sort_name">nombre</string>
- <string name="caches_sort_geocode">Código</string>
- <string name="caches_sort_rating">valoración</string>
- <string name="caches_sort_vote">votar (valoración propia)</string>
- <string name="caches_sort_inventory">recuento de inventario</string>
- <string name="caches_sort_date_hidden">fecha</string>
+ <string name="caches_sort_name">Nombre</string>
+ <string name="caches_sort_geocode">Código GC</string>
+ <string name="caches_sort_rating">Valoración</string>
+ <string name="caches_sort_vote">Votos (valoración propia)</string>
+ <string name="caches_sort_inventory">Recuento de inventario</string>
+ <string name="caches_sort_date_hidden">Fecha escondido</string>
<string name="caches_sort_date_logged">Fecha de registro</string>
<string name="caches_sort_finds">Encontrados</string>
<string name="caches_sort_state">Estado</string>
- <string name="caches_sort_storage">Fecha almacenada en el dispositivo</string>
+ <string name="caches_sort_storage">Fecha de guardado en dispositivo</string>
+ <string name="caches_sort_eventdate">Fecha del evento</string>
<string name="caches_select_mode">Modo selección</string>
<string name="caches_select_mode_exit">Salir de modo selección</string>
<string name="caches_select_invert">Invertir selección</string>
<string name="caches_nearby">Cercanos</string>
<string name="caches_manage">Gestionar</string>
<string name="caches_remove_all">Eliminar todos</string>
- <string name="caches_remove_all_confirm">¿Desea eliminar todos los cachés (%s) de la lista actual?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">¿Quieres eliminar este caché de la lista actual?</item>
+ <item quantity="other">¿Quieres eliminar los %d cachés de la lista actual?</item>
+ </plurals>
<string name="caches_remove_selected">Eliminar los seleccionados</string>
- <string name="caches_remove_selected_confirm">¿Desea eliminar los %s cachés seleccionados de su dispositivo?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">¿Quieres eliminar este caché del dispositivo?</item>
+ <item quantity="other">¿Quieres eliminar los %d cachés seleccionados del dispositivo?</item>
+ </plurals>
<string name="caches_remove_progress">Eliminando los cachés</string>
<string name="caches_delete_events">Borrar eventos pasados</string>
<string name="caches_refresh_selected">Actualizar seleccionados</string>
@@ -281,37 +299,42 @@
<string name="caches_map_locus">Locus</string>
<string name="caches_map_locus_export">Exportar a Locus</string>
<string name="caches_recaptcha_title">reCAPTCHA</string>
- <string name="caches_recaptcha_explanation">Debes escribir el texto de la imagen. Es importante que descargues las coordenadas de los escondites. Es opcional y lo puedes desactivar en Ajustes.</string>
+ <string name="caches_recaptcha_explanation">Por favor escribe el texto de la imagen. Esto permite descargar las coordenadas de los cachés. Es opcional y lo puedes desactivar en Ajustes.</string>
<string name="caches_recaptcha_hint">Texto de la imagen</string>
<string name="caches_recaptcha_continue">Continuar</string>
<string name="caches_filter">Filtrar</string>
<string name="caches_filter_title">Filtrar por</string>
- <string name="caches_filter_size">tamaño</string>
- <string name="caches_filter_type">tipo</string>
- <string name="caches_filter_track">con rastreables</string>
- <string name="caches_filter_clear">limpiar filtros</string>
+ <string name="caches_filter_size">Tamaño</string>
+ <string name="caches_filter_type">Tipo</string>
+ <string name="caches_filter_track">Con rastreables</string>
+ <string name="caches_filter_clear">Limpiar filtros</string>
<string name="caches_filter_modified">Con las coordenadas modificadas</string>
+ <string name="caches_filter_offline_log">Con registro sin conexión</string>
<string name="caches_filter_origin">Coordenadas originales</string>
<string name="caches_filter_distance">Distancia</string>
<string name="caches_filter_personal_note">Con nota personal</string>
<string name="caches_filter_popularity">Favoritos</string>
<string name="caches_filter_popularity_ratio">Favoritos [%]</string>
+ <string name="caches_filter_personal_data">Con datos personales</string>
+ <string name="caches_filter_rating">Con puntuación</string>
+ <string name="caches_filter_own_rating">Con puntuación propia</string>
<string name="caches_removing_from_history">Borrando del historial…</string>
<string name="caches_clear_offlinelogs">Borrar registros sin conexión</string>
+ <string name="caches_clear_offlinelogs_message">¿Quieres borrar los registros sin conexión?</string>
<string name="caches_clear_offlinelogs_progress">Borrando registros sin conexión</string>
<string name="list_menu_create">Crear nueva lista</string>
<string name="list_menu_drop">Borrar lista actual</string>
<string name="list_menu_rename">Renombrar la lista actual</string>
<string name="list_menu_import">Importar</string>
<string name="list_title">Escoger lista</string>
- <string name="list_inbox">Guardadas</string>
- <string name="list_all_lists">Todos los caches</string>
+ <string name="list_inbox">Guardados</string>
+ <string name="list_all_lists">Todos los cachés</string>
<string name="list_dialog_create_title">Nueva lista</string>
<string name="list_dialog_create">Crear</string>
<string name="list_dialog_create_ok">Se ha creado una nueva lista</string>
<string name="list_dialog_create_err">c:geo no ha podido crear la lista</string>
<string name="list_dialog_remove_title">Borrar lista</string>
- <string name="list_dialog_remove_description">¿Quieres borrar esta lista de escondites? Todos los escondites de la lilsta serán movidos a \"Guardados\".</string>
+ <string name="list_dialog_remove_description">¿Quieres borrar la lista actual? Todos los cachés de la lista serán movidos a \"Guardados\".</string>
<string name="list_dialog_remove">Borrar</string>
<string name="list_dialog_remove_ok">La lista ha sido borrada</string>
<string name="list_dialog_remove_err">c:geo no ha podido borrar la lista actual</string>
@@ -320,17 +343,21 @@
<string name="list_not_available">La lista ya no está disponible, cambiando a la lista estándar</string>
<string name="about_version">Versión</string>
<string name="about_changelog">Cambios</string>
+ <string name="about_system">Sistema</string>
<string name="about_donate">Donar</string>
- <string name="about_donation_more">Donar\nmas</string>
+ <string name="about_donation_more">Donar para el\ndesarrollo de c:geo</string>
<string name="about_contributors">Colaboradores</string>
<string name="about_license">Licencia</string>
<string name="about_apache_license"><a href="">Licencia Apache, Versión 2.0</a></string>
<string name="about_help">Ayuda</string>
+ <string name="about_system_include">Por favor, incluya la siguiente información del sistema cuando envíe un informe de error o pida más información sobre c:geo:</string>
+ <string name="changelog_github">Lista de todos los cambios</string>
<string name="settings_title_services">Servicios</string>
+ <string name="settings_summary_services">Configura la información de la cuenta de usuario y accede a servicios opcionales.</string>
<string name="settings_title_appearance">Aspecto</string>
- <string name="settings_title_cachedetails">Detalles del cache</string>
+ <string name="settings_title_cachedetails">Detalles del caché</string>
<string name="settings_title_offlinedata">Datos sin conexión</string>
- <string name="settings_title_logging">Registrar</string>
+ <string name="settings_title_logging">Registro</string>
<string name="settings_title_map">Mapa</string>
<string name="settings_title_map_data">Datos del mapa</string>
<string name="settings_title_map_content">Contenido del mapa</string>
@@ -348,24 +375,27 @@
<string name="settings_activate_ec">Activar</string>
<string name="settings_activate_ox">Activar</string>
<string name="settings_gc_legal_note">Usando el servicio de geocaching.com, usted acepta los términos de uso de Groundspeak.</string>
- <string name="settings_info_facebook_login_title">Facebook Login</string>
+ <string name="settings_info_facebook_login_title">Conectarse con Facebook</string>
<string name="settings_info_facebook_login">No puedes iniciar sesión en geocaching.com desde c:geo con tu cuenta de Facebook. Pero esto se puede solucionar con un simple truco…</string>
<string name="settings_authorize">Autorizar c:geo</string>
<string name="settings_reauthorize">Autorizar c:geo otra vez</string>
<string name="init_oc">Opencaching.de</string>
<string name="settings_activate_oc">Activar</string>
- <string name="init_oc_de_description">Autorizar que c:geo pueda usar opencaching.de para buscar caches y acceder a / filtrar tus caches encontrados.</string>
+ <string name="init_oc_de_description">Autorizar que c:geo pueda usar opencaching.de para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="settings_activate_oc_pl">Activar</string>
- <string name="init_oc_pl_description">Autorizar que c:geo pueda usar opencaching.pl para buscar caches y acceder a / filtrar tus caches encontrados.</string>
+ <string name="init_oc_pl_description">Autorizar que c:geo pueda usar opencaching.pl para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="settings_activate_oc_nl">Activar</string>
- <string name="init_oc_nl_description">Autorizar que c:geo pueda usar opencaching.nl para buscar caches y acceder a / filtrar tus caches encontrados.</string>
+ <string name="init_oc_nl_description">Autorizar que c:geo pueda usar opencaching.nl para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="settings_activate_oc_us">Activar</string>
- <string name="init_oc_us_description">Autorizar que c:geo pueda usar opencaching.us para buscar caches y acceder a / filtrar tus caches encontrados.</string>
+ <string name="init_oc_us_description">Autorizar que c:geo pueda usar opencaching.us para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="settings_activate_oc_ro">Activar</string>
- <string name="init_oc_ro_description">Autorizar que c:geo pueda usar opencaching.ro para buscar caches y acceder a / filtrar tus caches encontrados.</string>
+ <string name="init_oc_ro_description">Autorizar que c:geo pueda usar opencaching.ro para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="settings_activate_oc_uk">Activar</string>
- <string name="init_oc_uk_description">Autorizar que c:geo pueda usar opencaching.org.uk para buscar caches y acceder a / filtrar tus cachés encontrados.</string>
+ <string name="init_oc_uk_description">Autorizar que c:geo pueda usar opencaching.org.uk para buscar cachés y acceder a / filtrar tus cachés encontrados.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Para poder calificar un caché, tienes que seguir las instrucciones en GCVote.com e introducir tu contraseña de GCVote aquí.</string>
+ <string name="err_gcvote_send_rating">Error al enviar la calificación, comprueba tu contraseña de GCVote en configuración o déjala en blanco.</string>
+ <string name="gcvote_sent">Voto enviado con éxito</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activar</string>
<string name="init_username">Usuario</string>
@@ -392,71 +422,73 @@
<string name="init_signature_template_name">Nombre</string>
<string name="init_signature_template_url">URL</string>
<string name="init_signature_template_log">Texto de registro</string>
- <string name="init_ratingwanted">Clasificación de GCvote</string>
+ <string name="init_ratingwanted">Puntuación de GCvote</string>
<string name="init_summary_ratingwanted">Cargar la puntuación del cache desde GCvote.com</string>
- <string name="init_friends_and_own_logs_wanted">Mostrar logs de amigos / propios</string>
- <string name="init_summary_friends_and_own_logs_wanted">Mostrar una página adicional para los logs de amigos y propios</string>
- <string name="init_openlastdetailspage">Detalles de la última página</string>
- <string name="init_summary_openlastdetailspage">Recordar última vista usada al consultar los detalles del cache</string>
- <string name="init_autoload">Autocargar descripción larga</string>
+ <string name="init_friends_and_own_logs_wanted">Mostrar amigos / propios</string>
+ <string name="init_summary_friends_and_own_logs_wanted">Mostrar una página adicional para los registros de amigos y propios</string>
+ <string name="init_openlastdetailspage">Recordar última página</string>
+ <string name="init_summary_openlastdetailspage">Mostrar última página vista al consultar los detalles del caché</string>
+ <string name="init_autoload">Descripción larga</string>
<string name="init_summary_autoload">Autocargar descripción larga</string>
- <string name="init_skin">Fondo blanco (necesita reiniciar c:geo)</string>
- <string name="init_summary_skin">Fondo blanco (necesita reiniciar c:geo)</string>
- <string name="init_address">Mostrar dirección en lugar de posición en la pantalla principal</string>
- <string name="init_summary_address">Mostrar dirección en lugar de posición en la pantalla principal</string>
- <string name="init_captcha">Mostrar CAPTCHA si es necesario</string>
- <string name="init_summary_captcha">Mostrar CAPTCHA si es necesario</string>
- <string name="init_useenglish">Usar inglés interno (necesita reiniciar c:geo)</string>
- <string name="init_summary_useenglish">Usar inglés interno (necesita reiniciar c:geo)</string>
+ <string name="init_skin">Fondo blanco</string>
+ <string name="init_summary_skin">Usar fondo blanco (necesitas reiniciar c:geo)</string>
+ <string name="init_address">Mostrar dirección</string>
+ <string name="init_summary_address">Mostrar dirección en lugar de coordenadas en la pantalla principal</string>
+ <string name="init_captcha">Mostrar CAPTCHA</string>
+ <string name="init_summary_captcha">Mostrar CAPTCHA si es necesario (sólo miembros básicos)</string>
+ <string name="init_useenglish">Usar inglés</string>
+ <string name="init_summary_useenglish">Usar c:geo en inglés (se necesita reiniciar)</string>
<string name="init_exclude">Excluir encontrados y propios</string>
- <string name="init_summary_exclude">Excluir encontrados y propios</string>
+ <string name="init_summary_exclude">Excluir cachés ya encontrados y propios</string>
<string name="init_showwaypoints">Mostrar Waypoints</string>
- <string name="init_showwaypoint_description">Mostar los puntos de referencia de los caches mostrados si en el mapa se hay menos caches que la cantidad indicada.</string>
- <string name="init_disabled">Excluir escondites desactivados</string>
- <string name="init_summary_disabled">Excluir escondites desactivados</string>
- <string name="init_offline">Guardar mapas para usar sin conexión</string>
- <string name="init_summary_offline">Guardar mapas para usar sin conexión</string>
+ <string name="init_showwaypoint_description">Mostrar los waypoints de los cachés si en el mapa se muestran menos cachés que el número seleccionado.</string>
+ <string name="init_disabled">Excluir desactivados</string>
+ <string name="init_summary_disabled">Excluir cachés desactivados</string>
+ <string name="init_offline">Mapas estáticos</string>
+ <string name="init_summary_offline">Guardar mapas estáticos de los cachés para usar sin conexión</string>
<string name="init_offline_wp">Mapas estáticos (WP)</string>
<string name="init_summary_offline_wp">Guardar waypoints en los mapas estáticos para su uso sin conexión</string>
- <string name="init_save_log_img">Guardar imágenes de los registros</string>
+ <string name="init_save_log_img">Guardar imágenes</string>
<string name="init_summary_save_log_img">Guardar imágenes de los registros</string>
- <string name="init_units">Usar millas/pies (unidades imperiales)</string>
+ <string name="init_units">Usar millas/pies</string>
<string name="init_summary_units">Usar millas/pies (unidades imperiales)</string>
- <string name="init_log_offline">Log sin conexión</string>
+ <string name="init_log_offline">Registro sin conexión</string>
<string name="init_summary_log_offline">Permitir el registro sin conexión (No se mostrará la pantalla de registro en línea ni se enviarán los logs)</string>
- <string name="init_choose_list">Pida lista</string>
- <string name="init_summary_choose_list">Pregunte qué lista para almacenar en caché</string>
- <string name="init_livelist">Mostrar dirección a los escondites en su listado</string>
- <string name="init_summary_livelist">Mostrar dirección a los escondites en su listado</string>
- <string name="init_backup">Backup</string>
+ <string name="init_choose_list">Preguntar lista</string>
+ <string name="init_summary_choose_list">Preguntar en qué lista guardar el caché</string>
+ <string name="init_livelist">Mostrar dirección</string>
+ <string name="init_summary_livelist">Mostrar la dirección de los cachés en la lista</string>
+ <string name="init_backup">Copia de seguridad</string>
<string name="init_backup_backup">Copia de seguridad</string>
<string name="init_backup_running">Creando copia de seguridad de la base de datos de cachés…</string>
- <string name="init_backup_note">Esta opción copia/restaura la base de datos de escondites y puntos de referencia, no la configuración. Los datos de acceso y contraseña no se guardarán.</string>
+ <string name="init_backup_note">Esta opción copia/restaura la base de datos de cachés y puntos de referencia, no la configuración.\nTus datos de acceso y contraseña no se guardarán.</string>
<string name="init_backup_restore">Restaurar</string>
- <string name="init_backup_success">La base de datos de c:geo se ha copiado satisfactoriamente</string>
+ <string name="init_backup_success">La base de datos de c:geo se ha copiado a:</string>
<string name="init_backup_failed">Ha fallado la copia de seguridad.</string>
<string name="init_backup_unnecessary">La base de datos está vacía, no es necesaria una copia de seguridad.</string>
+ <string name="backup_confirm_overwrite">¿Quieres sobreescribir la copia de seguridad existente de %s?</string>
+ <string name="restore_confirm_overwrite">¿Quieres sobreescribir %s en tu dispositivo con la copia de seguridad?</string>
<string name="init_restore_success">Restauración completa.</string>
- <string name="init_restore_failed">Restauración errónea</string>
+ <string name="init_restore_failed">Restauración errónea.</string>
<string name="init_restore_running">Restaurando la base de datos de cachés…</string>
<string name="init_restore_confirm">La base de datos está vacia. ¿Desea restaurar la copia de seguridad de la base de datos?</string>
<string name="init_backup_last">Copia guardada el</string>
<string name="init_backup_last_no">No hay ninguna copia de seguridad.</string>
- <string name="settings_info_offline_maps_title">Información sobre mapas sin conexión</string>
- <string name="settings_info_offline_maps">c:geo permite mapas de uso sin conexión. Puedes descargar mapas desde Mapsforge o incluso crear los tuyos propios desde los datos de OSM (Open Street Map). Necesitas seleccionar primero el directorio de mapas sin conexión para obtener soporte para mapas sin conexión.</string>
+ <string name="settings_info_offline_maps_title">Mapas sin conexión</string>
+ <string name="settings_info_offline_maps">c:geo permite el uso de mapas sin conexión. Puedes descargar mapas desde Mapsforge o incluso crear los tuyos propios desde los datos de OSM (Open Street Map). Necesitas seleccionar primero el directorio con los mapas sin conexión para poder usarlos.</string>
<string name="settings_info_themes_title">Información sobre temas de mapas</string>
<string name="settings_info_themes">c:geo permite personalizar los mapas sin conexión. Se puede usar para cambiar el estilo del color del mapa (p. ej. tener un mapa de visión nocturna) o para resatar ciertos objetos como carriles bici o líneas de altitud en el mapa.</string>
- <string name="init_mapsource_select">Elige proveedor de mapas</string>
+ <string name="init_mapsource_select">Elegir proveedor de mapas</string>
<string name="settings_title_scale_map_text">Escalar el texto del mapa</string>
<string name="settings_summary_scale_map_text">Escala el texto de los mapas sin conexión según los p.p.p. del dispositivo</string>
<string name="init_map_directory_description">Directorio de mapas sin conexión</string>
- <string name="init_gpx_exportdir">Directorio de exportación de GPX</string>
- <string name="init_gpx_importdir">Directorio de importación de GPX</string>
- <string name="init_maptrail">Mostrar rastro en el mapa</string>
+ <string name="init_gpx_exportdir">Directorio para exportar GPX</string>
+ <string name="init_gpx_importdir">Directorio para importar GPX</string>
+ <string name="init_maptrail">Mostrar rastro</string>
<string name="init_summary_maptrail">Muestra el rastro en el mapa</string>
<string name="init_share_after_export">Abrir el menú de compartir tras exportar GPX</string>
- <string name="init_trackautovisit">Convertir rastreables automáticamente a \"visita\"</string>
- <string name="init_summary_trackautovisit">Convertir rastreables automáticamente a \"visita\"</string>
+ <string name="init_trackautovisit">Convertir TBs a Visitado</string>
+ <string name="init_summary_trackautovisit">Convertir rastreables automáticamente a \"Visitado\"</string>
<string name="init_sigautoinsert">Insertar automáticamente</string>
<string name="init_loaddirectionimg">Imagen de dirección</string>
<string name="init_summary_loaddirectionimg">Descarga si es necesario las imágenes de las flechas direccionales (necesario solo para miembros básicos)</string>
@@ -476,11 +508,11 @@
<string name="init_dbmove_running">Moviendo base de datos</string>
<string name="init_dbmove_success">Base de datos movida con éxito.</string>
<string name="init_dbmove_failed">Error al mover la base de datos</string>
- <string name="init_plain_logs">Logs sencillos</string>
- <string name="init_summary_plain_logs">Muestra los logs sin usar colores</string>
+ <string name="init_plain_logs">Registros sencillos</string>
+ <string name="init_summary_plain_logs">Muestra los registros sin usar colores</string>
<string name="init_use_native_ua">Navegador de Android</string>
<string name="init_summary_use_native_ua">Identificarse como usuario Android. Resuelve algunos problemas de acceso cuando se usan ciertos proveedores de red.</string>
- <string name="init_rendertheme_folder">Mapa directorio de temas</string>
+ <string name="init_rendertheme_folder">Directorio de temas para mapas</string>
<string name="init_maintenance">Mantenimiento</string>
<string name="init_maintenance_directories_note">c:Geo almacena imágenes, registro de imágenes y otros archivos relacionados con una memoria caché en un directorio separado. En algunos casos (como importar/exportar la base de datos) este directorio puede contener archivos obsoletos, que aquí se pueden eliminar.</string>
<string name="init_maintenance_directories">Eliminar archivos huérfanos</string>
@@ -489,7 +521,7 @@
<string name="init_location_googleplayservices">Usar servicios de Google Play</string>
<string name="init_low_power">Modo ahorro energía</string>
<string name="init_low_power_note">El modo de ahorro de energía evita el uso del GPS y del giroscopio cuando no es necesaria una ubicación muy precisa, a costa de aumentar el tiempo para fijar los satélites.</string>
- <string name="init_low_power_mode">Activar modo ahorro de energía</string>
+ <string name="init_low_power_mode">Activar ahorro de energía</string>
<string name="init_create_memory_dump">Crear volcado de memoria</string>
<string name="init_memory_dump">Volcado de memoria</string>
<string name="init_memory_dumped">Memoria volcada a %s</string>
@@ -497,6 +529,7 @@
<string name="init_hardware_acceleration_note">La aceleración por hardware renderiza los elementos gráficos en pantalla de manera más rápida. Sin embargo en algunos dispositivos el sistema operativo Android contiene fallos y algunos textos pueden aparecer borrosos (especialmente caracteres en negrita). Inhabilita la aceleración por hardware si ocurriera esto.</string>
<string name="init_hardware_acceleration">Habilitar aceleración por hardware</string>
<string name="settings_open_website">Abrir el sitio web</string>
+ <string name="settings_open_geokretymap_website">Abrir el sitio web GeokretyMap.org</string>
<string name="settings_settings">Ajustes</string>
<string name="settings_information">Información</string>
<string name="settings_twitter_cache_message">Mensaje para caché encontrado</string>
@@ -510,7 +543,7 @@
<string name="feature_online_logging">Registro online</string>
<string name="feature_log_images">Adjuntar imágenes a los registros</string>
<string name="feature_watch_list">Lista de seguimiento</string>
- <string name="feature_own_coordinates">Almacenamiento de coordenadas modificadas</string>
+ <string name="feature_own_coordinates">Almacenar coordenadas modificadas</string>
<string name="feature_search_keyword">Buscar por palabra clave</string>
<string name="feature_search_live_map">Mapa en vivo</string>
<string name="feature_search_center">Búsqueda por posición</string>
@@ -523,28 +556,28 @@
<string name="map_source_osm_cyclemap">OSM: Cyclemap</string>
<string name="map_source_osm_offline">Offline</string>
<string name="init_sendToCgeo">Enviar a c:geo</string>
- <string name="settings_info_send2cgeo_title">Info de send2cgeo</string>
+ <string name="settings_info_send2cgeo_title">Sobre Enviar a c:geo</string>
<string name="init_sendToCgeo_name">Nombre de tu dispositivo</string>
- <string name="init_sendToCgeo_description">Enviar a c:geo (send2cgeo)te permite recibir escondites automáticamente desde la web de geocaching usando un complemento especialpara Firefox o Chrome. Antes de registrarte, te sugerimos que leas <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Sólo necesitas registarte si vas a usar send2cgeo. C:geo funciona sin tener que registrar tu dispositivo.</string>
+ <string name="init_sendToCgeo_description"><b>Send2c:geo</b> te permite recibir cachés automáticamente desde la web de geocaching usando un complemento especial para Firefox o Chrome. Antes de registrarte, te sugerimos que leas <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Sólo necesitas registarte si vas a usar send2cgeo. c:geo funciona sin tener que registrar tu dispositivo.</string>
<string name="init_sendToCgeo_register">Solicitar registro</string>
<string name="init_sendToCgeo_registering">Registrando \"Enviar a c:geo\"…</string>
<string name="init_sendToCgeo_register_ok">Registro finalizado. Tu código PIN ####. Úsalo en la web de c:geo para añadir este dispositivo a tu navegador.</string>
<string name="init_sendToCgeo_register_fail">Error al registrarse.</string>
<string name="sendToCgeo_download_fail">c:geo no ha podido descargar cachés. No hay conexión a internet o send2c:geo no está disponible.</string>
- <string name="sendToCgeo_no_registration">c:geo no ha podido descargar cachés. El registro en send2c:geo ha expirado. Por favor registrate en configuración.</string>
+ <string name="sendToCgeo_no_registration">c:geo no ha podido descargar cachés. El registro en send2c:geo ha expirado. Por favor registrate en ajustes.</string>
<string name="auth_twitter">Twitter</string>
<string name="auth_authorize">Autorizar c:geo</string>
<string name="auth_start">Iniciar autorización</string>
<string name="auth_again">Volver a iniciar</string>
<string name="auth_dialog_waiting">Esperando a %s…</string>
- <string name="auth_explain_short">El suiguiente proceso permitirá a <b>c:geo</b> acceder a %s.</string>
- <string name="auth_explain_long">Presionando el botón \"Autoriza a c:geo\" comenzará el proceso. Este proceso abrirá el navegador web con una página %s. Resgistrate en esta página y permite a <b>c:geo</b> acceder a tu cuenta. Eso es todo.</string>
+ <string name="auth_explain_short">El siguiente proceso permitirá a <b>c:geo</b> acceder a %s.</string>
+ <string name="auth_explain_long">Presionando el botón \"Autorizar c:geo\" comenzará el proceso. Este proceso abrirá el navegador web con una página %s. Registrate en esta página y permite a <b>c:geo</b> acceder a tu cuenta. Eso es todo.</string>
<string name="auth_dialog_completed_twitter">c:geo está autorizado ahora a publicar en Twitter.</string>
<string name="auth_ocde">Opencaching.de</string>
<string name="auth_dialog_completed_oc">c:geo está autorizado a interactuar con %s.</string>
<plurals name="cache_counts">
- <item quantity="one">Un escondite</item>
- <item quantity="other">%1$d Escondites</item>
+ <item quantity="one">Un caché</item>
+ <item quantity="other">%1$d cachés</item>
</plurals>
<string name="cache_offline">Desconectado</string>
<string name="cache_offline_refresh">Actualizar</string>
@@ -552,7 +585,7 @@
<string name="cache_offline_store">Guardar</string>
<string name="cache_offline_stored">Guardado en el dispositivo</string>
<string name="cache_offline_not_ready">No preparado\npara usar desconectado</string>
- <string name="cache_offline_time_about">Acerca</string>
+ <string name="cache_offline_time_about">desde</string>
<string name="cache_offline_time_mins">minutos atrás</string>
<string name="cache_offline_time_mins_few">hace unos minutos</string>
<string name="cache_offline_time_hour">hace una hora</string>
@@ -561,21 +594,21 @@
<string name="cache_premium">Premium</string>
<string name="cache_attributes">Atributos</string>
<string name="cache_inventory">Inventario</string>
- <string name="cache_log_images_title">Imagen de registro</string>
+ <string name="cache_log_images_title">Imágenes de registros</string>
<string name="cache_log_image_default_title">Foto</string>
<string name="cache_personal_note">Nota personal</string>
<string name="cache_personal_note_edit">Editar</string>
<string name="cache_personal_note_limit">Límite de la nota personal</string>
<string name="cache_personal_note_truncation">Geocaching.com cortará esta nota personal después de %d caracteres.</string>
<string name="cache_personal_note_upload">Subir</string>
- <string name="cache_personal_note_uploading">Subir nota personal</string>
+ <string name="cache_personal_note_uploading">Cargando nota personal</string>
<string name="cache_personal_note_upload_done">Nota personal cargada</string>
- <string name="cache_personal_note_upload_cancelled">Subir nota personal cancelado</string>
+ <string name="cache_personal_note_upload_cancelled">Se ha cancelado la carga de la nota personal</string>
<string name="cache_description">Descripción</string>
<string name="cache_description_long">Descripción larga</string>
<string name="cache_description_table_note">La descripción contiene formato de tabla que puede necesitar ser vista en %s para mostrarse correctamente.</string>
- <string name="cache_watchlist_on">Este escondite está en tu Lista de seguimiento.</string>
- <string name="cache_watchlist_not_on">Este escondite no está en tu Lista de seguimiento.</string>
+ <string name="cache_watchlist_on">Este caché está en tu Lista de seguimiento.</string>
+ <string name="cache_watchlist_not_on">Este caché no está en tu Lista de seguimiento.</string>
<string name="cache_watchlist_add">Añadir a Lista de seguimiento</string>
<string name="cache_watchlist_remove">Borrar de la Lista de seguimiento</string>
<string name="cache_favpoint_on">Este caché es uno de tus favoritos.</string>
@@ -586,42 +619,43 @@
<string name="cache_list_change">Mover</string>
<string name="cache_list_unknown">No está en lista</string>
<string name="cache_images">Imágenes</string>
- <string name="cache_waypoints">Puntos de referencia</string>
+ <string name="cache_waypoints">Waypoints</string>
<plurals name="waypoints">
<item quantity="one">1 Waypoint</item>
<item quantity="other">%d Waypoints</item>
</plurals>
- <string name="cache_waypoints_add">Añadir referencia</string>
+ <string name="cache_waypoints_add">Añadir waypoint</string>
<string name="cache_hint">Pista</string>
- <string name="cache_logs">Bitácora</string>
+ <string name="cache_hint_not_available">No hay pista disponible</string>
+ <string name="cache_logs">Registros</string>
<string name="cache_logs_friends_and_own">Amigos/propios</string>
- <string name="cache_dialog_loading_details">Cargando detalles del escondite…</string>
- <string name="cache_dialog_loading_details_status_loadpage">Cargando la página</string>
+ <string name="cache_dialog_loading_details">Cargando detalles del caché…</string>
+ <string name="cache_dialog_loading_details_status_loadpage">Cargando página</string>
<string name="cache_dialog_loading_details_status_details">Procesando detalles</string>
<string name="cache_dialog_loading_details_status_spoilers">Cargando imágenes spoiler</string>
<string name="cache_dialog_loading_details_status_logs">Cargando registros</string>
- <string name="cache_dialog_loading_details_status_waypoints">Procesando Waypoints</string>
+ <string name="cache_dialog_loading_details_status_waypoints">Procesando waypoints</string>
<string name="cache_dialog_loading_details_status_gcvote">Cargando GCVote</string>
- <string name="cache_dialog_loading_details_status_cache">Salvando datos</string>
+ <string name="cache_dialog_loading_details_status_cache">Almacenando datos</string>
<string name="cache_dialog_loading_details_status_render">Procesando la representación</string>
<string name="cache_dialog_offline_save_title">Desconectado</string>
- <string name="cache_dialog_offline_save_message">Guardando escondite para usar desconectado…</string>
+ <string name="cache_dialog_offline_save_message">Guardando caché para usar desconectado…</string>
<string name="cache_dialog_offline_drop_title">Desconectado</string>
- <string name="cache_dialog_offline_drop_message">Borrando escondite de la memoria del dispositivo…</string>
+ <string name="cache_dialog_offline_drop_message">Borrando caché de la memoria del dispositivo…</string>
<string name="cache_dialog_refresh_title">Actualizar</string>
- <string name="cache_dialog_refresh_message">Recargando detalles del escondite…</string>
+ <string name="cache_dialog_refresh_message">Recargando detalles del caché…</string>
<string name="cache_dialog_watchlist_add_title">Lista de seguimiento</string>
- <string name="cache_dialog_watchlist_add_message">Añadiendo el escondite a tu Lista de seguimiento…</string>
+ <string name="cache_dialog_watchlist_add_message">Añadiendo el caché a tu Lista de seguimiento…</string>
<string name="cache_dialog_watchlist_remove_title">Lista de seguimiento</string>
- <string name="cache_dialog_watchlist_remove_message">Borrando escondite de tu Lista de seguimiento…</string>
+ <string name="cache_dialog_watchlist_remove_message">Borrando caché de tu Lista de seguimiento…</string>
<string name="cache_dialog_favorite_add_title">Favorito</string>
<string name="cache_dialog_favorite_add_message">Añadiendo el caché a tus favoritos…</string>
<string name="cache_dialog_favorite_remove_title">Favorito</string>
<string name="cache_dialog_favorite_remove_message">Borrando el caché de tus favoritos…</string>
<string name="cache_menu_navigate">Navegar</string>
- <string name="cache_menu_navigation_drive">Navegación (conduciendo)</string>
- <string name="cache_menu_navigation_walk">Navegación (a pie)</string>
- <string name="cache_menu_navigation_bike">Navegación (En bici)</string>
+ <string name="cache_menu_navigation_drive">Navegación (Coche)</string>
+ <string name="cache_menu_navigation_walk">Navegación (A Pie)</string>
+ <string name="cache_menu_navigation_bike">Navegación (Bici)</string>
<string name="cache_menu_maps_directions">Direcciones de Google Maps</string>
<string name="cache_menu_radar">Radar</string>
<string name="cache_menu_map">Ver en mapa</string>
@@ -630,23 +664,27 @@
<string name="cache_menu_rmaps">Rmaps</string>
<string name="cache_menu_map_ext">Mostrar en mapa ext.</string>
<string name="cache_menu_streetview">Street View</string>
- <string name="cache_menu_browser">Navegador</string>
- <string name="cache_menu_visit">Encontrado</string>
- <string name="cache_menu_visit_offline">Registar vista sin conexión</string>
+ <string name="cache_menu_browser">Abrir navegador</string>
+ <string name="cache_menu_visit">Registrar visita</string>
+ <string name="cache_menu_visit_offline">Registro rápido sin conexión</string>
<string name="cache_menu_spoilers">Revelaciones</string>
- <string name="cache_menu_around">Alrededores</string>
- <string name="cache_menu_event">Añadir a calendario</string>
+ <string name="cache_menu_around">Cachés cercanos</string>
+ <string name="around">Cerca de %s</string>
+ <string name="cache_menu_event">Añadir al calendario</string>
<string name="cache_menu_details">Detalles</string>
<string name="cache_menu_refresh">Actualizar</string>
- <string name="cache_menu_share">Compartir escondite</string>
+ <string name="cache_menu_share">Compartir caché</string>
<string name="cache_menu_move_list">Mover a otra lista</string>
<string name="cache_menu_whereyougo">WhereYouGo</string>
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Votar</string>
+ <string name="cache_menu_checker">Abrir Geochecker</string>
+ <string name="cache_menu_ignore">Ignorar caché</string>
<string name="cache_status">Estado</string>
<string name="cache_status_offline_log">Registro guardado</string>
<string name="cache_status_found">Encontrado</string>
- <string name="cache_not_status_found">No encontrados</string>
+ <string name="cache_not_status_found">No encontrado</string>
<string name="cache_status_archived">Archivado</string>
<string name="cache_status_disabled">Desactivado</string>
<string name="cache_status_premium">Sólo para miembros Premium</string>
@@ -661,7 +699,7 @@
<string name="cache_difficulty">Dificultad</string>
<string name="cache_terrain">Terreno</string>
<string name="cache_rating">Puntuación</string>
- <string name="cache_own_rating">Su calificación</string>
+ <string name="cache_own_rating">Tu puntuación</string>
<string name="cache_rating_of">de</string>
<string name="cache_favorite">Favorito</string>
<string name="cache_owner">Propietario</string>
@@ -672,7 +710,7 @@
<string name="cache_coordinates_original">Coordenadas originales</string>
<string name="cache_spoiler_images_title">Imágenes reveladoras</string>
<string name="cache_log_types">Tipos de registro</string>
- <string name="cache_coordinates_no">Este escondite no tiene coordenadas.</string>
+ <string name="cache_coordinates_no">Este caché no tiene coordenadas.</string>
<string name="cache_clear_history">Borrar historial</string>
<string name="cache_remove_from_history">Borrar del historial</string>
<string name="cache_license">Licencia</string>
@@ -690,10 +728,10 @@
<string name="simple_dir_chooser_title">Elegir directorio</string>
<string name="simple_dir_chooser_current_path">Ruta:</string>
<string name="simple_dir_chooser_invalid_path">Ruta inválida</string>
- <string name="gpx_import_loading_caches">Cargando escondites del archivo .gpx</string>
+ <string name="gpx_import_loading_caches">Cargando cachés del archivo .gpx</string>
<string name="gpx_import_loading_waypoints">Cargando archivo de waypoints</string>
- <string name="gpx_import_store_static_maps">Almacenar mapas estáticos</string>
- <string name="gpx_import_caches_imported">escondites importados</string>
+ <string name="gpx_import_store_static_maps">Almacenando mapas estáticos</string>
+ <string name="gpx_import_caches_imported">cachés importados</string>
<string name="gpx_import_static_maps_skipped">Descarga de mapas estáticos abortada</string>
<string name="gpx_import_title_static_maps">Almacenar mapas estáticos</string>
<string name="gpx_import_title_reading_file">Leyendo archivo</string>
@@ -710,39 +748,40 @@
<string name="gpx_import_android">Importar desde Android</string>
<string name="map_file_select_title">Selecciona un mapa</string>
<string name="web_import_title">Importar de la web</string>
- <string name="web_import_waiting">Esperando por nuevos escondites desde la web…</string>
+ <string name="web_import_waiting">Esperando a nuevos cachés desde la web…</string>
<string name="web_downloading">Descargando</string>
<string name="web_downloaded">Descargados</string>
<string name="popup_more">Más detalles</string>
<string name="waypoint">Waypoint</string>
- <string name="waypoint_cache_coordinates">Coordenadas del cache</string>
+ <string name="waypoint_cache_coordinates">Coordenadas del caché</string>
<string name="waypoint_custom">A medida</string>
<string name="waypoint_my_coordinates">Mis coordenadas</string>
- <string name="waypoint_bearing">Orientación</string>
+ <string name="waypoint_bearing">Orientación en º</string>
<string name="waypoint_distance">Distancia</string>
<string name="waypoint_name">Nombre</string>
<string name="waypoint_edit">Editar</string>
<string name="waypoint_delete">Borrar</string>
- <string name="waypoint_edit_title">Editar punto de referencia</string>
- <string name="waypoint_add_title">Añadir referencia</string>
+ <string name="waypoint_edit_title">Editar waypoint</string>
+ <string name="waypoint_add_title">Añadir waypoint</string>
<string name="waypoint_note">Nota</string>
<string name="waypoint_visited">Visitado</string>
<string name="waypoint_save">Guardar</string>
- <string name="waypoint_loading">Cargando punto de referencia…</string>
- <string name="waypoint_do_not_touch_cache_coordinates">No cambiar las coordenadas del cache</string>
- <string name="waypoint_set_as_cache_coords">Establecer como coordenadas del cache solo en c:geo</string>
- <string name="waypoint_save_and_modify_on_website">Establecer como coordenadas del cache en c:geo y en la web</string>
- <string name="waypoint_reset_cache_coords">Restablecer las coordenadas del cache</string>
- <string name="waypoint_coordinates_has_been_reset_on_website">Las coordenadas del cache han sido reseteadas en la web.</string>
- <string name="waypoint_coordinates_being_reset_on_website">Reseteando las coordenadas del cache en la web...</string>
+ <string name="waypoint_cancel_edit">Cancelar</string>
+ <string name="waypoint_loading">Cargando waypoint…</string>
+ <string name="waypoint_do_not_touch_cache_coordinates">No cambiar las coordenadas del caché</string>
+ <string name="waypoint_set_as_cache_coords">Establecer como coordenadas del caché en c:geo</string>
+ <string name="waypoint_save_and_modify_on_website">Establecer como coordenadas del caché en c:geo y en la web</string>
+ <string name="waypoint_reset_cache_coords">Restablecer las coordenadas del caché</string>
+ <string name="waypoint_coordinates_has_been_reset_on_website">Las coordenadas del caché han sido reseteadas en la web.</string>
+ <string name="waypoint_coordinates_being_reset_on_website">Reseteando las coordenadas del caché en la web…</string>
<string name="waypoint_reset">Restablecer</string>
<string name="waypoint_localy_reset_cache_coords">Restablecer en c:geo</string>
<string name="waypoint_reset_local_and_remote_cache_coords">Restablecer en c:geo y en la web</string>
<string name="waypoint_being_saved">Se está guardando el waypoint…</string>
<string name="waypoint_coordinates_couldnt_be_modified_on_website">El sitio web no permite modificar las coordenadas del caché.</string>
<string name="waypoint_coordinates_upload_error">Ha ocurrido un error mientras se modificaban las coordenadas en la web.</string>
- <string name="waypoint_coordinates_uploading_to_website">Subiendo coordenadas a la página %s.</string>
- <string name="waypoint_coordinates_has_been_modified_on_website">Las coordenadas del cache en la web modificadas a: %s.</string>
+ <string name="waypoint_coordinates_uploading_to_website">Subiendo coordenadas %s a la web.</string>
+ <string name="waypoint_coordinates_has_been_modified_on_website">Las coordenadas del caché en la web modificadas a: %s.</string>
<string name="waypoint_done">Hecho</string>
<string name="waypoint_duplicate">Duplicar</string>
<string name="waypoint_copy_of">Copia de</string>
@@ -752,43 +791,45 @@
<string name="search_clear_history">Borrar historial</string>
<string name="search_history_cleared">Historial borrado</string>
<string name="waypoint_coordinate_formats_plain">Sencillo</string>
+ <string name="from_clipboard">Desde portapapeles</string>
+ <string name="copy_to_clipboard">Copiar al portapapeles</string>
<string name="visit_tweet">Publicar en Twitter</string>
<string name="map_map">Mapa</string>
<string name="map_live">Mapa activo</string>
- <string name="map_view_map">Ver mapa</string>
- <string name="map_modes">Configuración del mapa</string>
+ <string name="map_view_map">Elegir mapa</string>
+ <string name="map_modes">Ajustes del mapa</string>
<string name="map_trail_show">Mostrar rastro</string>
<string name="map_circles_show">Mostrar círculos</string>
- <string name="map_mycaches_hide">Esconder cachés propios/encontrados</string>
+ <string name="map_mycaches_hide">Ocultar propios/encontr.</string>
<string name="map_theme_builtin">Por defecto</string>
<string name="map_theme_select">Seleccionar tema del mapa</string>
<string name="map_live_enable">Activar en vivo</string>
<string name="map_live_disable">Desactivar en vivo</string>
<string name="map_static_title">Mapas estáticos</string>
<string name="map_static_loading">Cargando mapas estáticos…</string>
- <string name="map_token_err">Dado que c:geo sólo es capaz de descargar datos parciales, la coordenadas de algunso escondites pueden ser inexactas.</string>
+ <string name="map_token_err">Dado que c:geo sólo es capaz de descargar datos parciales, la coordenadas de algunos cachés pueden ser inexactas.</string>
<string name="map_as_list">Mostrar como lista</string>
<string name="map_strategy">Estrategia</string>
- <string name="map_strategy_title">Estrategia de mapa en directo</string>
+ <string name="map_strategy_title">Estrategia de mapa activo</string>
<string name="map_strategy_fastest">Más rápido</string>
<string name="map_strategy_fast">Rápido</string>
<string name="map_strategy_auto">En función de la velocidad</string>
<string name="map_strategy_detailed">Detallado</string>
<string name="live_map_notification">Las coordenadas en el mapa en vivo pueden no ser precisas. Posibles coordenadas imprecisas están marcadas con un círculo naranja.\nAbrir los detalles del caché o guardándolo para su uso sin conexión proporcionará siempre coordenadas precisas.\n\nPuedes encontrar más información en la página \"Sobre c:geo\" dentro de la app.</string>
- <string name="search_bar_hint">Buscar escondites</string>
- <string name="search_bar_desc">Escondites (Código-GC, palabra clave), Rastreables (Código-TB)</string>
+ <string name="search_bar_hint">Buscar cachés</string>
+ <string name="search_bar_desc">Cachés (Código-GC, palabra clave), Rastreables (Código-TB)</string>
<string name="search_coordinates">Coordenadas</string>
<string name="search_coordinates_button">Buscar por coordenadas</string>
<string name="search_address">Dirección</string>
<string name="search_address_button">Buscar por dirección</string>
- <string name="search_geo">Geocode</string>
+ <string name="search_geo">Código GC</string>
<string name="search_geo_button">Buscar por código</string>
<string name="search_kw">Palabras clave</string>
- <string name="search_kw_prefill">palabra clave</string>
+ <string name="search_kw_prefill">Palabra clave</string>
<string name="search_kw_button">Buscar por palabra clave</string>
- <string name="search_fbu">Encontrar por usuario</string>
+ <string name="search_fbu">Encontrados por usuario</string>
<string name="search_fbu_prefill">Nombre de usuario</string>
- <string name="search_fbu_button">Buscar por nombre de usuario</string>
+ <string name="search_fbu_button">Buscar por usuario</string>
<string name="search_hbu">Oculto por usuario</string>
<string name="search_hbu_prefill">Propietario</string>
<string name="search_hbu_button">Buscar por propietario</string>
@@ -807,35 +848,36 @@
<string name="trackable_details_loading">Cargando detalles del rastreable…</string>
<string name="trackable_log_touch">Registrar contacto</string>
<string name="trackable_browser_open">Abrir en navegador</string>
- <string name="trackable_goal">Meta</string>
+ <string name="trackable_goal">Objetivo</string>
<string name="trackable_details">Detalles</string>
<string name="trackable_image">Imagen</string>
- <string name="trackable_code">Código TB</string>
+ <string name="trackable_code">Código rastreable</string>
<string name="trackable_name">Nombre</string>
<string name="trackable_type">Tipo</string>
<string name="trackable_owner">Propietario</string>
- <string name="trackable_spotted">Marcado</string>
+ <string name="trackable_spotted">Visto</string>
<string name="trackable_spotted_in_cache">En</string>
<string name="trackable_spotted_at_user">En manos de</string>
<string name="trackable_spotted_unknown_location">Ubicación desconocida</string>
<string name="trackable_spotted_owner">En manos del propietario</string>
<string name="trackable_origin">Origen</string>
<string name="trackable_unknown">Desconocido</string>
- <string name="trackable_released">Publicado</string>
+ <string name="trackable_released">Activado</string>
<string name="trackable_distance">Recorrido</string>
<string name="trackable_touch">Contacto</string>
<string name="trackable_not_activated">Rasteable no activado</string>
+ <string name="trackable_geokrety">Geokrety</string>
<string name="geokret_type_traditional">Tradicional</string>
<string name="geokret_type_book_or_media">Libro o medio electrónicos</string>
<string name="geokret_type_human">Humano</string>
<string name="geokret_type_coin">Moneda</string>
<string name="geokret_type_post">Correo</string>
- <string name="user_menu_title">Acerca</string>
- <string name="user_menu_view_hidden">Escondites ocultos</string>
- <string name="user_menu_view_found">Escondites encontrados</string>
+ <string name="user_menu_title">Sobre</string>
+ <string name="user_menu_view_hidden">Cachés escondidos</string>
+ <string name="user_menu_view_found">Cachés encontrados</string>
<string name="user_menu_open_browser">Abrir perfil en el navegador</string>
<string name="user_menu_send_message">Enviar mensaje</string>
- <string name="user_menu_open_contact">Abriendo tarjeta de contacto</string>
+ <string name="user_menu_open_contact">Abriendo contacto</string>
<string name="navigation">Navegación</string>
<string name="compass_title">Brújula</string>
<string name="compass_sensors">Sensores activos</string>
@@ -850,13 +892,13 @@
<string name="license_dismiss">Descartar</string>
<string name="helper_calendar_title">Complemento de calendario de c:geo</string>
<string name="helper_calendar_missing">Complemento de calendario de c:geo no está instalado.</string>
- <string name="helper_calendar_description">Permite exportar caches evento al calendario de tu dispositivo.</string>
+ <string name="helper_calendar_description">Permite exportar eventos al calendario de tu dispositivo.</string>
<string name="helper_sendtocgeo_title">Send to c:geo</string>
<string name="helper_contacts_title">Complemento de contactos de c:geo</string>
- <string name="helper_contacts_description">Permite abrir un contacto (de tu libreta de contactos) directamente desde un registro, para que puedas pedir ayuda a tus amigos más facilmente.</string>
+ <string name="helper_contacts_description">Permite abrir un contacto (de tu libreta de contactos) directamente desde un registro, para que puedas pedir ayuda a tus amigos más fácilmente.</string>
<string name="helper_sendtocgeo_description">\'Enviar a c:geo\' es una extensión <strong>para tu PC</strong>. Cuando navegues por geocaching.com, puedes enviar cachés a tu smartphone haciendo clic directamente desde tu navegador.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Sencilla aplicación que muestra mapas en línea y permite descargarlos para ser usados sin conexión (sólo mapas no vectoriales). También permite registrar el recorrido, gestionar puntos de interés y más funciones interesantes.</string>
+ <string name="helper_locus_description">App de navegación exterior para tu móvil o tableta. Puede visualizar mapas Topo sin conexión, marcar tu ruta, buscar geocachés, usar una guía de voz y mucho más.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Puedes usar el radar de esta aplicación con c:geo. Además ofrece un montón de información relacionada con el GPS.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -899,7 +941,7 @@
<string name="attribute_campfires_yes">Hogueras permitidas</string>
<string name="attribute_campfires_no">Hogueras no permitidas</string>
<string name="attribute_rv_yes">Camión/remolque permitido</string>
- <string name="attribute_rv_no">camión/remolque no permitido</string>
+ <string name="attribute_rv_no">Camión/remolque no permitido</string>
<string name="attribute_kids_yes">Recomendado para niños</string>
<string name="attribute_kids_no">No recomendado para niños</string>
<string name="attribute_onehour_yes">Se hace en menos de una hora</string>
@@ -926,8 +968,8 @@
<string name="attribute_firstaid_no">No necesita mantenimiento</string>
<string name="attribute_cow_yes">Hay que tener cuidado con el ganado</string>
<string name="attribute_cow_no">No hay que tener cuidado con el ganado</string>
- <string name="attribute_field_puzzle_yes">Terreno enrevesado</string>
- <string name="attribute_field_puzzle_no">Terreno no enrevesado</string>
+ <string name="attribute_field_puzzle_yes">Puzzle en el lugar</string>
+ <string name="attribute_field_puzzle_no">No es puzzle en el lugar</string>
<string name="attribute_nightcache_yes">Caché nocturno</string>
<string name="attribute_nightcache_no">Caché no nocturno</string>
<string name="attribute_parkngrab_yes">Se puede aparcar justo al lado</string>
@@ -950,8 +992,8 @@
<string name="attribute_teamwork_no">No es necesario trabajo en equipo</string>
<string name="attribute_landf_yes">Viaje perdidos y encontrados</string>
<string name="attribute_landf_no">No viaje perdidos y encontrados</string>
- <string name="attribute_partnership_yes">Escondite asociado</string>
- <string name="attribute_partnership_no">Escondite no asociado</string>
+ <string name="attribute_partnership_yes">Caché asociado</string>
+ <string name="attribute_partnership_no">No es un caché asociado</string>
<string name="attribute_fee_yes">Cuota de aparcamiento o acceso requerida</string>
<string name="attribute_fee_no">Cuota de aparcamiento o acceso no requerida</string>
<string name="attribute_rappelling_yes">Material de escalada necesario</string>
@@ -982,8 +1024,8 @@
<string name="attribute_ticks_no">No hay garrapatas</string>
<string name="attribute_mine_yes">Minas abandonadas</string>
<string name="attribute_mine_no">No hay minas abandonadas</string>
- <string name="attribute_cliff_yes">Precipicio /Caida de rocas</string>
- <string name="attribute_cliff_no">No hay peligro de precipicio o caida de rocas</string>
+ <string name="attribute_cliff_yes">Precipicio/Caída de rocas</string>
+ <string name="attribute_cliff_no">No hay peligro de precipicio o caída de rocas</string>
<string name="attribute_hunting_yes">Cacería</string>
<string name="attribute_hunting_no">No hay cacerías</string>
<string name="attribute_danger_yes">Zona peligrosa</string>
@@ -1052,13 +1094,13 @@
<string name="attribute_all_seasons_no">No todas las estaciones</string>
<string name="attribute_breeding_yes">Época de cría / Naturaleza protegida</string>
<string name="attribute_breeding_no">No es época de cría / naturaleza protegida</string>
- <string name="attribute_snow_proof_yes">Escondite a prueba de nieve</string>
- <string name="attribute_snow_proof_no">Escondite NO a prueba de nieve</string>
+ <string name="attribute_snow_proof_yes">Caché a prueba de nieve</string>
+ <string name="attribute_snow_proof_no">No es caché a prueba de nieve</string>
<string name="attribute_compass_yes">Brújula</string>
<string name="attribute_compass_no">Sin brújula</string>
<string name="attribute_cave_yes">Equipo para cuevas</string>
<string name="attribute_cave_no">Sin equipo para cuevas</string>
- <string name="attribute_aircraft_yes">Avión</string>
+ <string name="attribute_aircraft_yes">Aeronave</string>
<string name="attribute_aircraft_no">No aeronave</string>
<string name="attribute_investigation_yes">Investigación</string>
<string name="attribute_investigation_no">No requiere investigar</string>
@@ -1068,8 +1110,8 @@
<string name="attribute_arithmetic_no">No es un problema aritmético</string>
<string name="attribute_other_cache_yes">Caché de otro tipo</string>
<string name="attribute_other_cache_no">No es caché de otro tipo</string>
- <string name="attribute_ask_owner_yes">Pregunta al propietario las coordendanas de inicio</string>
- <string name="attribute_ask_owner_no">No es necesario preguntar al propietario las coordendas de inicio</string>
+ <string name="attribute_ask_owner_yes">Pregunta al propietario las condiciones iniciales</string>
+ <string name="attribute_ask_owner_no">No es necesario preguntar al propietario las condiciones iniciales</string>
<string name="attribute_unknown_yes">Hay un atributo desconocido</string>
<string name="attribute_unknown_no">No hay atributo desconocido</string>
<string name="attribute_geotour_yes">Parte de un GeoTour</string>
@@ -1107,12 +1149,15 @@
<string name="attribute_offset_cache_yes">Caché offset</string>
<string name="attribute_offset_cache_no">No es caché offset</string>
<string name="quote">Para hacer el geocaching más sencillo, para hacer a los usuarios más vagos.</string>
- <string name="support">Soporte: <a href="">support@cgeo.org</a></string>
- <string name="website">Web: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo en Google Play</a></string>
- <string name="about_twitter">¿Debe <b>c:geo</b> publicar el nuevo estado en Twitter cuando registras un escondite?</string>
+ <string name="support_title">Soporte técnico</string>
+ <string name="website_title">Sitio Web</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">Página de c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo en Google Play</a></string>
+ <string name="about_twitter">¿Debe <b>c:geo</b> publicar el nuevo estado en Twitter cuando registras un caché?</string>
+ <string name="faq_title">Preguntas frecuentes</string>
<string name="status_new_release" tools:ignore="UnusedResources">Nueva versión disponible. \nClick para instalar.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nueva versión nightly build disponible.\nHaz clic para instalar.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Nueva versión candidate disponible.\nHaz clic para instalar.</string>
@@ -1150,23 +1195,31 @@
<string name="tts_oclock">%s en punto</string>
<string name="clipboard_copy_ok">Copiado al portapapeles</string>
<plurals name="days_ago">
- <item quantity="one">Ayer</item>
- <item quantity="other">Hace %d días</item>
+ <item quantity="one">ayer</item>
+ <item quantity="other">hace %d días</item>
</plurals>
<plurals name="favorite_points">
<item quantity="one">%s favorito</item>
<item quantity="other">%s favoritos</item>
</plurals>
- <string name="percent_favorite_points">% \ favoritos</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoritos</string>
<string name="cgeo_shortcut">Atajo de c:geo</string>
<string name="create_shortcut">Crear atajo</string>
<string name="send">Enviar</string>
<string name="showcase_logcache_title">Enviar el registro</string>
- <string name="showcase_logcache_text">Recuerda, muchos de los comandos están ahora el la barra de título. Allí encontrarás el botón para enviar el registro terminado.</string>
+ <string name="showcase_logcache_text">Recuerda, muchos de los comandos están ahora en la barra de título. Allí encontrarás el botón para enviar el registro terminado.</string>
<string name="showcase_main_title">Menús nuevos</string>
<string name="showcase_main_text">c:geo coloca ahora los elementos del menú en la barra de título como otras apps modernas. Algunos elementos se esconden detrás del símbolo de puntos. Presiona de manera larga para ver su descripción.</string>
<string name="showcase_cachelist_title">Cambio entre listas</string>
<string name="showcase_cachelist_text">Puedes cambiar entre tus listas de cachés haciendo clic sobre el nombre de la lista.</string>
+ <string name="showcase_compass_hint_title">Mostrar la pista</string>
+ <string name="showcase_compass_hint_text">Este nuevo elemento del menú puede darte una idea de dónde encontrar el caché - muestra la pista, si está disponible.</string>
<string name="confirm_log_title">Tipo de registro inusual</string>
- <string name="confirm_log_message">Quieres registrar \'%s\'. ¿Estás seguro?</string>
+ <string name="confirm_log_message">Vas a registrar \'%s\'. ¿Estás seguro?</string>
+ <string name="init_geokrety">Geokrety.org</string>
+ <string name="init_geokrety_login">Iniciar sesión en Geokrety.org</string>
+ <string name="init_connectorGeokretyActive">Rastreables de Geokrety</string>
+ <string name="init_summary_geokrety">Habilitar rastreables de Geokrety.org</string>
+ <string name="init_summary_geokrety_cache">Mejorar la velocidad de carga.</string>
+ <string name="init_summary_geokrety_account">No hay cuenta configurada.</string>
</resources>
diff --git a/main/res/values-fr/strings.xml b/main/res/values-fr/strings.xml
index 0287b48..655c31a 100644
--- a/main/res/values-fr/strings.xml
+++ b/main/res/values-fr/strings.xml
@@ -5,7 +5,7 @@
<string name="cache">Cache</string>
<string name="detail">Détails</string>
<string name="search">Rechercher</string>
- <string name="helpers">Aide à l\'installation</string>
+ <string name="helpers">Applications utiles</string>
<string name="about">À propos de c:geo</string>
<string name="latitude">Latitude</string>
<string name="longitude">Longitude</string>
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Visité</string>
<string name="log_tb_drop">Déposé ici</string>
<string name="log_tb_changeall">Tout modifié</string>
- <string name="log_save">Enregistrer</string>
+ <string name="log_save">Sauvegarder hors-ligne</string>
<string name="log_saving">Enregistrement en cours…</string>
<string name="log_saving_and_uploading">Envoi de la note et de l\'image…</string>
<string name="log_clear">Effacer</string>
<string name="log_post_not_possible">Chargement de la page…</string>
+ <string name="log_date_future_not_allowed">Les entrées de carnet dans le futur sont interdites.</string>
<string name="log_add">Ajouter</string>
+ <string name="log_repeat">Recopier la dernière entrée</string>
<string name="log_no_rating">Pas de note</string>
<string name="log_stars_1_description">faible</string>
<string name="log_stars_15_description">plutôt faible</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Mot de passe du carnet :</string>
<string name="log_hint_log_password">Entrez votre mot de passe pour le carnet</string>
<string name="log_oc_team_comment">Commentaire de l\'équipe OC</string>
+ <string name="log_your_saved_log">Votre journal enregistré</string>
<string-array name="log_image_scales">
<item>Taille originale</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Pas d\'utilisateur ou de mot de passe enregistré</string>
<string name="err_login_failed_toast">c:geo est en mode hors-ligne et ne peut pas se connecter. Vérifiez votre connexion Internet.</string>
<string name="err_unknown">Erreur inconnue</string>
+ <string name="err_unknown_address">c:geo n\'a pas réussi à trouver de coordonnées géographiques pour cette adresse</string>
<string name="err_comm">Erreur inconnue de communication</string>
<string name="err_missing_auth">Nom d\'utilisateur ou mot de passe manquant.</string>
<string name="err_wrong">Nom d\'utilisateur inconnu ou mauvais mot de passe</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">L\'acquisition d\'une nouvelle image pour la note a échoué.</string>
<string name="err_tb_display">\"c:geo ne peut pas afficher l\'objet voyageur demandé. Est-ce vraiment un objet voyageur?</string>
<string name="err_tb_details_open">c:geo ne peut pas ouvrir le détail de l\'objet voyageur.</string>
- <string name="err_tb_forgot_saw">c:geo a oublié quel objet voyageur vous avez vu.</string>
<string name="err_tb_find">c:geo ne peut pas trouver d\'objet voyageur.</string>
<string name="err_tb_find_that">c:geo ne peut pas trouver cet objet voyageur.</string>
<string name="err_waypoint_cache_unknown">c:geo ne sait pas à quel cache vous voulez ajouter une étape.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo ne peut pas savoir où vous êtes.</string>
<string name="err_point_no_position_given_title">Information obligatoire</string>
<string name="err_point_no_position_given">Remplissez au moins la latitude ou la longitude ou la distance et le relèvement. Vous pouvez aussi remplir tous les champs.</string>
- <string name="err_point_curr_position_unavailable">c:geo ne connaît pas encore votre position. Veuillez patienter…</string>
<string name="err_point_bear_and_dist_title">Besoin d\'aide?</string>
<string name="err_point_bear_and_dist">Remplissez le relèvement et la distance. Le relèvement est l\'angle de 0 à 360 degrés par rapport au Nord. La distance est avec ou sans les unités.</string>
<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_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>
+ <string name="err_log_post_failed">Il semble que votre visite n\'ait pas été enregistrée. Veuillez vérifier sur le site web d\'origine de la géocache.</string>
+ <string name="err_logimage_post_failed">Il semble que l\'envoi de l\'image a échoué. Veuillez vérifier sur le site web d\'origine de la géocache.</string>
<string name="err_search_address_forgot">c:geo a oublié l\'adresse recherchée.</string>
<string name="err_parse_lat">c:geo n\'arrive pas à lire la latitude.</string>
<string name="err_parse_lon">c:geo n\'arrive pas à lire la longitude.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Réseau</string>
<string name="loc_fused">Fusionné</string>
<string name="loc_low_power">Éco</string>
+ <string name="loc_home">Domicile</string>
<string name="loc_gps">Gps</string>
<string name="loc_sat">Satellites</string>
<string name="loc_trying">Localisation en cours…</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Proches</string>
<string name="advanced_search_button">Recherche</string>
<string name="stored_caches_button">Stockées</string>
- <string name="any_button">N\'importe</string>
+ <string name="any_button">Aller à</string>
<string name="unknown_scan">Le scan ne trouve pas de géocode.</string>
<string name="caches_no_cache">Aucune cache</string>
<string name="caches_more_caches">Charger plus de caches</string>
@@ -263,15 +265,22 @@
<string name="caches_sort_finds">Trouvées</string>
<string name="caches_sort_state">État</string>
<string name="caches_sort_storage">Date de sauvegarde dans l\'appareil</string>
+ <string name="caches_sort_eventdate">Date de l\'événement</string>
<string name="caches_select_mode">Mode sélection</string>
<string name="caches_select_mode_exit">Sortir du mode sélection</string>
<string name="caches_select_invert">Inverser la sélection</string>
<string name="caches_nearby">Proches</string>
<string name="caches_manage">Gérer</string>
<string name="caches_remove_all">Tout supprimer</string>
- <string name="caches_remove_all_confirm">Voulez-vous supprimer les %s caches de votre liste actuelle ?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Voulez-vous supprimer cette cache de la liste actuelle ?</item>
+ <item quantity="other">Voulez vous supprimer ces %d caches de la liste actuelle ?</item>
+ </plurals>
<string name="caches_remove_selected">Supprimer la sélection</string>
- <string name="caches_remove_selected_confirm">Voulez-vous supprimer de votre appareil les %s caches sélectionnées ?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Voulez-vous supprimer cette cache de votre appareil ?</item>
+ <item quantity="other">Voulez-vous supprimer les %d caches sélectionnées de votre appareil ?</item>
+ </plurals>
<string name="caches_remove_progress">Suppression des caches en cours</string>
<string name="caches_delete_events">Effacer les événements précédents</string>
<string name="caches_refresh_selected">Rafraîchir les caches sélectionnées</string>
@@ -291,13 +300,18 @@
<string name="caches_filter_track">Avec des objets voyageurs</string>
<string name="caches_filter_clear">Effacer les filtres</string>
<string name="caches_filter_modified">Avec les coordonnées modifiées</string>
+ <string name="caches_filter_offline_log">Avec entrée de carnet hors connexion</string>
<string name="caches_filter_origin">Avec les coordonées originales</string>
<string name="caches_filter_distance">Distance</string>
<string name="caches_filter_personal_note">Avec une note personnelle</string>
<string name="caches_filter_popularity">Favoris</string>
<string name="caches_filter_popularity_ratio">Favoris [%]</string>
+ <string name="caches_filter_personal_data">Avec des données personnelles</string>
+ <string name="caches_filter_rating">Ayant reçu une note</string>
+ <string name="caches_filter_own_rating">Ayant reçu une note de votre part</string>
<string name="caches_removing_from_history">Effacer de l\'historique…</string>
<string name="caches_clear_offlinelogs">Effacer les entrées de carnet hors-ligne</string>
+ <string name="caches_clear_offlinelogs_message">Effacer tous les journaux hors ligne ?</string>
<string name="caches_clear_offlinelogs_progress">Effacement des entrées de carnet hors-ligne</string>
<string name="list_menu_create">Nouvelle liste</string>
<string name="list_menu_drop">Effacer la liste courante</string>
@@ -320,13 +334,17 @@
<string name="list_not_available">La liste n\'est plus disponible, basculement vers la liste standard</string>
<string name="about_version">Version</string>
<string name="about_changelog">Versions</string>
+ <string name="about_system">Système</string>
<string name="about_donate">Dons</string>
<string name="about_donation_more">Don\ndéveloppement</string>
<string name="about_contributors">Contributeurs</string>
<string name="about_license">Licence</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Aide</string>
+ <string name="about_system_include">Merci d\'inclure systématiquement les informations suivantes lorsque vous signalez un problème ou demandez plus d\'information à propos de c:geo:</string>
+ <string name="changelog_github">Liste de toutes les modifications</string>
<string name="settings_title_services">Services</string>
+ <string name="settings_summary_services">Configuration des données de connexion et des services optionnels.</string>
<string name="settings_title_appearance">Apparence</string>
<string name="settings_title_cachedetails">Détails de la cache</string>
<string name="settings_title_offlinedata">Données hors-ligne</string>
@@ -374,6 +392,9 @@
<string name="settings_activate_oc_uk">Activer</string>
<string name="init_oc_uk_description">Autoriser c:geo à utiliser opencaching.org.uk pour chercher des caches et accéder/filtrer vos caches trouvées.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Pour pouvoir attribuer une note à une géocache, vous devez suivre les instructions de GCVote.com et entrer ici votre mot de passe GCVote.</string>
+ <string name="err_gcvote_send_rating">Erreur lors de l\'envoi de la note, vérifiez le mot de passe GCVote dans les paramètres ou effacez le.</string>
+ <string name="gcvote_sent">Note envoyée</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activer</string>
<string name="init_username">Identifiant</string>
@@ -444,6 +465,8 @@
<string name="init_backup_success">La base de données de c:geo a été sauvegardée dans un fichier</string>
<string name="init_backup_failed">La sauvegarde de la base de données de c:geo a échouée.</string>
<string name="init_backup_unnecessary">La base de données est vide, sauvegarde non nécessaire.</string>
+ <string name="backup_confirm_overwrite">Voulez-vous remplacer la sauvegarde existante de %s ?</string>
+ <string name="restore_confirm_overwrite">Voulez vous remplacer %s sur votre appareil par la sauvegarde ?</string>
<string name="init_restore_success">Restauration terminée.</string>
<string name="init_restore_failed">Échec de la restauration.</string>
<string name="init_restore_running">Restauration de la base de données des caches…</string>
@@ -602,6 +625,7 @@
</plurals>
<string name="cache_waypoints_add">Ajouter une étape</string>
<string name="cache_hint">Indice</string>
+ <string name="cache_hint_not_available">Aucun indice disponible</string>
<string name="cache_logs">Carnet de bord</string>
<string name="cache_logs_friends_and_own">Vous / amis</string>
<string name="cache_dialog_loading_details">Chargement des détails…</string>
@@ -641,9 +665,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Navigateur</string>
<string name="cache_menu_visit">Carnet</string>
- <string name="cache_menu_visit_offline">Enregistrer la visite hors-ligne</string>
+ <string name="cache_menu_visit_offline">Journal hors connexion en un clic</string>
<string name="cache_menu_spoilers">Images indices</string>
<string name="cache_menu_around">Alentours</string>
+ <string name="around">Autour de %s</string>
<string name="cache_menu_event">Ajouter à l\'agenda</string>
<string name="cache_menu_details">Détails</string>
<string name="cache_menu_refresh">Recharger</string>
@@ -653,6 +678,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Noter</string>
+ <string name="cache_menu_checker">Ouvrir le geovérificateur</string>
+ <string name="cache_menu_ignore">Ignorer la cache</string>
<string name="cache_status">Statut</string>
<string name="cache_status_offline_log">Visite sauvée hors-ligne</string>
<string name="cache_status_found">Trouvée</string>
@@ -738,6 +766,7 @@
<string name="waypoint_note">Note</string>
<string name="waypoint_visited">Marquer comme visité</string>
<string name="waypoint_save">Sauver</string>
+ <string name="waypoint_cancel_edit">Annuler</string>
<string name="waypoint_loading">Chargement d\'une étape…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Ne pas modifier les coordonnées de la cache</string>
<string name="waypoint_set_as_cache_coords">Utiliser comme coordonnées de la cache dans c:geo</string>
@@ -762,6 +791,8 @@
<string name="search_clear_history">Effacer l\'historique</string>
<string name="search_history_cleared">Historique effacé</string>
<string name="waypoint_coordinate_formats_plain">Texte</string>
+ <string name="from_clipboard">Depuis le presse-papiers</string>
+ <string name="copy_to_clipboard">Copier dans le presse-papiers</string>
<string name="visit_tweet">Publier votre découverte sur Twitter</string>
<string name="map_map">Carte</string>
<string name="map_live">Carte active</string>
@@ -866,7 +897,7 @@
<string name="helper_contacts_description">Permet d\'ouvrir une fiche de contact (depuis le carnet d\'adresses) directement depuis une entrée de journal, de manière à pouvoir plus facilement appeler des amis à l\'aide.</string>
<string name="helper_sendtocgeo_description">Envoyer à c:geo (<i>Send to c:geo</i>) est une extension pour le navigateur <strong>de votre ordinateur</strong>. Lorsque vous naviguez sur geocaching.com, vous pouvez envoyer des caches vers votre smartphone avec un clic.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Application simple affichant des cartes en ligne et hors ligne. Permet d\'enregistrer son parcours, de gérer des POI et de nombreuses autres fonctions utiles.</string>
+ <string name="helper_locus_description">Application pour la navigation en plein air pour téléphone ou tablette. Visualisez les cartes hors-lignes, enregistrez le chemin parcouru, cherchez les géocaches, utilisez le guidage vocal et plus.</string>
<string name="helper_gpsstatus_title">Etat GPS</string>
<string name="helper_gpsstatus_description">Vous pouvez utiliser le radar de cette application dans c:geo. Il gère des informations supplémentaires relatives au GPS.</string>
<string name="helper_bluetoothgps_title">GPS Bluetooth</string>
@@ -1118,13 +1149,15 @@
<string name="attribute_offset_cache_no">Pas de cache relative</string>
<string name="quote">Pour faciliter le géocaching.</string>
<string name="powered_by">carnero</string>
- <string name="support">support: <a href="">support@cgeo.org</a></string>
- <string name="website">site: <a href="">cgeo.org</a></string>
- <string name="facebook">facebook: <a href="">page c:geo</a></string>
- <string name="twitter">twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo sur Google Play</a></string>
+ <string name="support_title">Assistance</string>
+ <string name="website_title">Site web</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">Page de c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo sur Google Play</a></string>
<string name="about_twitter">Voulez-vous publier un nouveau statut sur Twitter à chaque nouvelle cache découverte sous <b>c:geo</b>?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Nouvelle version disponible.\nCliquer pour installer.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nouvelle version de test disponible.\nCliquer pour installer.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Nouvelle version candidate disponible.\nCliquer pour installer.</string>
@@ -1169,7 +1202,7 @@
<item quantity="one">%s favori</item>
<item quantity="other">%s favoris</item>
</plurals>
- <string name="percent_favorite_points">%\ favoris</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoris</string>
<string name="cgeo_shortcut">c:geo raccourci</string>
<string name="create_shortcut">Créer un raccourci</string>
<string name="send">Envoyer</string>
@@ -1179,6 +1212,8 @@
<string name="showcase_main_text">c:geo place maintenant les entrées de menu dans la barre de titre. Certaines sont cachées derrière les trois points. Un appui long donne la description d\'un bouton.</string>
<string name="showcase_cachelist_title">Changer de liste</string>
<string name="showcase_cachelist_text">Vous pouvez basculer entre vos différentes listes en cliquant sur le nom de la liste courante.</string>
+ <string name="showcase_compass_hint_title">Afficher l\'indice</string>
+ <string name="showcase_compass_hint_text">Cette nouvelle entrée de menu peut vous aider à trouver la géocache - elle montre l\'indice, s\'il y en a un.</string>
<string name="confirm_log_title">Type inhabituel d\'entrée de journal</string>
<string name="confirm_log_message">Vous allez envoyer \'%s\'. Êtes-vous sûr(e) ?</string>
</resources>
diff --git a/main/res/values-hu/strings.xml b/main/res/values-hu/strings.xml
index 8352fb8..84a8658 100644
--- a/main/res/values-hu/strings.xml
+++ b/main/res/values-hu/strings.xml
@@ -15,9 +15,9 @@
<string name="multi">Multi-láda</string>
<string name="mystery">Rejtvény láda</string>
<string name="letterbox">Postaláda hibrid</string>
- <string name="event">Esemény láda</string>
- <string name="mega">Mega-esemény láda</string>
- <string name="giga">Giga-esemény geoláda</string>
+ <string name="event">Esemény</string>
+ <string name="mega">Mega esemény</string>
+ <string name="giga">Giga esemény</string>
<string name="earth">Earthcache</string>
<string name="cito">CITO esemény</string>
<string name="webcam">Webkamera láda</string>
@@ -74,12 +74,13 @@
<string name="log_tb_visit">Látogatás</string>
<string name="log_tb_drop">Ládába helyezés</string>
<string name="log_tb_changeall">Az összes megváltoztatása</string>
- <string name="log_save">Mentés</string>
+ <string name="log_save">Offline mentés</string>
<string name="log_saving">Log mentése…</string>
<string name="log_saving_and_uploading">Log beküldése és kép feltöltése…</string>
<string name="log_clear">Törlés</string>
<string name="log_post_not_possible">Log oldal betöltése…</string>
<string name="log_add">Hozzáadás</string>
+ <string name="log_repeat">Utolsó log ismétlése</string>
<string name="log_no_rating">Nincs értékelés</string>
<string name="log_stars_1_description">nagyon rossz</string>
<string name="log_stars_15_description">elég rossz</string>
@@ -124,6 +125,7 @@
<string name="err_login">Nincs mentett belépési adat</string>
<string name="err_login_failed_toast">Sajnos a c:geo nem tud belépni. A c:geo hálózat nélküli módban fut. Ellenőrizd a belépési adataid a beállításoknál vagy engedélyezd az internet kapcsolatot.</string>
<string name="err_unknown">Ismeretlen hiba</string>
+ <string name="err_unknown_address">A c:geo nem tudta leképezni ezt a címet egy létező helyszínre</string>
<string name="err_comm">Ismeretlen kommunikációs hiba</string>
<string name="err_missing_auth">Nincs megadva belépési név és/vagy jelszó.</string>
<string name="err_wrong">Rossz belépési adatok</string>
@@ -152,13 +154,12 @@
<string name="err_dwld_details_failed">Sajnáljuk, a c:geo nem tudja letölteni a láda adatait.</string>
<string name="err_load_descr_failed">Sajnáljuk, a c:geo nem tudja betölteni a leírást.</string>
<string name="err_location_unknown">A c:geo nem ismeri a láda helyét.</string>
- <string name="err_missing_device_name">Kérlek, regisztráció előtt írd be az eszköz nevét.</string>
+ <string name="err_missing_device_name">Kérlek, regisztráció előtt adj meg egy készüléknevet.</string>
<string name="err_favorite_failed">Kedvenc állapotmódosítása nem sikerült.</string>
<string name="err_select_logimage_failed">Kép kiválasztása sikertelen.</string>
<string name="err_acquire_image_failed">A kép készítése nem sikerült.</string>
<string name="err_tb_display">Sajnáljuk, a c:geo nem tudja megjeleníteni a követhető tárgyat. Biztos, hogy ez egy követhető tárgy?</string>
<string name="err_tb_details_open">Sajnáljuk, a c:geo nem tudja megnyitni a követhető tárgy leírását.</string>
- <string name="err_tb_forgot_saw">Sajnáljuk, a c:geo elfelejtette, melyik követhető tárgyat láttad.</string>
<string name="err_tb_find">Sajnáljuk, a c:geo nem találja a követhető tárgyat.</string>
<string name="err_tb_find_that">Sajnáljuk, a c:geo nem találja azt a követhető tárgyat.</string>
<string name="err_waypoint_cache_unknown">Sajnáljuk, a c:geo nem tudja melyik ládához szeretnéd hozzáadni az útpontot.</string>
@@ -166,15 +167,13 @@
<string name="err_point_unknown_position">Sajnáljuk, a c:geo nem tudja felismerni hol vagy.</string>
<string name="err_point_no_position_given_title">Információ szükséges</string>
<string name="err_point_no_position_given">Ãrd be legalább a szélességi és hosszúsági vagy a távolsági és irány értéket. Megadhatod mind a négyet is.</string>
- <string name="err_point_curr_position_unavailable">A c:geo továbbra sem ismeri a jelenlegi koordinátákat. Kérlek várj egy ideig.</string>
<string name="err_point_bear_and_dist_title">Segítségre van szükséged?</string>
<string name="err_point_bear_and_dist">Tölsd ki az irányt és a távolságot is. Az irány az északkal bezárt szög 0 és 360 fok között. A távolság mértékegységgel és mértékegység nélkül is állhat.</string>
<string name="err_log_load_data">Sajnáljuk, a c:geo nem tudja betölteni a megtalálás bejelentéséhez szükségesek adatokat.</string>
<string name="err_log_load_data_again">Sajnáljuk, a c:geo nem tudja betölteni a megtalálás bejelentéséhez szükségesek adatokat. Újrapróbálkozás.</string>
<string name="err_log_load_data_still">A c:geo még tölti a megtalálás bejelentéséhez szükségesek adatokat. Kérlek, várj egy kicsit tovább.</string>
- <string name="err_log_post_failed">Úgy tűnik, a logod nem került hozzáadásra. Kérlek, ellenőrizd a geocaching.com-on.</string>
- <string name="err_log_post_failed_ec">Úgy tűnik, hogy a logod nem került hozzáadásra. Kérlek, ellenőrizd a geocaching.com-on!</string>
- <string name="err_logimage_post_failed">Úgy tűnik, hogy a log képed feltöltése nem sikerült. Kérjük, ellenőrizd a geocaching.com-on!</string>
+ <string name="err_log_post_failed">Úgy tűnik, hogy a logod nem ment át. Kérlek, ellenőrizd a láda eredeti oldalát.</string>
+ <string name="err_logimage_post_failed">Úgy tűnik, hogy a logfotóid nem mentek át. Kérlek, ellenőrizd a láda eredeti oldalát.</string>
<string name="err_search_address_forgot">Sajnáljuk, a c:geo elfelejtette a keresett címet.</string>
<string name="err_parse_lat">Sajnáljuk, a c:geo nem tudja értelmezni a szélességet.</string>
<string name="err_parse_lon">Sajnáljuk, a c:geo nem tudja értelmezni a hosszúságot.</string>
@@ -210,6 +209,8 @@
<string name="loc_last">Utolsó ismert</string>
<string name="loc_net">Hálózat</string>
<string name="loc_fused">Kombinált</string>
+ <string name="loc_low_power">Takarékos üzemmód</string>
+ <string name="loc_home">Otthon koordinátái</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Műhold</string>
<string name="loc_trying">Keresés folyamatban</string>
@@ -223,12 +224,11 @@
<string name="menu_filter">Szűrő</string>
<string name="menu_scan_geo">Geokód szkennelése</string>
<string name="menu_pocket_queries">Pocket lekérdezések</string>
- <string name="menu_scan_description">A c:geo QR formátumó geokódokat is be tud olvasni, de az ehhez szükséges alkalmazás nincs telepítve. Szeretné megnyitni a Google Play-t, hogy telepítse?</string>
+ <string name="menu_scan_description">A c:geo QR formátumú geokódokat is be tud olvasni, de az ehhez szükséges alkalmazás nincs telepítve. Szeretné megnyitni a Google Play-t, hogy telepítse?</string>
<string name="live_map_button">Élő térkép</string>
<string name="caches_nearby_button">A közelben</string>
<string name="advanced_search_button">Keresés</string>
<string name="stored_caches_button">Mentett</string>
- <string name="any_button">Szabad cél</string>
<string name="unknown_scan">Nem található geokód a scannelés eredményében.</string>
<string name="caches_no_cache">Nem található láda</string>
<string name="caches_more_caches">Nem elég? Keress több ládát!</string>
@@ -254,23 +254,29 @@
<string name="caches_sort_favorites_ratio">kedvencek [%]</string>
<string name="caches_sort_name">név</string>
<string name="caches_sort_geocode">GC-kód</string>
- <string name="caches_sort_rating">osztályzat</string>
- <string name="caches_sort_vote">szavazat (saját osztályzat)</string>
+ <string name="caches_sort_rating">értékelés</string>
+ <string name="caches_sort_vote">szavazat (saját értékelés)</string>
<string name="caches_sort_inventory">tárgyak száma</string>
<string name="caches_sort_date_hidden">rejtés dátuma</string>
<string name="caches_sort_date_logged">log dátuma</string>
<string name="caches_sort_finds">megtalálások</string>
<string name="caches_sort_state">állapot</string>
- <string name="caches_sort_storage">Az eszközön tárolt dátum</string>
+ <string name="caches_sort_storage">A készüléken tárolt dátum</string>
<string name="caches_select_mode">Kiválasztó mód</string>
<string name="caches_select_mode_exit">Kilépés a kiválasztó módból</string>
<string name="caches_select_invert">Kijelölés megfordítása</string>
<string name="caches_nearby">Közeli</string>
<string name="caches_manage">Kezelés</string>
<string name="caches_remove_all">Összes eltávolítása</string>
- <string name="caches_remove_all_confirm">Szeretnéd eltávolítani az összes (%s) ládát a jelenlegi csoportból?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">El akarod távolítani ezt a ládát az aktuális listából?</item>
+ <item quantity="other">El akarod távolítani a(z) %d ládát az aktuális listából?</item>
+ </plurals>
<string name="caches_remove_selected">Kijelölt ládák eltávolítása</string>
- <string name="caches_remove_selected_confirm">Szeretnéd a kijelölt %s ládát törölni az eszközödről?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">El akarod távolítani ezt a ládát a készülékedről?</item>
+ <item quantity="other">El akarod távolítani a kijelölt %d ládát a készülékedről?</item>
+ </plurals>
<string name="caches_remove_progress">Ládák törlése</string>
<string name="caches_delete_events">Korábbi események törlése</string>
<string name="caches_refresh_selected">Kijelöltek frissítése</string>
@@ -285,18 +291,22 @@
<string name="caches_recaptcha_continue">Folytatás</string>
<string name="caches_filter">Szűrő</string>
<string name="caches_filter_title">Szűrés eszerint</string>
- <string name="caches_filter_size">méret</string>
- <string name="caches_filter_type">típus</string>
- <string name="caches_filter_track">követhető tárgyak</string>
- <string name="caches_filter_clear">szűrők törlése</string>
- <string name="caches_filter_modified">Módosított koordinátákkal</string>
+ <string name="caches_filter_size">Méret</string>
+ <string name="caches_filter_type">Típus</string>
+ <string name="caches_filter_track">Követhető tárgyak</string>
+ <string name="caches_filter_clear">Szűrők törlése</string>
+ <string name="caches_filter_modified">Módosított koordináták</string>
<string name="caches_filter_origin">Származás</string>
<string name="caches_filter_distance">Távolság</string>
- <string name="caches_filter_personal_note">Személyes megjegyzéssel ellátottak</string>
+ <string name="caches_filter_personal_note">Személyes megjegyzés</string>
<string name="caches_filter_popularity">Kedvencek</string>
<string name="caches_filter_popularity_ratio">Kedvencek [%]</string>
+ <string name="caches_filter_personal_data">Személyes adatok</string>
+ <string name="caches_filter_rating">Értékelés</string>
+ <string name="caches_filter_own_rating">Saját értékelés</string>
<string name="caches_removing_from_history">Eltávolítás a Előzményekből…</string>
<string name="caches_clear_offlinelogs">Offline logok törlése</string>
+ <string name="caches_clear_offlinelogs_message">Szeretnéd törölni az offline logokat?</string>
<string name="caches_clear_offlinelogs_progress">Offline logok törlése folyamatban</string>
<string name="list_menu_create">Új lista létrehozása</string>
<string name="list_menu_drop">Jelenlegi lista elvetése</string>
@@ -319,13 +329,16 @@
<string name="list_not_available">A csoport már nem elérhető, váltás az alapértelmezett csoportra</string>
<string name="about_version">Verzió</string>
<string name="about_changelog">Változások</string>
+ <string name="about_system">Rendszer</string>
<string name="about_donate">Adományozás</string>
<string name="about_donation_more">Adomány\na fejlesztéshez</string>
<string name="about_contributors">Hozzájárulók</string>
<string name="about_license">Licensz</string>
<string name="about_apache_license"><a href=""> Apache License, 2.0 verzió</a></string>
<string name="about_help">Segítség</string>
+ <string name="about_system_include">Kérlek, csatold a következő rendszerinformációt, ha hibajelentést küldesz, vagy további információt kérsz a c:geo-ról:</string>
<string name="settings_title_services">Szolgáltatók</string>
+ <string name="settings_summary_services">A felhasználói fiók adatainak és a választható szolgáltatásokhoz való hozzáférés beállítása.</string>
<string name="settings_title_appearance">Megjelenítés</string>
<string name="settings_title_cachedetails">Geoláda részletek</string>
<string name="settings_title_offlinedata">Offline adatok</string>
@@ -373,6 +386,9 @@
<string name="settings_activate_oc_uk">Aktiválás</string>
<string name="init_oc_uk_description">c:geo engedélyezése az opencaching.org.uk-ra, hogy geoládákat kereshessen és hozzáférhessen ill. szűrhessen a megtalált geoládáidra.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Ládák értékeléséhez kövesd az utasításokat a GCVote.com-on és add meg itt a GCVote jelszavad.</string>
+ <string name="err_gcvote_send_rating">Sikertelen az értélkelés elküldése, ellenőrizd a GCVote jelszavad a beállításoknál. Próbálkozz a törlésével.</string>
+ <string name="gcvote_sent">Az értékelés sikeresen elment</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktiválás</string>
<string name="init_username">Felhasználónév</string>
@@ -384,7 +400,7 @@
<string name="init_login_popup_failed">Belépés sikertelen.</string>
<string name="init_login_popup_failed_reason">Belépés sikertelen, mert </string>
<string name="init_login_popup_not_authorized">Nem engedélyezett</string>
- <string name="init_login_popup_invalid_timestamp">A helyi idő érvénytelen, állítsd be a telefon óráját</string>
+ <string name="init_login_popup_invalid_timestamp">A helyi idő érvénytelen, állítsd be a készülék óráját</string>
<string name="init_login_popup_invalid_token">Sikertelen engedélyezés, próbáld újra</string>
<string name="settings_service_active">Aktív</string>
<string name="init_signature">Aláírás</string>
@@ -492,10 +508,17 @@
<string name="init_maintenance_directories_note">A c:geo az egyes geoládákhoz képeket, logokat és egyéb fájlokat tárol egy külön mappában. Bizonyos esetekben (pl. adatbázis importja vagy exportja) ez a mappa már fölösleges adatokat tartalmazhat, amelyek ezzel a funkcióval törölhetők.</string>
<string name="init_maintenance_directories">Szükségtelen fájlok törlése</string>
<string name="init_location">Helymeghatározás</string>
+ <string name="init_location_note">A Google Play Szolgáltatásokat használó készülékeken a c:geo automatikusan egy jobb helymeghatározó technikát használ. Ez azonban lehetetlenné teszi külső, BlueTooth-os GPS vevő alkalmazását.</string>
<string name="init_location_googleplayservices">Google Play Szolgáltatások használata</string>
+ <string name="init_low_power">Takarékos üzemmód</string>
+ <string name="init_low_power_note">A takarékos üzemmód nem használja a GPS-t és a giroszkópot, emiatt a helymeghatározás lassabb és pontatlanabb.</string>
+ <string name="init_low_power_mode">Takarékos üzemmód indítása</string>
<string name="init_create_memory_dump">Memóriatartalom mentése</string>
<string name="init_memory_dump">Memóriatartalom</string>
<string name="init_memory_dumped">Memóriatartalom mentve a %s-n</string>
+ <string name="init_hardware_acceleration_title">Megjelenítés hardveres gyorsítással</string>
+ <string name="init_hardware_acceleration_note">Hardveres gyorsítással gyorsabban jelennek meg a grafikus elemek a képernyőn. Azonban néhány készüléken az Android hibákat tartalmaz és némely szöveg homályosan jelenhet meg (különösen a félkövér karakterek). Tiltsd le a hardveres gyorsítást, ha ezt tapasztalod.</string>
+ <string name="init_hardware_acceleration">Hardveres gyorsítás engedélyezése</string>
<string name="settings_open_website">Weboldal megnyitása</string>
<string name="settings_settings">Beállítások</string>
<string name="settings_information">További információk</string>
@@ -524,14 +547,14 @@
<string name="map_source_osm_offline">Offline</string>
<string name="init_sendToCgeo">Küldés c:geo-nak</string>
<string name="settings_info_send2cgeo_title">Információk a \'Küldés c:geo-nak\'-ról</string>
- <string name="init_sendToCgeo_name">Az eszközöd neve</string>
- <string name="init_sendToCgeo_description">A <b>\'Küldés c:geo-nak\'</b> segítségével közvetlenül a geocaching weboldalról tölthetsz le ládákat egy Firefox vagy Chrome modul segítségével. Regisztráció előtt olvasd el a leírást <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Csak akkor kell regisztrálnod, ha a \'Küldés c:geo-nak\' modult használni akarod. A c:geo a regisztráció nélkül is működik.</string>
+ <string name="init_sendToCgeo_name">Készüléked neve</string>
+ <string name="init_sendToCgeo_description">A <b>send2c:geo</b> segítségével közvetlenül a geocaching weboldalról tölthetsz le ládákat egy Firefox vagy Chrome modul segítségével. Regisztráció előtt olvasd el a leírást <a href="http://send2.cgeo.org/">http://send2.cgeo.org/</a>. Csak akkor kell regisztrálnod, ha a send2c:geo modult használni akarod. A c:geo a regisztráció nélkül is működik.</string>
<string name="init_sendToCgeo_register">Regisztráció kérése</string>
- <string name="init_sendToCgeo_registering">Az eszközöd regisztrációja a \'Küldés c:geo-nak\' modulhoz…</string>
- <string name="init_sendToCgeo_register_ok">A regisztráció sikeres. A PIN kód ####. Használd ezt a kódot a c:geo weboldalán, hogy hozzáadd ezt az eszközt a böngészőhöz.</string>
+ <string name="init_sendToCgeo_registering">Készüléked regisztrációja a send2c:geo modulhoz…</string>
+ <string name="init_sendToCgeo_register_ok">A regisztráció sikeres. A PIN kód ####. Használd ezt a kódot a c:geo weboldalán, hogy hozzáadd ezt a készüléket a böngészőhöz.</string>
<string name="init_sendToCgeo_register_fail">Regisztráció sikertelen.</string>
- <string name="sendToCgeo_download_fail">A c:geo nem tudta letölteni a ládákat. Nincs internetkapcsolat vagy a \'Küldés c:geo-nak\' leállt.</string>
- <string name="sendToCgeo_no_registration">A c:geo nem tudta letölteni a ládákat. A \'Küldés c:geo-nak\' regisztrációd lejárt. Kérlek regisztrálj a beállításoknál.</string>
+ <string name="sendToCgeo_download_fail">A c:geo nem tudta letölteni a ládákat. Nincs internetkapcsolat vagy a send2c:geo leállt.</string>
+ <string name="sendToCgeo_no_registration">A c:geo nem tudta letölteni a ládákat. A send2c:geo regisztrációd lejárt. Kérlek, regisztrálj a beállításoknál.</string>
<string name="auth_twitter">Twitter</string>
<string name="auth_authorize">Hozzáférés engedélyezése a c:geo-nak</string>
<string name="auth_start">Engedélyezés indítása</string>
@@ -566,7 +589,7 @@
<string name="cache_premium">Prémium</string>
<string name="cache_attributes">Tulajdonságok</string>
<string name="cache_inventory">Tárgyak</string>
- <string name="cache_log_images_title">Bejegyzés kép</string>
+ <string name="cache_log_images_title">Logfotók</string>
<string name="cache_log_image_default_title">Fotó</string>
<string name="cache_personal_note">Személyes megjegyzés</string>
<string name="cache_personal_note_edit">Szerkesztés</string>
@@ -637,7 +660,7 @@
<string name="cache_menu_streetview">Utcanézet</string>
<string name="cache_menu_browser">Megnyitás böngészőben</string>
<string name="cache_menu_visit">Megtalálás bejelentése</string>
- <string name="cache_menu_visit_offline">Megtalálás bejelentése offline</string>
+ <string name="cache_menu_visit_offline">Offline log egy kattintással</string>
<string name="cache_menu_spoilers">Spoiler képek</string>
<string name="cache_menu_around">Közeli ládák</string>
<string name="cache_menu_event">Hozzáadás a naptárhoz</string>
@@ -649,6 +672,8 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble (okosóra)</string>
+ <string name="cache_menu_android_wear">Android Wear</string>
+ <string name="cache_menu_vote">Értékelés</string>
<string name="cache_status">Ãllapot</string>
<string name="cache_status_offline_log">Mentett bejegyzés</string>
<string name="cache_status_found">Megtalált</string>
@@ -666,7 +691,7 @@
<string name="cache_distance">Távolság</string>
<string name="cache_difficulty">Nehézség</string>
<string name="cache_terrain">Terep</string>
- <string name="cache_rating">Osztályzat</string>
+ <string name="cache_rating">Értékelés</string>
<string name="cache_own_rating">Saját értékelés</string>
<string name="cache_rating_of">/</string>
<string name="cache_favorite">Kedvenc</string>
@@ -758,6 +783,7 @@
<string name="search_clear_history">Előzmények törlése</string>
<string name="search_history_cleared">Előzmények törölve</string>
<string name="waypoint_coordinate_formats_plain">Egyszerű</string>
+ <string name="from_clipboard">A vágólapról</string>
<string name="visit_tweet">Twitteld ki ezt a megtalálást</string>
<string name="map_map">Térkép</string>
<string name="map_live">Élő térkép</string>
@@ -856,13 +882,13 @@
<string name="license_dismiss">Elutasítás</string>
<string name="helper_calendar_title">c:geo naptár add-on</string>
<string name="helper_calendar_missing">c:geo naptár add-on nincs telepítve.</string>
- <string name="helper_calendar_description">Lehetővé teszi a geoládák exportálását az eszközöd naptárába.</string>
+ <string name="helper_calendar_description">Események exportálása a készüléked naptárába.</string>
<string name="helper_sendtocgeo_title">Küldés a c:geo-ra</string>
<string name="helper_contacts_title">c:geo kapcsolatok add-on</string>
<string name="helper_contacts_description">Lehetővé teszi egy névjegy közvetlen megnyitását a log bejegyzésekből, így könnyebben segítséget tudsz kérni.</string>
<string name="helper_sendtocgeo_description">A \'Küldés a c:geo-ra\' egy böngésző bővítmény <strong>PC-re</strong>. A geocaching.com böngészése közben, egy kattintással tudsz geoládákat küldeni az okostelefonodra.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Egyszerűen kezelhető alkalmazás online térképek megjelenítésére, amelyeket le is tud tölteni offline használatra (csak raszteres térképekkel működik). Támogatja a nyomvonalrögzítést, érdekes pontok kezelést és sok egyéb hasznos funkciót.</string>
+ <string name="helper_locus_description">Telefonodon, tableteden használható szabadtéri navigációs progi. Offline térképek használata, útvonal követése, ládavadászat, hangos útikalauz, stb.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">A programban található radart a c:geo-hoz is használhatod. Sok egyéb GPS-el kapcsolatos információt is megmutat.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1114,13 +1140,7 @@
<string name="attribute_offset_cache_no">Nem offset láda</string>
<string name="quote">Az egyszerűbb ládázásért, a lustább játékosokért.</string>
<string name="powered_by">carnero</string>
- <string name="support">Támogatás: <a href="">support@cgeo.org</a></string>
- <string name="website">Weboldal: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Androidra: <a href="">c:geo a Google Play-en</a></string>
<string name="about_twitter">Akarod, hogy a <b>c:geo</b> új bejegyzést írjon a Twitter-re, amikor megtalálsz egy ládát?</string>
- <string name="faq">GYIK: <a href="">faq.cgeo.org</a></string>
<string name="status_new_release" tools:ignore="UnusedResources">Új kiadás jelent meg.\nKattints a telepítéshez.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Új napi frissítés jelent meg.\nKattints a telepítéshez.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Új kiadás előtti verzió jelent meg.\nKattints a telepítéshez.</string>
@@ -1165,8 +1185,16 @@
<item quantity="one">%s kedvenc pont</item>
<item quantity="other">%s kedvenc pont</item>
</plurals>
- <string name="percent_favorite_points">%\ kedvenc pont</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% kedvenc pont</string>
<string name="cgeo_shortcut">c:geo parancsikon</string>
<string name="create_shortcut">Parancsikon létrehozása</string>
<string name="send">Küldés</string>
+ <string name="showcase_logcache_title">Log küldése</string>
+ <string name="showcase_logcache_text">Ne feledd, sok parancs található a címsorban. Ott találod a kész logot elküldő gombot is.</string>
+ <string name="showcase_main_title">Új menük</string>
+ <string name="showcase_main_text">A c:geo is a címsorban jeleníti meg a menüelemeket más modern appokhoz hasonlóan. Néhány elemet a pontozott szimbólum mögött találsz. A gombokat hosszan lenyomva jelennek meg a hozzájuk tartozó leírások.</string>
+ <string name="showcase_cachelist_title">Listák váltása</string>
+ <string name="showcase_cachelist_text">Váltogathatsz a ládalistáid között a listák címére kattintva.</string>
+ <string name="confirm_log_title">Különleges logtípus</string>
+ <string name="confirm_log_message">Logod a következő: \'%s\'. Biztosan ezt akarod?</string>
</resources>
diff --git a/main/res/values-it/strings.xml b/main/res/values-it/strings.xml
index e079b1d..1a379ea 100644
--- a/main/res/values-it/strings.xml
+++ b/main/res/values-it/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Visitato</string>
<string name="log_tb_drop">Lasciato</string>
<string name="log_tb_changeall">Cambia tutto</string>
- <string name="log_save">Salva</string>
+ <string name="log_save">Salva offline</string>
<string name="log_saving">Invio log…</string>
<string name="log_saving_and_uploading">Invio log e immagine…</string>
<string name="log_clear">Azzera</string>
<string name="log_post_not_possible">Connessione…</string>
+ <string name="log_date_future_not_allowed">Non sono ammesse date future per i log.</string>
<string name="log_add">Aggiungi</string>
+ <string name="log_repeat">Ripeti l\'ultimo log</string>
<string name="log_no_rating">Nessun voto</string>
<string name="log_stars_1_description">proprio brutto</string>
<string name="log_stars_15_description">abbastanza brutto</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Log Password:</string>
<string name="log_hint_log_password">Inserisci la password per il log</string>
<string name="log_oc_team_comment">Commenti del Team OC</string>
+ <string name="log_your_saved_log">I tuoi log salvati</string>
<string-array name="log_image_scales">
<item>Dimensioni originali</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Informazioni di login non memorizzate</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>
<string name="err_unknown">Errore sconosciuto</string>
+ <string name="err_unknown_address">c:geo non è in grado di mappare questo indirizzo su una posizione gps esistente</string>
<string name="err_comm">Errore sconosciuto di comunicazione</string>
<string name="err_missing_auth">username e/o password non settati.</string>
<string name="err_wrong">Informazioni di login errate</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Acquisizione immagine fallita.</string>
<string name="err_tb_display">c:geo non riesce a visualizzare il trackable che vuoi. È veramente un trackable?</string>
<string name="err_tb_details_open">c:geo non riesce ad aprire i dettagli del trackable.</string>
- <string name="err_tb_forgot_saw">c:geo ha dimenticato quale trackable vedevi.</string>
<string name="err_tb_find">c:geo non trova nessun trackable</string>
<string name="err_tb_find_that">c:geo non trova quel trackable.</string>
<string name="err_waypoint_cache_unknown">c:geo non conosce a quale cache vuoi aggiungere un waypoint.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo non capisce dove ti trovi.</string>
<string name="err_point_no_position_given_title">Info richieste</string>
<string name="err_point_no_position_given">Inserisci almeno latitudine e longitudine, o distanza e angolo. Puoi anche inserire tutti e quattro i valori.</string>
- <string name="err_point_curr_position_unavailable">c:geo non ha le coordinate attuali. Attendere, prego…</string>
<string name="err_point_bear_and_dist_title">Necessiti di aiuto?</string>
<string name="err_point_bear_and_dist">Inserisci angolo e distanza. Angolo specifica un valore in gradi tra 0 e 360 relativo al nord. La distanza non richiede unità di misura.</string>
<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_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_log_post_failed">Sembra che il log non sia stato pubblicato. Si prega di controllare sul sito Web del cache originario.</string>
+ <string name="err_logimage_post_failed">Sembra che l\'immagine del registro non sia stata caricata. Si prega di controllare sul sito Web del cache originario.</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>
<string name="err_parse_lon">c:geo non riesce ad interpretare la longitudine.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Network</string>
<string name="loc_fused">Combinato</string>
<string name="loc_low_power">Risparmio energetico</string>
+ <string name="loc_home">Coordinate di casa</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Localizzazione in corso</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Vicini</string>
<string name="advanced_search_button">Cerca</string>
<string name="stored_caches_button">Salvati</string>
- <string name="any_button">Ovunque</string>
+ <string name="any_button">Vai a</string>
<string name="unknown_scan">Nessun geocode trovato nello scan.</string>
<string name="caches_no_cache">Non ci sono cache</string>
<string name="caches_more_caches">Carica altri cache</string>
@@ -263,15 +265,18 @@
<string name="caches_sort_finds">Numero ritrovamenti</string>
<string name="caches_sort_state">Stato</string>
<string name="caches_sort_storage">Data salvataggio</string>
+ <string name="caches_sort_eventdate">Data Evento</string>
<string name="caches_select_mode">Modo Selezione</string>
<string name="caches_select_mode_exit">Esci dal modo Selezione</string>
<string name="caches_select_invert">Inverti selezione</string>
<string name="caches_nearby">Qui vicino</string>
<string name="caches_manage">Gestisci</string>
<string name="caches_remove_all">Elimina tutti</string>
- <string name="caches_remove_all_confirm">Vuoi rimuovere tutti i %s cache dalla lista corrente?</string>
<string name="caches_remove_selected">Elimina selezionati</string>
- <string name="caches_remove_selected_confirm">Vuoi rimuovere i %s cache selezionati dal dispositivo?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Si desidera rimuovere questo cache dal tuo dispositivo?</item>
+ <item quantity="other">Vuoi rimuovere i %d cache selezionati dal dispositivo?</item>
+ </plurals>
<string name="caches_remove_progress">Eliminazione dei cache</string>
<string name="caches_delete_events">Cancella eventi passati</string>
<string name="caches_refresh_selected">Aggiorna i cache selezionati</string>
@@ -291,13 +296,18 @@
<string name="caches_filter_track">Con oggetti trackables</string>
<string name="caches_filter_clear">Rimuovi filtri</string>
<string name="caches_filter_modified">Con coordinate modificate</string>
+ <string name="caches_filter_offline_log">Con log offline</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_filter_personal_data">Con dati personali</string>
+ <string name="caches_filter_rating">Con valutazione (rating)</string>
+ <string name="caches_filter_own_rating">Con propria valutazione (rating)</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_message">Vuoi cancellare tutti i log offline?</string>
<string name="caches_clear_offlinelogs_progress">Cancellazione logs offline</string>
<string name="list_menu_create">Crea nuova lista</string>
<string name="list_menu_drop">Elimina la lista corrente</string>
@@ -320,13 +330,17 @@
<string name="list_not_available">Elenco non più disponibile, passo a elenco standard</string>
<string name="about_version">Versione</string>
<string name="about_changelog">Modifiche</string>
+ <string name="about_system">Sistema</string>
<string name="about_donate">Donazioni</string>
<string name="about_donation_more">Fai una\nDonazione</string>
<string name="about_contributors">Contributori</string>
<string name="about_license">Licenza</string>
<string name="about_apache_license"><a href="">Licenza Apache, versione 2.0</a></string>
<string name="about_help">Guida</string>
+ <string name="about_system_include">Si prega di includere le seguenti informazioni di sistema quando si invia una segnalazione di bug o per chiedere ulteriori informazioni su c:geo:</string>
+ <string name="changelog_github">Elenco di tutte le modifiche</string>
<string name="settings_title_services">Servizi</string>
+ <string name="settings_summary_services">Configura le informazioni utente dell\'account ed accede a servizi opzionali.</string>
<string name="settings_title_appearance">Aspetto</string>
<string name="settings_title_cachedetails">Dettagli cache</string>
<string name="settings_title_offlinedata">Dati offline</string>
@@ -370,6 +384,9 @@
<string name="settings_activate_oc_uk">Attiva</string>
<string name="init_oc_uk_description">Autorizza c:geo a cercare cache ed accedere/filtrare i ritrovamenti su opencaching.org.uk.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Per poter votare un cache, è necessario seguire le istruzioni di GCVote.com e inserire la password di GCVote qui.</string>
+ <string name="err_gcvote_send_rating">Errore durante l\'invio del voto, verifica la password di GCVote nelle impostazioni oppure cancellala per disattivare GCVote.</string>
+ <string name="gcvote_sent">Voto inviato correttamente</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Attiva</string>
<string name="init_username">Utente</string>
@@ -440,6 +457,8 @@
<string name="init_backup_success">Il database di c:geo è stato salvato con successo nel file: </string>
<string name="init_backup_failed">Backup del database di c:geo fallito.</string>
<string name="init_backup_unnecessary">Il database è vuoto, il backup non è necessario.</string>
+ <string name="backup_confirm_overwrite">Vuoi sovrascrivere il backup esistente da %s?</string>
+ <string name="restore_confirm_overwrite">Vuoi sovrascrivere %s sul tuo dispositivo con il backup?</string>
<string name="init_restore_success">Ripristino completato.</string>
<string name="init_restore_failed">Ripristino fallito.</string>
<string name="init_restore_running">Ripristino del database dei cache…</string>
@@ -598,6 +617,7 @@
</plurals>
<string name="cache_waypoints_add">Aggiungi waypoint</string>
<string name="cache_hint">Aiuto (spoiler)</string>
+ <string name="cache_hint_not_available">Nessun aiuto disponibile</string>
<string name="cache_logs">Logbook</string>
<string name="cache_logs_friends_and_own">Log tuoi e degli amici</string>
<string name="cache_dialog_loading_details">Caricamento dettagli del cache…</string>
@@ -637,9 +657,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Apri nel browser</string>
<string name="cache_menu_visit">Scrivi Log</string>
- <string name="cache_menu_visit_offline">Scrivi Log offline</string>
+ <string name="cache_menu_visit_offline">Log offline con un solo click</string>
<string name="cache_menu_spoilers">Immagini spoiler</string>
<string name="cache_menu_around">Cache qui intorno</string>
+ <string name="around">Nei dintorni di %s</string>
<string name="cache_menu_event">Aggiungi al calendario</string>
<string name="cache_menu_details">Dettagli</string>
<string name="cache_menu_refresh">Aggiorna</string>
@@ -649,6 +670,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Vota</string>
+ <string name="cache_menu_checker">Open Geochecker</string>
+ <string name="cache_menu_ignore">Ignora cache</string>
<string name="cache_status">Stato</string>
<string name="cache_status_offline_log">Log salvato</string>
<string name="cache_status_found">Trovato</string>
@@ -734,6 +758,7 @@
<string name="waypoint_note">Note</string>
<string name="waypoint_visited">Visitato</string>
<string name="waypoint_save">Salva</string>
+ <string name="waypoint_cancel_edit">Annulla</string>
<string name="waypoint_loading">Caricamento waypoint…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Nessuna modifica alle coordinate cache</string>
<string name="waypoint_set_as_cache_coords">Setta come coordinate cache in c:geo</string>
@@ -758,6 +783,8 @@
<string name="search_clear_history">Cancella cronologia</string>
<string name="search_history_cleared">Cronologia azzerata</string>
<string name="waypoint_coordinate_formats_plain">Plain</string>
+ <string name="from_clipboard">Dagli appunti</string>
+ <string name="copy_to_clipboard">Copia nella Clipboard</string>
<string name="visit_tweet">Segnala questo ritrovamento su Twitter</string>
<string name="map_map">Mappa</string>
<string name="map_live">Mappa Live</string>
@@ -862,7 +889,7 @@
<string name="helper_contacts_description">Consente di aprire una scheda contatto (della tua rubrica) direttamente da un log, per permetterti di chiedere aiuto agli amici più facilmente.</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_locus_description">App per la navigazione in esterni per cellulare o tablet. Mostra mappe offline, traccia il tuo percorso, cerca geocache, usa una voce guida e molto altro.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Puoi usare il radar di questa applicazione con c:geo. Offre inoltre molte informazioni addizionali legate al GPS.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1114,13 +1141,15 @@
<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>
- <string name="website">Sito: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">Pagina c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo su Google Play</a></string>
+ <string name="support_title">Aiuto</string>
+ <string name="website_title">Sito Internet</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">pagina c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><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="faq_title">FAQ</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>
@@ -1165,7 +1194,7 @@
<item quantity="one">%s preferito</item>
<item quantity="other">%s preferiti</item>
</plurals>
- <string name="percent_favorite_points">%\ preferiti</string>
+ <string name="more_than_percent_favorite_points">&gt; preferiti %d%%</string>
<string name="cgeo_shortcut">collegamento a c:geo</string>
<string name="create_shortcut">Crea collegamento</string>
<string name="send">Invia</string>
@@ -1175,6 +1204,8 @@
<string name="showcase_main_text">c:geo ora ha le voci di menu nella barra del titolo come altre moderne applicazioni. Alcuni elementi potrebbero essere nascosti dietro il simbolo dei puntini. Tenere premuto un bottone per vederne la descrizione.</string>
<string name="showcase_cachelist_title">Cambio di liste</string>
<string name="showcase_cachelist_text">Puoi cambiare la lista attiva cliccando sul titolo.</string>
+ <string name="showcase_compass_hint_title">Visualizza l\'hint</string>
+ <string name="showcase_compass_hint_text">Questo nuovo menu potrebbe darti un\'idea di dove si trova il cache. Mostra l\'hint, se disponibile.</string>
<string name="confirm_log_title">Tipo di Log non usuale</string>
<string name="confirm_log_message">Si desidera registrare \'%s\'. Sei sicuro?</string>
</resources>
diff --git a/main/res/values-ja/strings.xml b/main/res/values-ja/strings.xml
index 0a2b143..0fa8aa0 100644
--- a/main/res/values-ja/strings.xml
+++ b/main/res/values-ja/strings.xml
@@ -54,7 +54,7 @@
<string name="log_attend">å‚加ã™ã‚‹</string>
<string name="log_attended">å‚加ã—ãŸ</string>
<string name="log_retrieved">回åŽã—ãŸ</string>
- <string name="log_placed">Placed</string>
+ <string name="log_placed">é…ç½®ã—ãŸ</string>
<string name="log_grabbed">ã©ã“ã‹ã§æ•ã¾ãˆãŸ</string>
<string name="log_movecollection">コレクションã«ç§»å‹•</string>
<string name="log_moveinventory">目録ã«ç§»å‹•</string>
@@ -70,8 +70,7 @@
<string name="log_tb_nothing">何もã—ãªã„</string>
<string name="log_tb_visit">訪れãŸ</string>
<string name="log_tb_drop">ã“ã“ã«ç½®ã</string>
- <string name="log_tb_changeall">Change All</string>
- <string name="log_save">ä¿å­˜</string>
+ <string name="log_tb_changeall">ã™ã¹ã¦ã‚’変更ã™ã‚‹</string>
<string name="log_saving">ログをé€ä¿¡ä¸­â€¦</string>
<string name="log_saving_and_uploading">ログã¨ç”»åƒã‚’é€ä¿¡ä¸­â€¦</string>
<string name="log_clear">消去</string>
@@ -101,8 +100,8 @@
<string name="log_image_caption">タイトル</string>
<string name="log_image_description">説明</string>
<string name="log_image_scale">拡大縮å°</string>
- <string name="log_password_title">Log Password:</string>
- <string name="log_hint_log_password">Enter your log password</string>
+ <string name="log_password_title">ログã®ãƒ‘スワード:</string>
+ <string name="log_hint_log_password">パスワードを入力ã—ã¦ãã ã•ã„</string>
<string-array name="log_image_scales">
<item>実サイズ</item>
<item>512 px</item>
@@ -126,7 +125,7 @@
<string name="err_maintenance">Geocaching.comã¯ãƒ¡ãƒ³ãƒ†ãƒŠãƒ³ã‚¹ä¸­ã§æŽ¥ç¶šã§ãã¾ã›ã‚“。 ä¿å­˜æ¸ˆã¿ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®ã¿ã§ã‚ªãƒ•ãƒ©ã‚¤ãƒ³ã§å‹•ä½œã—ã¾ã™ã€‚</string>
<string name="err_license">Geocaching.comã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹å¥‘ç´„ã«åŒæ„ã—ãªã‹ã£ãŸã®ã§ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®åº§æ¨™ã‚’見るã“ã¨ã¯ã§ãã¾ã›ã‚“。</string>
<string name="err_unvalidated_account">Geocaching.comã§ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’有効化ã—ã¦ãã ã•ã„。</string>
- <string name="err_unpublished">The requested cache is unpublished.</string>
+ <string name="err_unpublished">è¦æ±‚ã—ãŸã‚­ãƒ£ãƒƒã‚·ãƒ¥ãŒå…¬é–‹ã•ã‚Œã¦ã„ã¾ã›ã‚“。</string>
<string name="err_premium_only">ã“ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã¯ãƒ—レミアム会員ã®ã¿æœ‰åŠ¹ã§ã™ã€‚</string>
<string name="err_detail_open">キャッシュã®è©³ç´°ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“。</string>
<string name="err_detail_cache">キャッシュ情報を表示ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。ã“ã‚Œã¯æœ¬å½“ã«ã‚¸ã‚ªã‚­ãƒ£ãƒƒã‚·ãƒ¥ã§ã™ã‹?</string>
@@ -138,7 +137,7 @@
<string name="err_detail_no_map_static">ã“ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã®ã‚ªãƒ•ãƒ©ã‚¤ãƒ³åœ°å›³ã‚’見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</string>
<string name="err_detail_not_load_map_static">オフライン地図ã®ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸã€‚</string>
<string name="err_detail_still_working">ä»–ã®ã‚¿ã‚¹ã‚¯ãŒã¾ã å‹•ä½œä¸­ã§ã™ã€‚</string>
- <string name="err_watchlist_still_managing">Still managing your watchlist.</string>
+ <string name="err_watchlist_still_managing">ã¾ã ã‚¦ã‚©ãƒƒãƒãƒªã‚¹ãƒˆã‚’管ç†ä¸­ã§ã™ã€‚</string>
<string name="err_watchlist_failed">ウォッãƒãƒªã‚¹ãƒˆã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸã€‚</string>
<string name="err_application_no">é©åˆ‡ãªã‚¢ãƒ—リケーションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</string>
<string name="err_auth_initialize">èªè¨¼ãƒ—ロセスã®åˆæœŸåŒ–ã«å¤±æ•—ã—ã¾ã—ãŸã€‚</string>
@@ -154,24 +153,19 @@
<string name="err_acquire_image_failed">ç”»åƒãƒ•ã‚¡ã‚¤ãƒ«ã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸã€‚</string>
<string name="err_tb_display">トラッカブルを表示ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。本当ã«ãƒˆãƒ©ãƒƒã‚«ãƒ–ルã§ã™ã‹?</string>
<string name="err_tb_details_open">トラッカブルã®è©³ç´°ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“。</string>
- <string name="err_tb_forgot_saw">c:geo forgot which trackable you saw.</string>
<string name="err_tb_find">トラッカブルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</string>
<string name="err_tb_find_that">トラッカブルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</string>
<string name="err_waypoint_cache_unknown">c:geo doesn\'t know to which cache you want to add waypoint.</string>
<string name="err_waypoint_add_failed">ウェイãƒã‚¤ãƒ³ãƒˆã‚’追加ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚</string>
<string name="err_point_unknown_position">ç¾åœ¨åœ°ã‚’èªè­˜ã§ãã¾ã›ã‚“。</string>
- <string name="err_point_no_position_given_title">å¿…è¦ãªæƒ…å ±</string>
+ <string name="err_point_no_position_given_title">情報ãŒå¿…è¦ã§ã™</string>
<string name="err_point_no_position_given">å°‘ãªãã¨ã‚‚経度ã€ç·¯åº¦ã€ã¾ãŸã¯è·é›¢ã¨æ–¹ä½ã‚’入力ã—ã¦ãã ã•ã„。全ã¦ã‚’入力ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</string>
- <string name="err_point_curr_position_unavailable">ç¾åœ¨åœ°ã®åº§æ¨™ãŒåˆ†ã‹ã‚Šã¾ã›ã‚“。もã†å°‘ã—ãŠå¾…ã¡ãã ã•ã„…</string>
<string name="err_point_bear_and_dist_title">ヘルプãŒå¿…è¦?</string>
<string name="err_point_bear_and_dist">æ–¹ä½ã¨è·é›¢ã‚’入力ã—ã¦ãã ã•ã„。方ä½ã¯åŒ—を基準ã¨ã—ã¦æ™‚計回りã«0~360度ã§è¡¨ã—å˜ä½ã¯ä»˜ã‘ãªã„ã§ãã ã•ã„。</string>
<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_post_failed">ログを投稿ã™ã‚‹ã“ã¨ãŒã§ããªã‹ã£ãŸã‚ˆã†ã§ã™ã€‚Geocaching.comã§ç¢ºèªã—ã¦ãã ã•ã„。</string>
- <string name="err_log_post_failed_ec">ログを投稿ã™ã‚‹ã“ã¨ãŒã§ããªã‹ã£ãŸã‚ˆã†ã§ã™ã€‚Extremcaching.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>
+ <string name="err_search_address_forgot">c:geoã¯ã‚ãªãŸã®æ¤œç´¢ã—ãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’忘れã¦ã—ã¾ã„ã¾ã—ãŸã€‚</string>
<string name="err_parse_lat">緯度ã®è§£æžãŒã§ãã¾ã›ã‚“。</string>
<string name="err_parse_lon">経度ã®è§£æžãŒã§ãã¾ã›ã‚“。</string>
<string name="err_parse_dist">è·é›¢ã®è§£æžãŒã§ãã¾ã›ã‚“。</string>
@@ -200,7 +194,7 @@
<string name="info_select_logimage_cancelled">添付画åƒã®ãƒ•ã‚¡ã‚¤ãƒ«é¸æŠžã¾ãŸã¯æ’®å½±ãŒã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸã€‚</string>
<string name="info_stored_image">æ–°è¦ç”»åƒãƒ•ã‚¡ã‚¤ãƒ«ã®ä¿å­˜å ´æ‰€:</string>
<string name="info_storing_static_maps">オフライン用ã«åœ°å›³ã‚’ä¿å­˜ä¸­</string>
- <string name="loc_last">Last known</string>
+ <string name="loc_last">判明ã—ãŸæœ€å¾Œã®ä½ç½®</string>
<string name="loc_net">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">衛星</string>
@@ -213,12 +207,12 @@
<string name="menu_history">履歴</string>
<string name="menu_filter">フィルター</string>
<string name="menu_scan_geo">QRコードスキャン</string>
+ <string name="menu_pocket_queries">ãƒã‚±ãƒƒãƒˆãƒ»ã‚¯ã‚¨ãƒª</string>
<string name="menu_scan_description">QRコードã«ã—ãŸGCコードをスキャンã§ãã¾ã™ãŒå¿…è¦ãªã‚¢ãƒ—リãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã›ã‚“。Google Playã‹ã‚‰ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã™ã‹?</string>
<string name="live_map_button">地図</string>
<string name="caches_nearby_button">è¿‘ã</string>
<string name="advanced_search_button">検索</string>
<string name="stored_caches_button">ä¿å­˜æ¸ˆã¿</string>
- <string name="any_button">目的地</string>
<string name="unknown_scan">GCコードãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚</string>
<string name="caches_no_cache">キャッシュã¯ã‚ã‚Šã¾ã›ã‚“</string>
<string name="caches_more_caches">次ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥</string>
@@ -239,12 +233,12 @@
<string name="caches_sort_difficulty">難易度</string>
<string name="caches_sort_terrain">地形</string>
<string name="caches_sort_size">サイズ</string>
- <string name="caches_sort_favorites">人気</string>
+ <string name="caches_sort_favorites">ãŠæ°—ã«å…¥ã‚Š</string>
<string name="caches_sort_favorites_ratio">ãŠæ°—ã«å…¥ã‚Š [%]</string>
<string name="caches_sort_name">åå‰</string>
<string name="caches_sort_geocode">GCコード</string>
<string name="caches_sort_rating">評価</string>
- <string name="caches_sort_vote">Vote (Own Rating)</string>
+ <string name="caches_sort_vote">自己評価</string>
<string name="caches_sort_inventory">目録ã®æ•°</string>
<string name="caches_sort_date_hidden">設置日</string>
<string name="caches_sort_date_logged">ログãŒæ›¸ã‹ã‚ŒãŸæ—¥</string>
@@ -256,6 +250,7 @@
<string name="caches_select_invert">é¸æŠžã‚’å転</string>
<string name="caches_nearby">ç¾åœ¨åœ°ã®è¿‘ã</string>
<string name="caches_manage">管ç†</string>
+ <string name="caches_remove_progress">キャッシュを削除中</string>
<string name="caches_delete_events">éŽåŽ»ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’削除</string>
<string name="caches_refresh_selected">é¸æŠžã—ãŸã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’æ›´æ–°</string>
<string name="caches_refresh_all">å…¨ã¦ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’æ›´æ–°</string>
@@ -274,7 +269,7 @@
<string name="caches_filter_track">トラッカブルã‚ã‚Š</string>
<string name="caches_filter_clear">フィルターをクリア</string>
<string name="caches_filter_modified">座標ã®æ›´æ–°ã‚ã‚Š</string>
- <string name="caches_filter_origin">Origin</string>
+ <string name="caches_filter_origin">原点</string>
<string name="caches_filter_distance">è·é›¢</string>
<string name="caches_filter_personal_note">パーソナルノート付ã</string>
<string name="caches_filter_popularity">ãŠæ°—ã«å…¥ã‚Š</string>
@@ -561,7 +556,6 @@
<string name="cache_menu_streetview">Googleストリートビュー</string>
<string name="cache_menu_browser">ブラウザã§é–‹ã</string>
<string name="cache_menu_visit">ログを書ã</string>
- <string name="cache_menu_visit_offline">ログを書ã(オフライン)</string>
<string name="cache_menu_spoilers">スãƒã‚¤ãƒ©ãƒ¼ç”»åƒ</string>
<string name="cache_menu_around">è¿‘ãã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥</string>
<string name="cache_menu_event">カレンダーã«ç™»éŒ²</string>
@@ -777,7 +771,6 @@
<string name="helper_contacts_title">c:geo - 連絡先アドオン</string>
<string name="helper_sendtocgeo_description">Send to c:geoã¯<strong>PC用</strong>ブラウザã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚PCã®ãƒ–ラウザã§è¡¨ç¤ºã—ã¦ã‚‹ã‚­ãƒ£ãƒƒã‚·ãƒ¥æƒ…報をアンドロイド端末ã«ç›´æŽ¥é€ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">シンプルã§å½¹ã«ç«‹ã¤åœ°å›³ã‚¢ãƒ—リ。オフライン用ã«åœ°å›³ã‚’直接ダウンロード(ç”»åƒãƒ‡ãƒ¼ã‚¿ã®ã¿)ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚軌跡(GPSログ)を記録ã—ãŸã‚Šã€POIを扱ã£ãŸã‚Šã€ãã®ä»–ã‚‚ãŸãã•ã‚“便利ãªæ©Ÿèƒ½ãŒã‚ã‚Šã¾ã™ã€‚</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">c:geoã§ã“ã®ã‚¢ãƒ—リã®ãƒ¬ãƒ¼ãƒ€ãƒ¼ã‚’利用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ãã®ä»–ã€GPSã«é–¢ã™ã‚‹ãŸãã•ã‚“ã®æƒ…å ±ãŒå¾—られã¾ã™ã€‚</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -998,11 +991,6 @@ Google翻訳アプリã§å„言語ã®è¾žæ›¸ã‚’ダウンロードã—ã¦ãŠã‘ã°ã‚
<string name="attribute_geotour_no">ジオツアーã®ä¸€éƒ¨ã§ã¯ãªã„</string>
<string name="quote">To make geocaching easier, to make users lazier.</string>
<string name="powered_by">carnero</string>
- <string name="support">サãƒãƒ¼ãƒˆ: <a href="">support@cgeo.org</a></string>
- <string name="website">Webサイト: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">Google Playã®c:geo</a></string>
<string name="about_twitter">キャッシュã®ãƒ­ã‚°ã‚’書ã„ãŸã‚‰<b>c:geo</b>ã«Twitterã§ã¤ã¶ã‚„ã„ã¦ã»ã—ã„?</string>
<string name="status_new_release" tools:ignore="UnusedResources">æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒã‚ã‚Šã¾ã™ã€‚\nクリックã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¦ãã ã•ã„。</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">æ–°ã—ã„ナイトリービルドãŒã‚ã‚Šã¾ã™ã€‚\nクリックã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¦ãã ã•ã„。</string>
diff --git a/main/res/values-lt/strings.xml b/main/res/values-lt/strings.xml
index d0e6f9d..f20a913 100644
--- a/main/res/values-lt/strings.xml
+++ b/main/res/values-lt/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">ApsilankÄ—</string>
<string name="log_tb_drop">Paliktas</string>
<string name="log_tb_changeall">Keisti visus</string>
- <string name="log_save">IÅ¡saugoti</string>
+ <string name="log_save">IÅ¡saugoti neprisijungus</string>
<string name="log_saving">SiunÄiamas įraÅ¡as…</string>
<string name="log_saving_and_uploading">SiunÄiamas įraÅ¡as ir įkeliama nuotrauka…</string>
<string name="log_clear">IÅ¡valyti</string>
<string name="log_post_not_possible">Įkeliamas įrašo puslapis…</string>
+ <string name="log_date_future_not_allowed">Būsimos datos įrašai negalimi.</string>
<string name="log_add">PridÄ—ti</string>
+ <string name="log_repeat">Pakartoti paskutinį įrašą</string>
<string name="log_no_rating">NÄ—ra reitingo</string>
<string name="log_stars_1_description">Prasta</string>
<string name="log_stars_15_description">Pakankamai prasta</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Įrašo slaptažodis:</string>
<string name="log_hint_log_password">Įveskite savo įrašo slaptažodį</string>
<string name="log_oc_team_comment">OC komandos komentaras</string>
+ <string name="log_your_saved_log">Jūsų išsaugotas įrašas</string>
<string-array name="log_image_scales">
<item>Nekeisti dydžio</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Nėra išsaugotos prisijungimo informacijos</string>
<string name="err_login_failed_toast">c:geo negali prisijungti. c:geo veikia neprisijungusi su išsaugotomis slėptuvėmis. Patikrinkite prisijungimo nustatymus arba įjunkite prietaiso interneto ryšį.</string>
<string name="err_unknown">Nežinoma klaida</string>
+ <string name="err_unknown_address">C:geo nepavyko susieti Å¡io adreso su egzistuojanÄia vietove</string>
<string name="err_comm">Nežinoma ryšio klaida</string>
<string name="err_missing_auth">Neįvestas vartotojo vardas ir/ar slaptažodis.</string>
<string name="err_wrong">Neteisinga prisijungimo informacija</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Nepavyko pasiekti nuotraukos.</string>
<string name="err_tb_display">c:geo negali parodyti norimo keliauninko. Ar tai tikrai keliauninkas?</string>
<string name="err_tb_details_open">c:geo negali atidaryti keliauninko informacijos.</string>
- <string name="err_tb_forgot_saw">c:geo pamiršo kokį keliauninką žiūrėjote.</string>
<string name="err_tb_find">c:geo neranda keliauninko</string>
<string name="err_tb_find_that">c:geo neranda Å¡ito keliauninko.</string>
<string name="err_waypoint_cache_unknown">c:geo nežino, kokiai slėptuvei norite pridėti papildomą tašką.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo neranda Jūsų buvimo vietos.</string>
<string name="err_point_no_position_given_title">Reikalinga informacija</string>
<string name="err_point_no_position_given">Užpildykite bent platumą ir ilgumą arba atstumą ir azimutą. Taip pat galite užpildyt ir visus keturis laukelius.</string>
- <string name="err_point_curr_position_unavailable">c:geo dar negavo vietos koordinaÄių. PraÅ¡ome palaukti…</string>
<string name="err_point_bear_and_dist_title">Reikalinga pagalba?</string>
<string name="err_point_bear_and_dist">Užpildykite azimutą ir atstumą. Azimutas tai nuo 0 iki 360 laipsnių kampas nuo šiaurės. Atstumas nereikalauja matavimo vienetų.</string>
<string name="err_log_load_data">c:geo negali įkelti duomenų reikalingų apsilankymui įrašyti.</string>
<string name="err_log_load_data_again">c:geo negali įkelti duomenų reikalingų apsilankymui įrašyti. Bando dar kartą.</string>
<string name="err_log_load_data_still">c:geo dar įkelia duomenis reikalingus apsilankymui įrašyti. Prašome palaukti šiek tiek ilgiau.</string>
- <string name="err_log_post_failed">Atrodo, kad jūsų įrašas nebuvo paskelbtas. Prašome tai patikrinti Geocaching.com.</string>
- <string name="err_log_post_failed_ec">Atrodo, kad jūsų įrašas nebuvo paskelbtas. Prašome tai patikrinti Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Atrodo, kad jūsų įrašo nuotrauka nebuvo įkelta. Prašome tai patikrinti Geocaching.com.</string>
+ <string name="err_log_post_failed">Atrodo, kad jūsų įrašas nebuvo paskelbtas. Prašome patikrinti jį slėptuvės svetainėje.</string>
+ <string name="err_logimage_post_failed">Atrodo, kad jūsų įrašo nuotrauka nebuvo paskelbta. Prašome patikrinti ją slėptuvės svetainėje.</string>
<string name="err_search_address_forgot">c:geo pamiršo adresą kurio bandėte ieškoti.</string>
<string name="err_parse_lat">c:geo nesupranta įvestos platumos.</string>
<string name="err_parse_lon">c:geo nesupranta įvestos ilgumos.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Tinklas</string>
<string name="loc_fused">Sujungta</string>
<string name="loc_low_power">Energijos taupymas</string>
+ <string name="loc_home">Namų koordinatės</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Pal.</string>
<string name="loc_trying">Bandoma nustatyti</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Netoliese</string>
<string name="advanced_search_button">Ieškoti</string>
<string name="stored_caches_button">IÅ¡saugota</string>
- <string name="any_button">Bet kur</string>
+ <string name="any_button">Eiti į</string>
<string name="unknown_scan">Nepavyko rasti geo kodo.</string>
<string name="caches_no_cache">SlÄ—ptuvių Äia nÄ—ra</string>
<string name="caches_more_caches">Įkelti daugiau slėptuvių</string>
@@ -264,15 +266,24 @@
<string name="caches_sort_finds">Radimų kiekis</string>
<string name="caches_sort_state">BÅ«sena</string>
<string name="caches_sort_storage">IÅ¡saugojimo prietaise data</string>
+ <string name="caches_sort_eventdate">Renginio data</string>
<string name="caches_select_mode">Pasirinkti</string>
<string name="caches_select_mode_exit">Nebesirinkti</string>
<string name="caches_select_invert">Žymėti priešingai</string>
<string name="caches_nearby">Netoliese</string>
<string name="caches_manage">Valdyti</string>
<string name="caches_remove_all">Pašalinti visas</string>
- <string name="caches_remove_all_confirm">Ar norite pašalinti visas %s slėptuves iš dabartinio sąrašo?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Ar norite pašalinti slėptuvę iš dabartinio sąrašo?</item>
+ <item quantity="few">Ar norite pašalinti visas %d slėptuves iš dabartinio sąrašo?</item>
+ <item quantity="other">Ar norite pašalinti visas %d slėptuvių iš dabartinio sąrašo?</item>
+ </plurals>
<string name="caches_remove_selected">Pašalinti pasirinktą</string>
- <string name="caches_remove_selected_confirm">Ar norite pašalinti pasirinktas %s slėptuves iš prietaiso?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Ar norite pašalinti slėptuvę iš prietaiso?</item>
+ <item quantity="few">Ar norite pašalinti pasirinktas %d slėptuves iš prietaiso?</item>
+ <item quantity="other">Ar norite pašalinti pasirinktas %d slėptuvių iš prietaiso?</item>
+ </plurals>
<string name="caches_remove_progress">Pašalinamos slėptuvės</string>
<string name="caches_delete_events">Ištrinti praeities įvykius</string>
<string name="caches_refresh_selected">Atnaujinti pasirinktas</string>
@@ -292,13 +303,18 @@
<string name="caches_filter_track">Su keliauninkais</string>
<string name="caches_filter_clear">Valyti filtrus</string>
<string name="caches_filter_modified">Su pakeistomis koordinatÄ—mis</string>
+ <string name="caches_filter_offline_log">Su išsaugotu įrašu</string>
<string name="caches_filter_origin">Å altinis</string>
<string name="caches_filter_distance">Atstumas</string>
<string name="caches_filter_personal_note">Su asmenine pastaba</string>
<string name="caches_filter_popularity">Kaip mÄ—giamos</string>
<string name="caches_filter_popularity_ratio">Kaip mÄ—giamos [%]</string>
+ <string name="caches_filter_personal_data">Su asmeniniais duomenimis</string>
+ <string name="caches_filter_rating">Su reitingu</string>
+ <string name="caches_filter_own_rating">Su savo reitingu</string>
<string name="caches_removing_from_history">Pašalinama iš Istorijos…</string>
<string name="caches_clear_offlinelogs">Išvalyti išsaugotus įrašus</string>
+ <string name="caches_clear_offlinelogs_message">Ar norite išvalyti išsaugotus įrašus?</string>
<string name="caches_clear_offlinelogs_progress">Išvalomi išsaugoti įrašai</string>
<string name="list_menu_create">Sukurti naują sąrašą</string>
<string name="list_menu_drop">Išmesti dabartinį sąrašą</string>
@@ -321,13 +337,17 @@
<string name="list_not_available">Sąrašas nebeprieinamas, pereinama į standartinį sąrašą</string>
<string name="about_version">Versija</string>
<string name="about_changelog">Pakeitimų žurnalas</string>
+ <string name="about_system">Sistema</string>
<string name="about_donate">Paaukoti</string>
<string name="about_donation_more">Paaukoti\nkūrėjams</string>
<string name="about_contributors">Bendraautoriai</string>
<string name="about_license">Licencija</string>
<string name="about_apache_license"><a href=""> Apache licencija, versija 2.0</a></string>
<string name="about_help">Pagalba</string>
+ <string name="about_system_include">PridÄ—kite papildomÄ… sisteminÄ™ informacijÄ…, kai siunÄiate klaidos praneÅ¡imÄ… arba norite gauti daugiau informacijos apie c:geo:</string>
+ <string name="changelog_github">Pakeitimų sąrašas</string>
<string name="settings_title_services">Paslaugos</string>
+ <string name="settings_summary_services">Nustatyk naudotojo paskyros informaciją ir prieiga prie pasirinktinų paslaugų.</string>
<string name="settings_title_appearance">IÅ¡vaizda</string>
<string name="settings_title_cachedetails">SlÄ—ptuvÄ—s informacija</string>
<string name="settings_title_offlinedata">Duomenys darbui neprisijungus</string>
@@ -365,6 +385,9 @@
<string name="settings_activate_oc_uk">Aktyvuoti</string>
<string name="init_oc_uk_description">Leiskite c:geo prisijungti prie opencaching.org.uk tam, kad galėtumėt ieškoti slėptuvių ir pasiekti/filtruoti rastas slėptuves.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Kad bÅ«tų galima reitinguoti slÄ—ptuvÄ™, sekite instrukcijÄ… GCVote.com svetainÄ—je ir Äia įveskite GCVote slaptažodį.</string>
+ <string name="err_gcvote_send_rating">Klaida siunÄiant reitingÄ…, patikrinkite GCVote slaptažodį parametruose arba jį iÅ¡trinkite.</string>
+ <string name="gcvote_sent">Balsas sėkmingai išsiųstas</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktyvuoti</string>
<string name="init_username">Vartotojo vardas</string>
@@ -435,6 +458,8 @@
<string name="init_backup_success">c:geo duomenų bazė sėkmingai nukopijuota į:</string>
<string name="init_backup_failed">Nepavyko sukurti atsarginės c:geo duomenų bazės kopijos.</string>
<string name="init_backup_unnecessary">Duomenų bazÄ— tuÅ¡Äia, atsarginÄ— kopija nereikalinga.</string>
+ <string name="backup_confirm_overwrite">Ar norite perrašyti esamą atsarginę kopiją nuo %s?</string>
+ <string name="restore_confirm_overwrite">Ar norite perrašyti %s įrenginyje su atsargine kopija?</string>
<string name="init_restore_success">Atkūrimas baigtas.</string>
<string name="init_restore_failed">Atkurti nepavyko.</string>
<string name="init_restore_running">Atkuriama slėptuvių duomenų bazė…</string>
@@ -593,6 +618,7 @@
</plurals>
<string name="cache_waypoints_add">Pridėti papildomą tašką</string>
<string name="cache_hint">Užuomina</string>
+ <string name="cache_hint_not_available">Užuomina nepateikiama</string>
<string name="cache_logs">Įrašai</string>
<string name="cache_logs_friends_and_own">Draugų/savi įrašai</string>
<string name="cache_dialog_loading_details">Įkeliama slėptuvės informacija…</string>
@@ -632,9 +658,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Atidaryti naršyklėje</string>
<string name="cache_menu_visit">Registruoti</string>
- <string name="cache_menu_visit_offline">Registruoti neprisijungus</string>
+ <string name="cache_menu_visit_offline">Vienu paspaudimu žurnalo įrašo išsaugojimas</string>
<string name="cache_menu_spoilers">Užuominų nuotraukos</string>
<string name="cache_menu_around">SlÄ—ptuvÄ—s aplink</string>
+ <string name="around">Aplink %s</string>
<string name="cache_menu_event">Įtraukti į kalendorių</string>
<string name="cache_menu_details">Informacija</string>
<string name="cache_menu_refresh">Atnaujinti</string>
@@ -643,6 +670,8 @@
<string name="cache_menu_whereyougo">WhereYouGo</string>
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Balsuoti</string>
+ <string name="cache_menu_ignore">Ignoruoti slÄ—ptuvÄ™</string>
<string name="cache_status">BÅ«sena</string>
<string name="cache_status_offline_log">Išsaugotas įrašas</string>
<string name="cache_status_found">Rasta</string>
@@ -752,6 +781,8 @@
<string name="search_clear_history">IÅ¡valyti istorijÄ…</string>
<string name="search_history_cleared">Istorija išvalyta</string>
<string name="waypoint_coordinate_formats_plain">Paprastas</string>
+ <string name="from_clipboard">Iš mainų srities</string>
+ <string name="copy_to_clipboard">Kopijuoti į mainų sritį</string>
<string name="visit_tweet">Skelbti radybas Twitter paskytoje</string>
<string name="map_map">IÅ¡saugotos slÄ—ptuvÄ—s</string>
<string name="map_live">Slėptuvės iš interneto</string>
@@ -856,7 +887,7 @@
<string name="helper_contacts_description">Leidžia tiesiai iš įrašo atidaryti kontakto kortelę (iš jūsų adresų knygos), kad galėtumėte susisiekti su draugais paprašyti pagalbos.</string>
<string name="helper_sendtocgeo_description">Send to c:geo yra <strong>jūsų kompiuterio</strong> naršyklės priedas . Kai naršote geocaching.com, jūs galite siųsti slėptuves į savo išmanųjį telefoną tiesiog naršyklės viduje paspausdami mygtuką.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Patogi programa, kuri rodo žemėlapius tiesiai iš interneto ir suteikia galimybę atsisiųsti juos į prietaisą (tik rastrinius žemėlapius). Ji taip pat palaiko nukeliauto kelio įrašymą, lankytinų vietų valdymą ir turi daug kitų naudingų funkcijų.</string>
+ <string name="helper_locus_description">Navigacijos programa Jūsų telefonui. Žiūrėkite išsaugotus topo žemėlapius, įrašykite savo maršrutą, ieškokite slėptuves, naudokite balso komandas ir dar daugiau.</string>
<string name="helper_gpsstatus_title">GPS Status &amp; Toolbox</string>
<string name="helper_gpsstatus_description">Kartu su c:geo galite naudoti šioje programoje esantį radarą. Ji taip pat siūlo daug kitos su GPS susijusios informacijos.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1107,12 +1138,15 @@
<string name="attribute_offset_cache_yes">Offset cache</string>
<string name="attribute_offset_cache_no">No offset cache</string>
<string name="quote">To make geocaching easier, to make users lazier.</string>
- <string name="support">Palaikymas: <a href="">support@cgeo.org</a></string>
- <string name="website">Tinklapis: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo on Google Play</a></string>
+ <string name="support_title">Palaikymas</string>
+ <string name="website_title">Tinklapis</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href=""> c:Geo puslapis</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo Google Play</a></string>
<string name="about_twitter">Kaskart registruojant slÄ—ptuvÄ™ <b>c:geo</b> paskelbs nauja statusÄ… Twitter paskyroje.</string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Galima nauja versija. \nPaspauskite Äia ir įdiekite.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Galima nauja naktinÄ— versija.\nPaspauskite Äia ir įdiekite.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Galima nauja versija. \nPaspauskite Äia ir įdiekite.</string>
@@ -1163,7 +1197,7 @@
<item quantity="few">%s mÄ—giamos</item>
<item quantity="other">%s mėgiamų</item>
</plurals>
- <string name="percent_favorite_points">%\ mÄ—giamos</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% megstami</string>
<string name="cgeo_shortcut">c:geo nuoroda</string>
<string name="create_shortcut">Sukurti nuorodÄ…</string>
<string name="send">Siųsti</string>
diff --git a/main/res/values-lv/strings.xml b/main/res/values-lv/strings.xml
new file mode 100644
index 0000000..3a23710
--- /dev/null
+++ b/main/res/values-lv/strings.xml
@@ -0,0 +1,773 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <string name="app_name">c:geo</string>
+ <string name="cache">Slēpnis</string>
+ <string name="detail">InformÄcija</string>
+ <string name="search">Meklēšana</string>
+ <string name="helpers">NoderÄ«gas aplikÄcijas</string>
+ <string name="about">Par c:geo</string>
+ <string name="latitude">Platums</string>
+ <string name="longitude">Garums</string>
+ <string name="settings_titlebar">c:geo iestatījumi</string>
+ <string name="all_types">Visi slēpņu veidi</string>
+ <string name="traditional">TradicionÄlais slÄ“pnis</string>
+ <string name="multi">Multislēpnis</string>
+ <string name="mystery">Mistērijas/mīklas slēpnis</string>
+ <string name="letterbox">Letterbox hibrīds</string>
+ <string name="event">Event slēpnis</string>
+ <string name="mega">Mega-Event slēpnis</string>
+ <string name="giga">Giga-Event slēpnis</string>
+ <string name="earth">Zemes slēpnis</string>
+ <string name="cito">Cache In Trash Out pasÄkums (CITO)</string>
+ <string name="webcam">Tīmekļa kameras slēpnis</string>
+ <string name="virtual">VirtuÄlais slÄ“pnis</string>
+ <string name="wherigo">Wherigo slēpnis</string>
+ <string name="lostfound">Lost &amp; Found PasÄkuma slÄ“pnis</string>
+ <string name="ape">Projekta A.P.E. slēpnis</string>
+ <string name="gchq">Groundspeak HQ</string>
+ <string name="gps">GPS Adventures Exhibit</string>
+ <string name="block">Groundspeak Block Party</string>
+ <string name="unknown">NezinÄms tips</string>
+ <string name="cache_size_micro">Mikro</string>
+ <string name="cache_size_small">Mazs</string>
+ <string name="cache_size_regular">Parasts</string>
+ <string name="cache_size_large">Liels</string>
+ <string name="cache_size_other">Cits</string>
+ <string name="cache_size_virtual">VirtuÄls</string>
+ <string name="cache_size_notchosen">Nav izvēlēts</string>
+ <string name="cache_size_unknown">NezinÄms</string>
+ <string name="cache_size_nano">Nano</string>
+ <string name="cache_size_very_large">Ļoti liels</string>
+ <string name="wp_final">FinÄla vieta</string>
+ <string name="wp_stage">Multislēpņa posms</string>
+ <string name="wp_puzzle">JautÄjums, kas prasa atbildi</string>
+ <string name="wp_pkg">StÄvvieta</string>
+ <string name="wp_trailhead">Takas sÄkumvieta</string>
+ <string name="wp_waypoint">Izziņas vieta</string>
+ <string name="wp_original">SÄkotnÄ“jÄs koordinÄtas</string>
+ <string name="log_found">Atrasts</string>
+ <string name="log_dnf">Nav atrasts</string>
+ <string name="log_note">Rakstīt piezīmi</string>
+ <string name="log_published">Publicēts</string>
+ <string name="log_enabled">Iespējots</string>
+ <string name="log_disabled">Atspējots</string>
+ <string name="log_attend">Piedalīšos</string>
+ <string name="log_attended">Piedalījos</string>
+ <string name="log_retrieved">Iegūts</string>
+ <string name="log_placed">Novietots</string>
+ <string name="log_grabbed">Paņemts kaut kur citur</string>
+ <string name="log_movecollection">Pievienots kolekcijai</string>
+ <string name="log_moveinventory">Pievienots inventÄriem</string>
+ <string name="log_maintained">Apkope veikta</string>
+ <string name="log_maintenance_needed">Nepieciešama apkope</string>
+ <string name="log_update">AtjauninÄtas koordinÄtas</string>
+ <string name="log_archived">Arhivēts</string>
+ <string name="log_unarchived">Atarhivēts</string>
+ <string name="log_needs_archived">Nepieciešams arhivēt</string>
+ <string name="log_discovered">AtklÄts</string>
+ <string name="log_reviewer">PÄrskatÄ«tÄja piezÄ«me</string>
+ <string name="log_submit_for_review">Iesniegt izskatīšanai</string>
+ <string name="log_retractlisting">Aizliegto sarakstÄ</string>
+ <string name="log_marked_missing">AtzÄ«mÄ“ts kÄ pazudis</string>
+ <string name="log_tb_nothing">Nedarīt neko</string>
+ <string name="log_tb_visit">Apmeklēja</string>
+ <string name="log_tb_drop">Nometa</string>
+ <string name="log_tb_changeall">Mainīt visus</string>
+ <string name="log_save">SaglabÄt bezsaistes režīmÄ</string>
+ <string name="log_saving">Apmeklējuma ieraksta nosūtīšana…</string>
+ <string name="log_saving_and_uploading">Pieraksta nosÅ«tÄ«Å¡ana un bildes augÅ¡upielÄde…</string>
+ <string name="log_clear">Notīrīt</string>
+ <string name="log_post_not_possible">IelÄdÄ“ apmeklÄ“juma ierasta lapu…</string>
+ <string name="log_add">Pievienot</string>
+ <string name="log_repeat">AtkÄrtot iepriekÅ¡Ä“jo reÄ£istrÄ“Å¡anos</string>
+ <string name="log_no_rating">Nav vērtējuma</string>
+ <string name="log_stars_1_description">Slikti</string>
+ <string name="log_stars_15_description">Diezgan slikti</string>
+ <string name="log_stars_2_description">Zem vidÄ“jÄ</string>
+ <string name="log_stars_25_description">Nav slikti</string>
+ <string name="log_stars_3_description">Vidēji</string>
+ <string name="log_stars_35_description">VispÄr nav slikti</string>
+ <string name="log_stars_4_description">LabÄk nekÄ vidÄ“ji</string>
+ <string name="log_stars_45_description">Ļoti labi</string>
+ <string name="log_stars_5_description">Vienreizēji</string>
+ <string name="log_webcam">TÄ«mekļa kameras fotogrÄfija uzņemta</string>
+ <string name="log_new_log">Reģistrēt apmeklējumu</string>
+ <string name="log_new_log_text">Apmeklējuma teksts</string>
+ <string name="log_announcement">Paziņojums</string>
+ <string name="log_today">Å odien</string>
+ <string name="log_yesterday">Vakar</string>
+ <string name="log_smilies">Smaidiņi</string>
+ <string name="log_image">Attēls</string>
+ <string name="log_image_attach">Pievienot attēlu</string>
+ <string name="log_image_stored">Esošo</string>
+ <string name="log_image_camera">Jaunu</string>
+ <string name="log_image_caption">Nosaukums</string>
+ <string name="log_image_description">Apraksts</string>
+ <string name="log_image_scale">Mērogošana</string>
+ <string name="log_password_title">PierakstÄ«Å¡anÄs parole:</string>
+ <string name="log_hint_log_password">Ievadiet savu pierakstÄ«Å¡anÄs paroli</string>
+ <string name="log_oc_team_comment">OC Team komentÄrs</string>
+ <string-array name="log_image_scales">
+ <item>Bez mērogošanas</item>
+ <item>512 px</item>
+ <item>640 px</item>
+ <item>800 px</item>
+ <item>1024 px</item>
+ </string-array>
+ <string name="translate_to_sys_lang">Tulkot uz %s valodu</string>
+ <string name="translate_to_english">Tulkot uz angļu valodu</string>
+ <string name="translate_length_warning">Tulkojums var neizdoties liela teksta apjoma dēļ.</string>
+ <string name="err_none">OK</string>
+ <string name="err_parse">Kļūda autorizÄcijas lapas apstrÄdÄ“</string>
+ <string name="err_server">Nevar sazinÄties ar Geocaching.com. Vietne Å¡obrÄ«d var nedarboties vai arÄ« jÅ«su interneta savienojums nedarbojas.</string>
+ <string name="err_server_ec">Nevar sazinÄties ar Extremcaching.com. Vietne Å¡obrÄ«d var nedarboties vai arÄ« jÅ«su interneta savienojums nedarbojas.</string>
+ <string name="err_login">Nav saglabÄta pieteikÅ¡anÄs informÄcija</string>
+ <string name="err_login_failed_toast">c:geo nevar pierakstÄ«ties. c:geo darbojas bezsaistÄ“ ar bezsaistÄ“ saglabÄtajiem slÄ“pņiem. PÄrbaudiet ielogoÅ¡anÄs iestatÄ«jumus vai iespÄ“jojiet interneta savienojumu.</string>
+ <string name="err_unknown">NezinÄma kļūda</string>
+ <string name="err_unknown_address">c:geo nevarÄ“ja atrast kartÄ“ Å¡o adresi ar paÅ¡reizÄ“jo atraÅ¡anÄs vietu</string>
+ <string name="err_comm">NezinÄma sakaru kļūda</string>
+ <string name="err_missing_auth">Nav uzstÄdÄ«ts lietotÄjvÄrds un/vai parole.</string>
+ <string name="err_wrong">PieteikÅ¡anÄs informÄcija ir nepareiza</string>
+ <string name="err_maintenance">Geocaching.com apkopes dēļ nedarbojas. c:geo strÄdÄ bezsaistÄ“ ar saglabÄtajiem bezsaistÄ“ slÄ“pņiem.</string>
+ <string name="err_license">JÅ«s neesat piekritis Geocaching.com licences lÄ«gumam, tÄpÄ“c c:geo nevar ielÄdÄ“t slÄ“pņu koordinÄtas.</string>
+ <string name="err_unvalidated_account">Vispirms Jums jÄapstiprina savs konts vietnÄ“ Geocaching.com.</string>
+ <string name="err_unpublished">Pieprasītais slēpnis nav publicēts.</string>
+ <string name="err_premium_only">Å Ä«s slÄ“pnis ir pieejams tikai Geocaching.com Premium lietotÄjiem.</string>
+ <string name="err_detail_open">c:geo nevar atvÄ“rt Ä£eoslÄ“pņa informÄciju.</string>
+ <string name="err_detail_cache">c:geo nevar parÄdÄ«t izvÄ“lÄ“to Ä£eoslÄ“pni. Tas tieÅ¡Äm ir Ä£eoslÄ“pnis?</string>
+ <string name="err_detail_cache_find">c:geo nevar atrast ģeoslēpni</string>
+ <string name="err_detail_cache_find_some">c:geo nevar atrast šo ģeoslēpni.</string>
+ <string name="err_detail_cache_find_any">c:geo nevar atrast nevienu ģeoslēpni.</string>
+ <string name="err_detail_google_maps_limit_reached">c:geo neizdevÄs lejupielÄdÄ“t statiskÄs kartes. VarbÅ«t Google Maps API limits ir pÄrsniegts.</string>
+ <string name="err_detail_no_spoiler">c:geo neatrada spoilerbildi šim slēpnim.</string>
+ <string name="err_detail_no_map_static">c:geo neatrod statiskÄs kartes Å¡im slÄ“pnim.</string>
+ <string name="err_detail_not_load_map_static">c:geo neizdevÄs ielÄdÄ“t statiskÄs kartes.</string>
+ <string name="err_detail_still_working">JoprojÄm strÄdÄ pie citas darbÄ«bas.</string>
+ <string name="err_watchlist_still_managing">JoprojÄm kÄrto tavu novÄ“rojamo slÄ“pņu sarakstu.</string>
+ <string name="err_watchlist_failed">NeizdevÄs mainÄ«t tavu novÄ“rojamo slÄ“pņu sarakstu.</string>
+ <string name="err_application_no">c:geo nevar atrast nevienu piemÄ“rotu aplikÄciju.</string>
+ <string name="err_auth_initialize">c:geo neizdevÄs izpildÄ«t pierakstÄ«Å¡anÄs procesu.</string>
+ <string name="err_auth_process">PierakstÄ«Å¡anÄs process neizdevÄs.</string>
+ <string name="err_cannot_log_visit">c:geo nevar pierakstīt jūsu apmeklējumu. Lūdzu, pierakstiet savu apmeklējumu no pilna slēpņa apraksta loga.</string>
+ <string name="err_download_fail">c:geo neizdevÄs lejupielÄdÄ“t slÄ“pņus.</string>
+ <string name="err_dwld_details_failed">c:geo neizdevÄs lejupielÄdÄ“t slÄ“pņa datus.</string>
+ <string name="err_load_descr_failed">c:geo nevar ielÄdÄ“t aprakstu.</string>
+ <string name="err_location_unknown">c:geo nezina slÄ“pņa atraÅ¡anÄs vietu.</string>
+ <string name="err_missing_device_name">LÅ«dzu, ievadiet ierÄ«ces nosaukumu pirms reÄ£istrÄ“Å¡anÄs.</string>
+ <string name="err_favorite_failed">FavorÄ«ta statusa maiņa neizdevÄs.</string>
+ <string name="err_select_logimage_failed">AttÄ“lu atlasÄ«Å¡ana priekÅ¡ pierakstÄ«Å¡anÄs neizdevÄs.</string>
+ <string name="err_acquire_image_failed">AttÄ“la iegÅ«Å¡ana neizdevÄs.</string>
+ <string name="err_tb_display">c:geo nevar parÄdÄ«t ceļotÄjums, kurus izvÄ“lÄ“jÄties. Vai tie patieÅ¡Äm ir ceļotÄji?</string>
+ <string name="err_tb_details_open">c:geo nevar atvÄ“rt ceļotÄja datus.</string>
+ <string name="err_tb_find">c:geo nevar atrast ceļotÄju</string>
+ <string name="err_tb_find_that">c:feo nevar atrast Å¡o ceļotÄju.</string>
+ <string name="err_waypoint_cache_unknown">c:geo, nezina, kuram slēpnim Jūs vēlaties pievienot Starpposma punktu.</string>
+ <string name="err_waypoint_add_failed">c:geo neizdevÄs pievienot jÅ«su Starpposmu.</string>
+ <string name="err_point_unknown_position">c:geo nevar parÄdÄ«t, kur jÅ«s atrodaties.</string>
+ <string name="err_point_no_position_given_title">InformÄcija nepiecieÅ¡ama</string>
+ <string name="err_point_no_position_given">Aizpildiet vismaz platumu un garumu var arÄ« attÄlumu ar pagrieziena leņķi. Varat norÄdÄ«t visas Äetras Å¡Å«nas.</string>
+ <string name="err_point_bear_and_dist_title">Nepieciešama palīdzība?</string>
+ <string name="err_point_bear_and_dist">AizpildÄ«t abus - gan virzienu, gan attÄlumu. Virziena leņķis ir no 0 lÄ«dz 360 grÄdiem attiecÄ«bÄ pret ziemeļiem. AttÄlumam nav jÄnorÄda mÄ“rvienÄ«bas.</string>
+ <string name="err_log_load_data">c:geo nevar ielÄdÄ“t datus, kas nepiecieÅ¡ami lai pierakstÄ«tu apmeklÄ“jumu.</string>
+ <string name="err_log_load_data_again">c:geo nevar ielÄdÄ“t datus, kas nepiecieÅ¡ami lai pierakstÄ«tu apmeklÄ“jumu. MÄ“Ä£iniet vÄ“lreiz.
+</string>
+ <string name="err_log_load_data_still">c:geo joprojÄm ielÄdÄ“ datus, kas vajadzÄ«gi, lai pierakstÄ«tos. LÅ«dzu, uzgaidiet nedaudz ilgÄk.</string>
+ <string name="err_log_post_failed">Å Ä·iet, ka jÅ«su apmeklÄ“juma ieraksts nav pievienots. LÅ«dzu, pÄrbaudiet to slÄ“pņa mÄjas lapÄ.</string>
+ <string name="err_logimage_post_failed">Å Ä·iet, ka jÅ«su apmeklÄ“juma ieraksta attÄ“ls nav augÅ¡upielÄdÄ“ts. LÅ«dzu, pÄrbaudiet to slÄ“pņa mÄjas lapÄ.</string>
+ <string name="err_search_address_forgot">c:geo aizmirsa adresi, kuru mÄ“Ä£inÄjÄt atrast.</string>
+ <string name="err_parse_dist">c:geo nevar parsÄ“t attÄlumu.</string>
+ <string name="warn_save_nothing">Å eit nekÄ nav ko saglabÄt.</string>
+ <string name="warn_no_cache_coord">Te nav slÄ“pņu ar koordinÄtÄm.</string>
+ <string name="warn_no_coordinates">Nav dotas koordinÄtas.</string>
+ <string name="warn_no_keyword">Nav sniegts atslÄ“gvÄrds.</string>
+ <string name="warn_no_username">Nav dots lietotÄjvÄrds.</string>
+ <string name="warn_search_help_title">Nepieciešama palīdzība?</string>
+ <string name="warn_search_help_address">Ievadiet adresi vai atraÅ¡anÄs vietas nosaukumu. PiemÄ“ram, pasta adrese \"BrÄ«vÄ«bas iela 99, RÄ«ga, Latvija\", pilsÄ“tas nosaukumu \"BerlÄ«ne\" vai tikai vietas nosaukumu - kaut ko lÄ«dzÄ«gu \"Zelta Boulings\".</string>
+ <string name="warn_search_help_gccode">Ievadiet kodu ģeoslēpnim. Piemēram, \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Ievadiet visu vai daļu ģeoslēpņa nosaukuma. Piemēram, \"Nakts Slēpnis\".</string>
+ <string name="warn_search_help_user">Ievadiet savu lietotÄjvÄrdu no vietnes Geocaching.com.</string>
+ <string name="warn_search_help_tb">Ievadiet ceļotÄja kodu, lai reÄ£istrÄ“tu atradumu. PiemÄ“ram, \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">LÅ«dzu, ievadi tekstu savam pierakstam.</string>
+ <string name="warn_load_images">c:geo neizdevÄs ielÄdÄ“t attÄ“lus.</string>
+ <string name="warn_nonexistant_mapfile">IzvÄ“lÄ“tais kartes fails nepastÄv. \nBezsaistes kartes nav pieejamas.</string>
+ <string name="warn_rendertheme_missing">Kartes tēma nav atrasta.</string>
+ <string name="warn_no_pocket_query_found">Tiešsaistē nav atrasts Pocket queries.</string>
+ <string name="info_log_posted">c:geo veiksmīgi iesniedza pierakstu.</string>
+ <string name="info_log_saved">c:geo veiksmÄ«gi saglabÄja pierakstu.</string>
+ <string name="info_log_cleared">Ieraksts tika dzēsts.</string>
+ <string name="info_log_type_changed">Pieraksta tips tika mainīts!</string>
+ <string name="info_select_logimage_cancelled">Attēla atlase vai uzņemšana tika atcelta.</string>
+ <string name="info_stored_image">Jauns attÄ“ls tika saglabÄts:</string>
+ <string name="info_storing_static_maps">CenÅ¡as saglabÄt statiskÄs kartes</string>
+ <string name="info_cache_saved">SlÄ“pnis ir saglabÄts bezsaistÄ“ JÅ«su ierÄ«cÄ“</string>
+ <string name="loc_last">PÄ“dÄ“jais zinÄmais</string>
+ <string name="loc_net">TÄ«kls</string>
+ <string name="loc_fused">Kombinēts</string>
+ <string name="loc_low_power">Maza jauda</string>
+ <string name="loc_home">MÄjas koordinÄtas</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Satelīti</string>
+ <string name="loc_trying">MeklÄ“ atraÅ¡anÄs vietu</string>
+ <string name="loc_no_addr">NezinÄma adrese</string>
+ <string name="loc_gps_disabled">GPS atspējots</string>
+ <string name="menu_centerposition">CentrÄ“t manu atraÅ¡anÄs vietu kartÄ“</string>
+ <string name="menu_about">Par c:geo</string>
+ <string name="menu_helpers">Papildus programmas</string>
+ <string name="menu_settings">Iestatījumi</string>
+ <string name="menu_history">VÄ“sture</string>
+ <string name="menu_filter">Filtrēt</string>
+ <string name="menu_scan_geo">Skenēt Geo code</string>
+ <string name="menu_scan_description">c:geo var skenÄ“t Ä£eokodus, kuri tiek drukÄti kÄ QR kods. Nav instalÄ“ta nepiecieÅ¡amÄ aplikÄcija. Vai vÄ“laties atvÄ“rt Google Play (Google veikalu), lai to instalÄ“tu?</string>
+ <string name="live_map_button">Karte</string>
+ <string name="caches_nearby_button">TuvumÄ</string>
+ <string name="advanced_search_button">Meklēt</string>
+ <string name="stored_caches_button">SaglabÄtie bezsaistÄ“</string>
+ <string name="unknown_scan">SkenÄ“Å¡anas rezultÄtÄ neviens Ä£eokods netika atrasts.</string>
+ <string name="caches_no_cache">Šeit nav slēpņu</string>
+ <string name="caches_more_caches">IelÄdÄ“t vairÄk slÄ“pņus</string>
+ <string name="caches_more_caches_no">Vairs nav slēpņu</string>
+ <string name="caches_more_caches_loading">IelÄdÄ“ slÄ“pņus…</string>
+ <string name="caches_more_caches_currently">pašlaik</string>
+ <string name="caches_downloading">LejupielÄdÄ“ slÄ“pņus…\nETA: </string>
+ <string name="caches_eta_ltm">MazÄk nekÄ minÅ«te</string>
+ <string name="caches_store_offline">SaglabÄt bezsaistes lietoÅ¡anai</string>
+ <string name="caches_store_selected">SaglabÄt atlasÄ«to</string>
+ <string name="caches_history">VÄ“sture</string>
+ <string name="caches_on_map">ParÄdÄ«t kartÄ“</string>
+ <string name="caches_sort">KÄrtot</string>
+ <string name="caches_sort_distance">PÄ“c attÄluma</string>
+ <string name="caches_sort_difficulty">Pēc grūtības</string>
+ <string name="caches_sort_terrain">Pēc pieķļuves grūtības</string>
+ <string name="caches_sort_size">PÄ“c lieluma</string>
+ <string name="caches_sort_favorites">Pēc favorītu daudzuma</string>
+ <string name="caches_sort_favorites_ratio">Pēc favorītu [%]</string>
+ <string name="caches_sort_name">VÄ“c nosaukuma</string>
+ <string name="caches_sort_geocode">PÄ“c Geo code</string>
+ <string name="caches_sort_rating">Pēc vērtējuma</string>
+ <string name="caches_sort_vote">Balsojums (paša vērtējums)</string>
+ <string name="caches_sort_inventory">PÄ“c krÄjumu skaita</string>
+ <string name="caches_sort_date_hidden">Pēc paslēpšanas datuma</string>
+ <string name="caches_sort_date_logged">PÄ“c pierakstÄ«Å¡anÄs datuma</string>
+ <string name="caches_sort_finds">PÄ“c atradumu skaita</string>
+ <string name="caches_sort_state">PÄ“c valsts</string>
+ <string name="caches_sort_storage">PÄ“c datuma, kad saglabÄts lietoÅ¡anai bezsaistÄ“ JÅ«su ierÄ«cÄ“</string>
+ <string name="caches_select_mode">AtzÄ«mÄ“t vairÄkus</string>
+ <string name="caches_select_mode_exit">Atcelt atzīmēšanu</string>
+ <string name="caches_select_invert">Mainīt atlasi uz pretējo</string>
+ <string name="caches_nearby">TuvumÄ</string>
+ <string name="caches_manage">PÄrvaldÄ«t</string>
+ <string name="caches_remove_all">Izdzēst visus</string>
+ <string name="caches_remove_selected">Izdzēst atlasīto</string>
+ <string name="caches_remove_progress">Slēpņu noņemšana</string>
+ <string name="caches_delete_events">PagÄjuÅ¡o notikumu dzÄ“Å¡ana</string>
+ <string name="caches_refresh_selected">Atjaunot atlasīto</string>
+ <string name="caches_refresh_all">Atjaunot visu</string>
+ <string name="caches_move_selected">PÄrvietot atlasÄ«to</string>
+ <string name="caches_move_all">PÄrvietot visus</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_map_locus_export">Eksportēt uz Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">LÅ«dzu, ievadiet attÄ“lÄ redzamo tekstu. Tas ļauj lejupielÄdÄ“t slÄ“pņu koordinÄtes, ko uzstÄdÄ«jumos var deaktivizÄ“t.</string>
+ <string name="caches_recaptcha_hint">Teksts no attēla</string>
+ <string name="caches_recaptcha_continue">TurpinÄt</string>
+ <string name="caches_filter">Filtrēt</string>
+ <string name="caches_filter_title">Filtrēt</string>
+ <string name="caches_filter_size">PÄ“c lieluma</string>
+ <string name="caches_filter_type">PÄ“c tipa</string>
+ <string name="caches_filter_track">Ar ceļotÄjiem</string>
+ <string name="caches_filter_clear">Notīrīt filtrus</string>
+ <string name="caches_filter_modified">Ar izmainÄ«tÄm koordinÄtÄm</string>
+ <string name="caches_filter_origin">PÄ“c izcelsmes</string>
+ <string name="caches_filter_distance">PÄ“c attÄluma</string>
+ <string name="caches_filter_personal_note">Ar personisku piezīmi</string>
+ <string name="caches_filter_popularity">Pēc favorītu daudzuma</string>
+ <string name="caches_filter_popularity_ratio">Pēc favorītu [%]</string>
+ <string name="caches_filter_personal_data">Ar personīgiem datiem</string>
+ <string name="caches_filter_rating">Ar reitingu</string>
+ <string name="caches_filter_own_rating">Ar paša vērtējumu</string>
+ <string name="caches_removing_from_history">Dzēš no vēstures…</string>
+ <string name="caches_clear_offlinelogs">Notīrīt bezsaistes ierakstus</string>
+ <string name="caches_clear_offlinelogs_message">Vai izdzēst bezsaistes ierakstus?</string>
+ <string name="caches_clear_offlinelogs_progress">Bezsaistes pierakstu dzēšana</string>
+ <string name="list_menu_create">Izveidot jaunu sarakstu</string>
+ <string name="list_menu_drop">Noņemt pašreizējo sarakstu</string>
+ <string name="list_menu_rename">PÄrdÄ“vÄ“t paÅ¡reizÄ“jo sarakstu</string>
+ <string name="list_menu_import">Importēt</string>
+ <string name="list_title">Izvēlēties sarakstu</string>
+ <string name="list_inbox">SaglabÄtie bezsaistÄ“</string>
+ <string name="list_all_lists">Visi slēpņi</string>
+ <string name="list_dialog_create_title">Jauns saraksts</string>
+ <string name="list_dialog_create">Izveidot</string>
+ <string name="list_dialog_create_ok">Tika izveidots jauns saraksts</string>
+ <string name="list_dialog_create_err">c:geo neizdevÄs izveidot jaunu sarakstu</string>
+ <string name="list_dialog_remove_title">Noņemt sarakstu</string>
+ <string name="list_dialog_remove_description">Vai vÄ“laties dzÄ“st paÅ¡reizÄ“jo sarakstu? Visi slÄ“pņi, kas paliks sarakstÄ, tiks pÄrvietoti uz \"SaglabÄtie\".</string>
+ <string name="list_dialog_remove">Dzēst</string>
+ <string name="list_dialog_remove_ok">Saraksts tika dzēsts</string>
+ <string name="list_dialog_remove_err">c:geo neizdevÄs dzÄ“st paÅ¡reizÄ“jo sarakstu</string>
+ <string name="list_dialog_rename_title">PÄrdÄ“vÄ“t sarakstu</string>
+ <string name="list_dialog_rename">PÄrdÄ“vÄ“t</string>
+ <string name="list_not_available">Saraksts vairs nav pieejams, pÄrslÄ“dzas uz standarta sarakstu</string>
+ <string name="about_version">Versija</string>
+ <string name="about_changelog">Izmaiņas</string>
+ <string name="about_system">Sistēma</string>
+ <string name="about_donate">Ziedot</string>
+ <string name="about_donation_more">Ziedot\nattÄ«stÄ«tÄjiem</string>
+ <string name="about_contributors">AtbalstÄ«tÄji</string>
+ <string name="about_license">Licences</string>
+ <string name="about_apache_license"><a href=""> Apache License, Version 2.0</a></string>
+ <string name="about_help">Palīdzība</string>
+ <string name="about_system_include">LÅ«dzu, iekļaujiet sekojoÅ¡u informÄciju par sistÄ“mu, nosÅ«tot kļūdas ziņojumu vai prasot vairÄk informÄcijas par c:geo:</string>
+ <string name="settings_title_services">Servisi</string>
+ <string name="settings_summary_services">KonfigurÄ“t lietotÄja konta informÄciju un papildu pakalpojumu pieejamÄ«bu.</string>
+ <string name="settings_title_appearance">Izskats</string>
+ <string name="settings_title_cachedetails">Slēpņu dati</string>
+ <string name="settings_title_offlinedata">Bezsaistes dati</string>
+ <string name="settings_title_logging">PierakstÄ«Å¡anÄs</string>
+ <string name="settings_title_map">Karte</string>
+ <string name="settings_title_map_data">Karšu dati</string>
+ <string name="settings_title_map_content">Kartes saturs</string>
+ <string name="settings_title_basicmembers">IestatÄ«jumi bezmaksas lietotÄjiem</string>
+ <string name="settings_title_navigation">NavigÄcija</string>
+ <string name="settings_title_system">Sistēma</string>
+ <string name="settings_title_navigation_menu">NavigÄcijas izvÄ“lne</string>
+ <string name="settings_category_browser">PÄrlÅ«kprogramma</string>
+ <string name="settings_category_social">Social media</string>
+ <string name="settings_category_logging_other">Citi pierakstÄ«Å¡anÄs iestatÄ«jumi</string>
+ <string name="settings_goto_url_button">vairÄk…</string>
+ <string name="settings_title_ec">Extremcaching.com</string>
+ <string name="settings_activate_gc">Aktivizēt</string>
+ <string name="settings_activate_ec">Aktivizēt</string>
+ <string name="settings_activate_ox">Aktivizēt</string>
+ <string name="settings_gc_legal_note">Izmantojot geocaching.com pakalpojumu, jūs piekrītat Groundspeak lietošanas noteikumiem.</string>
+ <string name="settings_info_facebook_login_title">Facebook Login</string>
+ <string name="settings_info_facebook_login">Nevar veikt c:geo pieteikÅ¡anÄs ar savu Facebook kontu iekÅ¡ geocaching.com. Bet tur ir vienkÄrÅ¡s risinÄjums…</string>
+ <string name="settings_authorize">Atļaut c:geo</string>
+ <string name="settings_reauthorize">Atkal atļaut c:geo</string>
+ <string name="settings_activate_oc">Aktivizēt</string>
+ <string name="init_oc_de_description">Atļaut c:geo un opencaching.de meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="settings_activate_oc_pl">Aktivizēt</string>
+ <string name="init_oc_pl_description">Atļaut c:geo un opencaching.pl meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="settings_activate_oc_nl">Aktivizēt</string>
+ <string name="init_oc_nl_description">Atļaut c:geo un opencaching.nl meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="settings_activate_oc_us">Aktivizēt</string>
+ <string name="init_oc_us_description">Atļaut c:geo un opencaching.us meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="settings_activate_oc_ro">Aktivizēt</string>
+ <string name="init_oc_ro_description">Atļaut c:geo un opencaching.ro meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="settings_activate_oc_uk">Aktivizēt</string>
+ <string name="init_oc_uk_description">Atļaut c:geo un opencaching.org.uk meklēt slēpņus un piekļūt/filtrēt savus atrastos slēpņus.</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Lai spÄ“tu novÄ“rtÄ“t slÄ“pni, jums jÄseko instrukcijÄm GCVote.com mÄjas lapÄ un jÄievada jÅ«su GCVote parole Å¡eit.</string>
+ <string name="gcvote_sent">Balsojums veiksmīgi nosūtīts</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="settings_activate_twitter">Aktivizēt</string>
+ <string name="init_username">LietotÄjvÄrds</string>
+ <string name="init_password">Parole</string>
+ <string name="init_login">PÄrbaudÄ«t pieteikÅ¡anos</string>
+ <string name="init_login_popup">PieteikÅ¡anÄs</string>
+ <string name="init_login_popup_working">PiesakÄs sistÄ“mÄ…</string>
+ <string name="init_login_popup_ok">PieteikÅ¡anÄs izpildÄ«ta veiksmÄ«gi</string>
+ <string name="init_login_popup_failed">PieteikÅ¡anÄs neizdevÄs</string>
+ <string name="init_login_popup_failed_reason">PieteikÅ¡anÄs neizdevÄs:</string>
+ <string name="init_login_popup_not_authorized">Nav autorizēts</string>
+ <string name="init_login_popup_invalid_timestamp">VietÄ“jais laiks nepareizs, pielÄgot ierÄ«ces laiku</string>
+ <string name="init_login_popup_invalid_token">Atļauja nederÄ«ga, atkÄrtoti mÄ“Ä£iniet autorizÄ“ties</string>
+ <string name="settings_service_active">Aktīvs</string>
+ <string name="init_signature">Paraksts</string>
+ <string name="init_template_help">IestarpinÄjumi, piemÄ“ram, [NAME] tiks paplaÅ¡inÄts vÄ“lÄk lietojot Å¡o sagatavi.</string>
+ <string name="init_signature_template_button">Ievietot sagatavi</string>
+ <string name="init_signature_template_date">Datums</string>
+ <string name="init_signature_template_time">Laiks</string>
+ <string name="init_signature_template_datetime">Datums &amp; laiks</string>
+ <string name="init_signature_template_user">LietotÄjs</string>
+ <string name="init_signature_template_number">Numurs</string>
+ <string name="init_signature_template_owner">Īpašnieks</string>
+ <string name="init_signature_template_name">VÄrds</string>
+ <string name="init_signature_template_url">URL</string>
+ <string name="init_signature_template_log">Ieraksta teksts</string>
+ <string name="init_ratingwanted">GCvote reitings</string>
+ <string name="init_friends_and_own_logs_wanted">RÄdÄ«t draugu / savus</string>
+ <string name="init_summary_friends_and_own_logs_wanted">RÄdÄ«t papildu lapu ar draugu un saviem apmeklÄ“juma ierakstiem</string>
+ <string name="init_autoload">Pilns apraksts</string>
+ <string name="init_summary_autoload">VienmÄ“r ielÄdÄ“t pilnu aprakstu</string>
+ <string name="init_skin">Gaišs fons</string>
+ <string name="init_summary_skin">Izmantot gaišu fonu (nepieciešama restartēšana)</string>
+ <string name="init_address">RÄdÄ«t adresi</string>
+ <string name="init_summary_address">RÄdÄ«t adresi, nevis koordinÄtes galvenajÄ ekrÄnÄ</string>
+ <string name="init_captcha">RÄdÄ«t CAPTCHA</string>
+ <string name="init_useenglish">Lietot angļu valodu</string>
+ <string name="init_summary_useenglish">Izmantot angļu valodu c:geo (nepieciešama restartēšana)</string>
+ <string name="init_exclude">NerÄdÄ«t savus un atrastos</string>
+ <string name="init_summary_exclude">NerÄdÄ«t jÅ«su paÅ¡u vai jau atrastos slÄ“pņus</string>
+ <string name="init_showwaypoints">RÄdÄ«t Starpposmus</string>
+ <string name="init_showwaypoint_description">Ja skaits ir mazÄks nekÄ norÄdÄ«tais attÄ“lojamo slÄ“pņu skaits, tad papildus kartÄ“ tiek parÄdÄ«ti arÄ« to Starpposmi.</string>
+ <string name="init_summary_offline_wp">SaglabÄt Starpposmu statiskÄs kartes lietoÅ¡anai bezsaistÄ“</string>
+ <string name="init_save_log_img">SaglabÄt attÄ“lus</string>
+ <string name="init_log_offline">Bezsaistes apmeklÄ“juma reÄ£istrÄcija</string>
+ <string name="init_summary_log_offline">IespÄ“jot bezsaistes pierakstÄ«Å¡anos (nerÄdÄ«s tieÅ¡saistes pieteikÅ¡anÄs logu ekrÄnÄ, kad reÄ£istrÄ“ atradumu, netiks augÅ¡upielÄdÄ“ti pieraksta teksti)</string>
+ <string name="init_livelist">RÄdÄ«t virzienu</string>
+ <string name="init_summary_livelist">RÄdÄ«t slÄ“pņu virzienus sarakstÄ</string>
+ <string name="init_backup">Rezerves kopija</string>
+ <string name="init_backup_backup">Izveidot rezerves kopiju</string>
+ <string name="init_backup_running">Notiek slēpņu rezerves kopijas izveide…</string>
+ <string name="init_backup_note">LÅ«dzu, ņemiet vÄ“rÄ, ka Å¡is funkcija atjaunos datu bÄzi, kas satur slÄ“pņu un Starpposmu, bet ne jÅ«su iestatÄ«jumus.\nYour pieteikÅ¡anÄs dati un paroles nekÄdÄ gadÄ«jumÄ nepazudÄ«s no aplikÄcijas datiem.</string>
+ <string name="init_backup_restore">Atjaunot</string>
+ <string name="init_restore_failed">AtjaunoÅ¡ana neizdevÄs.</string>
+ <string name="init_restore_confirm">DatubÄze ir tukÅ¡a. Vai vÄ“laties atjaunot datubÄzes dublÄ“jumu?</string>
+ <string name="init_backup_last">Pieejams dublējums no</string>
+ <string name="settings_info_offline_maps_title">Info uz bezsaistes kartēm</string>
+ <string name="settings_info_offline_maps">c:geo atbalsta kartes lietoÅ¡anai bezsaistÄ“. JÅ«s varat lejupielÄdÄ“t kartes no Mapsforge vai pat izveidot savas kartes no OSM datiem. Vispirms jÄatlasa bezsaistes karÅ¡u direktorija, lai iegÅ«tu karti ar bezsaistes atbalstu.</string>
+ <string name="init_mapsource_select">Izvēlies karti</string>
+ <string name="init_gpx_exportdir">GPX eksporta direktorija</string>
+ <string name="init_gpx_importdir">GPX importa direktorija</string>
+ <string name="init_maptrail">ParÄdÄ«t pÄrvietojumu</string>
+ <string name="init_summary_maptrail">ParÄdÄ«t pÄrvietojumu kartÄ“</string>
+ <string name="init_share_after_export">Atvērt koplietošanas izvēlni pēc GPX eksporta</string>
+ <string name="init_trackautovisit">CeļotÄju automÄtiska atzÄ«mÄ“Å¡ana</string>
+ <string name="init_summary_trackautovisit">PÄ“c noklusÄ“juma uzlikt ceļotÄjam statusu \"ApmeklÄ“jis\" (\"VIsited\")</string>
+ <string name="init_sigautoinsert">Ievietot automÄtiski</string>
+ <string name="init_loaddirectionimg">Virziena attēls</string>
+ <string name="init_summary_loaddirectionimg">LejupielÄdÄ“t virziena bultiņas attÄ“lu pÄ“c nepiecieÅ¡amÄ«bas (nepiecieÅ¡ams tikai bezmaksas lietotÄjam)</string>
+ <string name="init_default_navigation_tool">NoklusÄ“juma navigÄcija</string>
+ <string name="init_secondary_navigation_tool">SekundÄrÄ navigÄcija</string>
+ <string name="init_default_navigation_tool_description">Å eit jÅ«s varat izvÄ“lÄ“ties primÄro navigÄcijas rÄ«ku.</string>
+ <string name="init_default_navigation_tool_select">Izvēlies rīku</string>
+ <string name="init_default_navigation_tool_2_description">Å eit var izvÄ“lÄ“ties sekundÄro navigÄcijas rÄ«ku. AktivizÄ“jiet to ilgi turot nospiestu navigÄcijas ikonu blakus slÄ“pņa nosaukumam.</string>
+ <string name="init_navigation_menu_description">Å eit var atlasÄ«t, kuras pieejamÄs navigÄcijas metodes tiks parÄdÄ«tas navigÄcijas izvÄ“lnÄ“ slÄ“pnim vai starpposmam. NeaktÄ«vie rÄ«ki nav instalÄ“ti Å¡ajÄ ierÄ«cÄ“.</string>
+ <string name="init_debug_title">AtkļūdoÅ¡anas informÄcija</string>
+ <string name="init_dbonsdcard_title">Datu bÄzes atraÅ¡anÄs vieta</string>
+ <string name="init_dbonsdcard_note">c:geo datu bÄze var tikt saglabÄt ÄrÄ“jÄ glabÄÅ¡anas vietÄ. Darot to, tas ļaus ietaupÄ«t iekÅ¡Ä“jo atmiņu, bet jÅ«s varat mazliet zaudÄ“t ÄtrdarbÄ«bu un c:geo nedarbosies, ja SD karte nav pieejama.</string>
+ <string name="init_dbonsdcard">Ä€rÄ“jÄ glabÄÅ¡anas vietÄ</string>
+ <string name="init_dbmove_dbmove">Tiek pÄrvietota datu bÄze</string>
+ <string name="init_dbmove_running">Tiek pÄrvietota datu bÄze</string>
+ <string name="init_dbmove_success">Datu bÄze ir veiksmÄ«gi pÄrvietota.</string>
+ <string name="init_dbmove_failed">NeizdevÄs pÄrvietot datu bÄzi</string>
+ <string name="init_plain_logs">VienkÄrÅ¡i ieraksti</string>
+ <string name="init_summary_plain_logs">AttÄ“lot ierakstus bezkrÄsainus</string>
+ <string name="init_use_native_ua">Android pÄrlÅ«kprogramma</string>
+ <string name="init_summary_use_native_ua">IdentificÄ“t kÄ Android pÄrlÅ«kprogrammu.Atrisina pierakstÄ«Å¡anÄs problÄ“mas, lietojot dažÄdus tÄ«kla pakalpojumu sniedzÄ“jus.</string>
+ <string name="init_rendertheme_folder">Karšu tēmu direktorija</string>
+ <string name="init_maintenance">Uzturēšana</string>
+ <string name="init_maintenance_directories_note">c:geo saglabÄ attÄ“lus, apmeklÄ“juma ierakstu attÄ“lus un citus failus, kas saistÄ«ti ar slÄ“pni atseviÅ¡Ä·Ä direktorijÄ. Dažos gadÄ«jumos (piemÄ“ram, importÄ“jot/eksportÄ“jot datu bÄzi) Å¡ajÄ direktorijÄ var bÅ«t novecojuÅ¡i faili, kuri Å¡eit var tikt dzÄ“sti.</string>
+ <string name="init_maintenance_directories">Dzēst failus, kas palikuši nevajadzīgi (novecojuši)</string>
+ <string name="init_location">Ä¢eolokÄcija</string>
+ <string name="init_location_note">IerÄ«cÄ“s, kas aprÄ«koti ar Google Play pakalpojumiem, c:geo automÄtiski var izmantot labÄku Ä£eolokÄcijas nodroÅ¡inÄtÄju. TomÄ“r tas neļauj izmantot ÄrÄ“jo BlueTooth GPS uztvÄ“rÄ“ju.</string>
+ <string name="init_location_googleplayservices">Izmantt Google Play pakalpojumus</string>
+ <string name="init_low_power">Mazjaudas režīms</string>
+ <string name="init_low_power_note">Mazjaudas režīms novÄ“rÅ¡ GPS un žiroskopa izmantoÅ¡anu, kad ļoti precÄ«za atraÅ¡anÄs vieta nav absolÅ«ti nepiecieÅ¡ama, patÄ“rÄ“ daudz vairÄk laika noteikÅ¡anai.</string>
+ <string name="init_low_power_mode">Aktivizēt mazjaudas režīmu</string>
+ <string name="init_create_memory_dump">Izveidot atmiņas izrakstu</string>
+ <string name="init_memory_dump">Atmiņas izraksts</string>
+ <string name="init_memory_dumped">Atmiņas izraksts %s</string>
+ <string name="init_hardware_acceleration_title">AparatÅ«ras paÄtrinÄta renderÄ“Å¡ana</string>
+ <string name="init_hardware_acceleration_note">AparatÅ«ras paÄtrinÄÅ¡ana renderÄ“ grafiskos elementus ÄtrÄk uz ekrÄna. TomÄ“r dažas Android operÄ“tÄjsistÄ“mas ierÄ«ces rada tehnisku kļūdu un daži teksti var parÄdÄ«ties neskaidrs (Ä«paÅ¡i treknraksta rakstzÄ«mÄ“m). AtspÄ“jojiet aparatÅ«ras paÄtrinÄÅ¡anu, ja tas jums notiek.</string>
+ <string name="init_hardware_acceleration">IespÄ“jot aparatÅ«ras paÄtrinÄÅ¡anu</string>
+ <string name="settings_open_website">Atvērt vietni</string>
+ <string name="settings_settings">Iestatījumi</string>
+ <string name="settings_information">InformÄcija</string>
+ <string name="settings_twitter_cache_message">Ziņojums par atrastu slēpni</string>
+ <string name="settings_twitter_trackable_message">Ziņojums par atrastu ceļotÄju</string>
+ <string name="init_ec_icons">Kartes ikonas</string>
+ <string name="settings_ec_icons_other">Savs stils</string>
+ <string name="settings_ec_icons_oc">Piemēram, OC</string>
+ <string name="settings_features">AtbalstÄ«tÄs funkcijas</string>
+ <string name="feature_description">Å Ädas <b>tieÅ¡saistes</b> funkcijas Å¡ajÄ mÄjas lapÄ tiek atbalstÄ«tas iekÅ¡ c:geo (papildus bezsaistes funkcijÄm):</string>
+ <string name="feature_personal_notes">Personiska piezīme</string>
+ <string name="feature_online_logging">TieÅ¡saistes pierakstÄ«Å¡anÄs</string>
+ <string name="feature_log_images">Pievienot attēlus ierakstam</string>
+ <string name="feature_watch_list">Skatīties sarakstu</string>
+ <string name="feature_own_coordinates">SaglabÄt modificÄ“tÄs koordinÄtas</string>
+ <string name="feature_search_keyword">MeklÄ“t pÄ“c atslÄ“gvÄrda</string>
+ <string name="feature_search_live_map">TIešsaistes karte</string>
+ <string name="feature_search_center">MeklÄ“t pÄ“c atraÅ¡anÄs vietas</string>
+ <string name="feature_search_geocode">Meklēt pēc Geo code</string>
+ <string name="feature_search_owner">Meklēt pēc īpašnieka</string>
+ <string name="feature_search_finder">Meklēt pēc atradēja</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>
+ <string name="map_source_osm_cyclemap">OSM: Cyclemap</string>
+ <string name="map_source_osm_offline">Bezsaistes režīmÄ</string>
+ <string name="init_sendToCgeo">Send to c:geo</string>
+ <string name="settings_info_send2cgeo_title">Info par send2cgeo</string>
+ <string name="init_sendToCgeo_name">Jūsu ierīces nosaukums</string>
+ <string name="init_sendToCgeo_register">PieprasÄ«t reÄ£istrÄciju</string>
+ <string name="init_sendToCgeo_register_ok">ReÄ£istrÄcija veiksmÄ«ga. PIN kods ir ####. Izmantojiet to tÄ«mekļa vietnÄ“ c:geo, lai pieslÄ“gtos ar Å¡o ierÄ«ci jÅ«su pÄrlÅ«kprogrammÄ.</string>
+ <string name="init_sendToCgeo_register_fail">ReÄ£istrÄcija neizdevÄs.</string>
+ <string name="auth_twitter">Twitter</string>
+ <plurals name="cache_counts">
+ <item quantity="zero">%1$d slēpnis</item>
+ <item quantity="one">%1$d slēpnis</item>
+ <item quantity="other">%1$d slēpņi</item>
+ </plurals>
+ <string name="cache_offline">Bezsaistes režīmÄ</string>
+ <string name="cache_offline_refresh">Atjaunot</string>
+ <string name="cache_offline_drop">Izmest</string>
+ <string name="cache_offline_store">SaglabÄt</string>
+ <string name="cache_offline_stored">SaglabÄtie bezsaistÄ“ JÅ«su ierÄ«cÄ“</string>
+ <string name="cache_offline_not_ready">Nav pieejams bezsaistē</string>
+ <string name="cache_offline_time_about">pirms</string>
+ <string name="cache_offline_time_mins">minūtes (-ēm)</string>
+ <string name="cache_offline_time_mins_few">dažas minūtes atpakaļ</string>
+ <string name="cache_offline_time_hour">pirms stundas</string>
+ <string name="cache_offline_time_hours">stundas (-Äm)</string>
+ <string name="cache_offline_time_days">dienu (-as)</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Atribūti</string>
+ <string name="cache_inventory">KrÄjumi</string>
+ <string name="cache_log_images_title">Apmeklējuma attēli</string>
+ <string name="cache_log_image_default_title">Attēls</string>
+ <string name="cache_personal_note">Personiska piezīme</string>
+ <string name="cache_personal_note_edit">Rediģēt</string>
+ <string name="cache_personal_note_limit">PersoniskÄs piezÄ«mes limits</string>
+ <string name="cache_personal_note_truncation">Å Ä« personiskÄ piezÄ«me tiks apcirsta iekÅ¡ Geocaching.com pÄ“c %d rakstzÄ«mju.</string>
+ <string name="cache_personal_note_upload">AugÅ¡upielÄdÄ“t</string>
+ <string name="cache_personal_note_upload_cancelled">PersoniskÄs piezÄ«mes ielÄde atcelta</string>
+ <string name="cache_description">Apraksts</string>
+ <string name="cache_description_long">Garš apraksts</string>
+ <string name="cache_watchlist_on">Jūs novērojat šo slēpni</string>
+ <string name="cache_watchlist_not_on">Å is slÄ“pnis nav jÅ«su sarakstÄ ar novÄ“rojamajiem.</string>
+ <string name="cache_watchlist_add">Pievienot sarakstam ar novērojamajiem</string>
+ <string name="cache_watchlist_remove">Noņemt no saraksta ar novērojamajiem</string>
+ <string name="cache_favpoint_on">Šis slēpnis ir viens no jūsu favorītiem.</string>
+ <string name="cache_favpoint_not_on">Šis slēpnis nav neviens no jūsu favorītiem.</string>
+ <string name="cache_favpoint_add">Pievienot</string>
+ <string name="cache_favpoint_remove">Noņemt</string>
+ <string name="cache_list_text">Saraksts:</string>
+ <string name="cache_list_change">PÄrvietot</string>
+ <string name="cache_list_unknown">Nav sarakstÄ</string>
+ <string name="cache_images">Attēli</string>
+ <string name="cache_waypoints">Starpposmi</string>
+ <plurals name="waypoints">
+ <item quantity="zero">%d Starpposms</item>
+ <item quantity="one">%d Starpposms</item>
+ <item quantity="other">%d Starpposmi</item>
+ </plurals>
+ <string name="cache_waypoints_add">Pievienot Starpposmu</string>
+ <string name="cache_hint">MÄjiens</string>
+ <string name="cache_logs">ApmeklÄ“jumu žurnÄls</string>
+ <string name="cache_logs_friends_and_own">Draugu/paša ieraksti</string>
+ <string name="cache_dialog_loading_details">IelÄdÄ“ slÄ“pņa datus…</string>
+ <string name="cache_dialog_loading_details_status_loadpage">IelÄdÄ“ lapu</string>
+ <string name="cache_dialog_loading_details_status_details">ApstrÄdÄ detaļas</string>
+ <string name="cache_dialog_loading_details_status_spoilers">IelÄdÄ“ \"spoiler\" attÄ“lus</string>
+ <string name="cache_dialog_loading_details_status_logs">IelÄdÄ“ ierakstus</string>
+ <string name="cache_dialog_loading_details_status_waypoints">ApstrÄdÄ Starpposmus</string>
+ <string name="cache_dialog_loading_details_status_gcvote">IelÄdÄ“ GCVote</string>
+ <string name="cache_dialog_loading_details_status_cache">Apkopo datus</string>
+ <string name="cache_dialog_loading_details_status_render">Gatavo attēlošanai</string>
+ <string name="cache_dialog_offline_save_title">Bezsaistes režīmÄ</string>
+ <string name="cache_dialog_offline_save_message">SaglabÄ slÄ“pni bezsaistes lietoÅ¡anai…</string>
+ <string name="cache_dialog_offline_drop_title">Bezsaistes režīmÄ</string>
+ <string name="cache_dialog_offline_drop_message">Notiek slēpņa izdzēšana no ierīces atmiņas…</string>
+ <string name="cache_dialog_refresh_title">Atjaunot</string>
+ <string name="cache_dialog_watchlist_add_title">Saraksts ar novērojamajiem</string>
+ <string name="cache_dialog_watchlist_add_message">Notiek slēpņa pievienošana novērojamo slēpņu sarakstam…</string>
+ <string name="cache_dialog_watchlist_remove_title">Saraksts ar novērojamajiem</string>
+ <string name="cache_dialog_watchlist_remove_message">Notiek slēpņa dzēšana no novērojamo slēpņu saraksta…</string>
+ <string name="cache_dialog_favorite_add_title">Favorīts</string>
+ <string name="cache_dialog_favorite_add_message">Pievienot slēpni favorītiem…</string>
+ <string name="cache_dialog_favorite_remove_title">Favorīts</string>
+ <string name="cache_dialog_favorite_remove_message">Noņemt slēpni no saviem favorītiem…</string>
+ <string name="cache_menu_radar">Radars</string>
+ <string name="cache_menu_map">Karte</string>
+ <string name="cache_menu_map_static">StatiskÄs kartes</string>
+ <string name="cache_menu_streetview">Ielas skats (Street View)</string>
+ <string name="cache_menu_browser">AtvÄ“rt pÄrlÅ«kprogrammÄ</string>
+ <string name="cache_menu_visit">Reģistrēt atradumu</string>
+ <string name="cache_menu_visit_offline">Viena klikÅ¡Ä·a bezsaistes apmeklÄ“juma reÄ£istrÄcija</string>
+ <string name="cache_menu_spoilers">\"Spoiler\" bilde (-es)</string>
+ <string name="cache_menu_event">Pievienot kalendÄram</string>
+ <string name="cache_menu_details">SÄ«kÄka informÄcija</string>
+ <string name="cache_menu_refresh">AtsvaidzinÄt</string>
+ <string name="cache_menu_move_list">PÄrvietot uz citu sarakstu</string>
+ <string name="cache_menu_whereyougo">WhereYouGo</string>
+ <string name="cache_menu_oruxmaps">OruxMaps</string>
+ <string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Balsot</string>
+ <string name="cache_status">Statuss</string>
+ <string name="cache_status_offline_log">ApmeklÄ“jums ieraksts saglabÄts</string>
+ <string name="cache_status_found">Atrasts</string>
+ <string name="cache_not_status_found">Nav atrasts</string>
+ <string name="cache_status_archived">Arhivēts</string>
+ <string name="cache_status_disabled">Atspējots</string>
+ <string name="cache_status_premium">TIkai Premium lietotÄjiem</string>
+ <string name="cache_status_not_premium">Pieejams visiem lietotÄjiem</string>
+ <string name="cache_status_stored">SaglabÄts</string>
+ <string name="cache_status_not_stored">Nav saglabÄti</string>
+ <string name="cache_geocode">Geo code</string>
+ <string name="cache_name">Nosaukums</string>
+ <string name="cache_type">Tips</string>
+ <string name="cache_size">Izmērs</string>
+ <string name="cache_distance">AttÄlums</string>
+ <string name="cache_difficulty">Grūtība</string>
+ <string name="cache_terrain">Pieķļuve</string>
+ <string name="cache_rating">Vērtējums</string>
+ <string name="cache_own_rating">Jūsu vērtējums</string>
+ <string name="cache_favorite">Favorīti</string>
+ <string name="cache_owner">Īpašnieks</string>
+ <string name="cache_hidden">Paslēpts</string>
+ <string name="cache_location">AtraÅ¡anÄs vieta</string>
+ <string name="cache_coordinates">KoordinÄtas</string>
+ <string name="cache_coordinates_original">SÄkotnÄ“jÄs koordinÄtas</string>
+ <string name="cache_spoiler_images_title">\"Spoiler\" bilde (-es)</string>
+ <string name="cache_log_types">Reģistrēto ierakstu tipi</string>
+ <string name="cache_coordinates_no">Å im slÄ“pnim nav koordinÄtu.</string>
+ <string name="cache_clear_history">Notīrīt vēsturi</string>
+ <string name="cache_remove_from_history">Noņemt no vēstures</string>
+ <string name="cache_license">Licence</string>
+ <string name="cache_image">Attēls</string>
+ <string name="cache_image_open_file">AtvÄ“rt kÄ failu</string>
+ <string name="cache_image_open_browser">AtvÄ“rt pÄrlÅ«kprogrammÄ</string>
+ <string name="gpx_import_loading_waypoints">IelÄdÄ“ Starpposmu failu</string>
+ <string name="gpx_import_title_caches_import_failed">ImportÄ“Å¡ana neizdevÄs</string>
+ <string name="gpx_import_error_io">Nevar nolasīt failu</string>
+ <string name="gpx_import_error_parser">Nepareizs faila formÄts</string>
+ <string name="gpx_import_error_unexpected">Neparedzēta kļūda</string>
+ <string name="gpx_import_canceled">GPX importēšana tika atcelta</string>
+ <string name="gpx_import_delete_title">Dzēst failu</string>
+ <string name="gpx_import_delete_message">Vai vēlaties dzēst %s?</string>
+ <string name="waypoint">Starpposms</string>
+ <string name="waypoint_cache_coordinates">SlÄ“pņa koordinÄtas</string>
+ <string name="waypoint_custom">UzstÄdÄ«t</string>
+ <string name="waypoint_my_coordinates">Manas koordinÄtas</string>
+ <string name="waypoint_bearing">Pagrieziena leņķis °</string>
+ <string name="waypoint_distance">AttÄlums</string>
+ <string name="waypoint_name">Nosaukums</string>
+ <string name="waypoint_edit">Rediģēt</string>
+ <string name="waypoint_delete">Dzēst</string>
+ <string name="waypoint_edit_title">Rediģēt Starpposmu</string>
+ <string name="waypoint_add_title">Pievienot Starpposmu</string>
+ <string name="waypoint_note">Piezīme</string>
+ <string name="waypoint_visited">Apmeklēts</string>
+ <string name="waypoint_save">SaglabÄt</string>
+ <string name="waypoint_loading">Notiek Starpposma ielÄde…</string>
+ <string name="waypoint_do_not_touch_cache_coordinates">NeizmainÄ«t slÄ“pņa koordinÄtas</string>
+ <string name="waypoint_set_as_cache_coords">IestatÄ«t kÄ slÄ“pņa koordinÄtas iekÅ¡ c:geo</string>
+ <string name="waypoint_save_and_modify_on_website">IestatÄ«t kÄ slÄ“pņa koordinÄtas c:geo un mÄjas lapÄ</string>
+ <string name="waypoint_reset_cache_coords">AtiestatÄ«t slÄ“pņa koordinÄtas</string>
+ <string name="waypoint_coordinates_has_been_reset_on_website">SlÄ“pņa koordinÄtas ir atiestatÄ«tas mÄjas lapÄ.</string>
+ <string name="waypoint_coordinates_being_reset_on_website">AtiestatÄ«t slÄ“pņa koordinÄtas mÄjas lapÄ…</string>
+ <string name="waypoint_reset">Atiestatīt</string>
+ <string name="waypoint_localy_reset_cache_coords">Atiestatīt iekš c:geo</string>
+ <string name="waypoint_reset_local_and_remote_cache_coords">AtiestatÄ«t iekÅ¡ c:geo un mÄjas lapÄ</string>
+ <string name="waypoint_being_saved">Starpposms tiek saglabÄts</string>
+ <string name="waypoint_coordinates_couldnt_be_modified_on_website">MÄjas lapa neatbalsta slÄ“pņa koordinÄtu modificÄ“Å¡anu.</string>
+ <string name="waypoint_coordinates_upload_error">ModificÄ“jot koordinÄtas mÄjas lapÄ, radÄs kļūda.</string>
+ <string name="waypoint_coordinates_uploading_to_website">Tiek augÅ¡upielÄdÄ“tas koordinÄtas %s mÄjas lapÄ.</string>
+ <string name="waypoint_coordinates_has_been_modified_on_website">SlÄ“pņa koordinÄtas mÄjas lapÄ tika modificÄ“tas uz: %s.</string>
+ <string name="waypoint_done">Izpildīts</string>
+ <string name="waypoint_duplicate">Dublicēt</string>
+ <string name="waypoint_copy_of">Kopija</string>
+ <string name="search_history">VÄ“sture</string>
+ <string name="waypoint_coordinate_formats_plain">VienkÄrÅ¡Ä</string>
+ <string name="map_map">Karte</string>
+ <string name="map_view_map">Kartes skats</string>
+ <string name="map_modes">Kartes iestatījumi</string>
+ <string name="map_mycaches_hide">NerÄdÄ«t savus/atrastos slÄ“pņus</string>
+ <string name="map_live_enable">Atļaut tiešsaistē</string>
+ <string name="map_live_disable">Deaktivizēt tiešsaistes darbību</string>
+ <string name="map_strategy_fastest">Ä€trÄkais</string>
+ <string name="map_strategy_fast">Ä€trs</string>
+ <string name="map_strategy_auto">AtkarÄ«bÄ no Ätruma</string>
+ <string name="map_strategy_detailed">Detalizēts</string>
+ <string name="search_coordinates">KoordinÄtas</string>
+ <string name="search_address">Adrese</string>
+ <string name="search_address_button">Meklēt pēc adreses</string>
+ <string name="search_hbu_button">MeklÄ“t pÄ“c Ä«paÅ¡nieka vÄrda</string>
+ <string name="search_tb">CeļotÄjs</string>
+ <string name="search_tb_button">MeklÄ“t ceļotÄju</string>
+ <string name="search_direction_rel">No šīs pozīcijas</string>
+ <string name="search_address_started">Meklē vietu</string>
+ <string name="search_own_caches">Meklēt manus slēpņus</string>
+ <string name="trackable_log_touch">PierakstÄ«t pieskÄrienu</string>
+ <string name="trackable_name">Nosaukums</string>
+ <string name="trackable_type">Veids</string>
+ <string name="trackable_owner">Īpašnieks</string>
+ <string name="trackable_spotted">Pamanīts</string>
+ <string name="trackable_spotted_in_cache">Iekš</string>
+ <string name="trackable_spotted_at_user">RokÄs</string>
+ <string name="trackable_spotted_unknown_location">AtraÅ¡anÄs nav zinÄma</string>
+ <string name="trackable_spotted_owner">Pie īpašnieka</string>
+ <string name="trackable_touch">Pieskarties</string>
+ <string name="user_menu_send_message">Nosūtīt ziņu</string>
+ <string name="navigation">NavigÄcija</string>
+ <string name="compass_title">Kompass</string>
+ <string name="compass_sensors">Aktīvie sensori</string>
+ <string name="use_gps">Izmantot tikai GPS</string>
+ <string name="use_compass">Izmantot GPS un kompasu</string>
+ <string name="destination_select">Izvēlieties galamērķi</string>
+ <string name="navigation_target">MÄ“rÄ·is</string>
+ <string name="err_nav_no_coordinates">Nevar sÄkt navigÄciju bez koordinÄtÄ“m</string>
+ <string name="license">Licence</string>
+ <string name="license_show">RÄdÄ«t licenci</string>
+ <string name="helper_barcode_description">Å ie ir Greasemonkey skripti un tÄ«mekļa vietnes, kas ļauj parÄdÄ«t Ä£eokodus kÄ svÄ«trkodus. Ar Å¡o aplikÄciju c:geo var lasÄ«t Å¡Ädu Ä£eokodus tieÅ¡i no datora ekrÄna.</string>
+ <string name="helper_pocketquery_description">Atļauj viegli izveidot un lejupielÄdÄ“t no Pocket Query, kas centrÄ“ts uz Tavu paÅ¡reizÄ“jo atraÅ¡anÄs vietu vai atlasÄ«ts no punkta kartÄ“. NepiecieÅ¡ams Geocaching.com Premium lietotÄja konts.</string>
+ <string name="export_fieldnotes_upload">AugÅ¡upielÄdÄ“t geocaching.com</string>
+ <string name="attribute_motorcycles_yes">Motocikli atļauti</string>
+ <string name="attribute_motorcycles_no">Motocikli nav atļauti</string>
+ <string name="attribute_firstaid_yes">Nepieciešama apkope</string>
+ <string name="attribute_wheelchair_yes">Pieejams ratiņkrÄ“slÄ</string>
+ <string name="attribute_wheelchair_no">Nav pieejams ratiņkrÄ“slÄ</string>
+ <string name="attribute_water_yes">TuvumÄ dzeramais Å«dens</string>
+ <string name="attribute_water_no">TuvumÄ dzeramÄ Å«dens nav</string>
+ <string name="attribute_restrooms_yes">PubliskÄs tualetes tuvumÄ</string>
+ <string name="attribute_restrooms_no">TuvumÄ nav publiskÄs tualetes</string>
+ <string name="attribute_phone_yes">Telefona tuvumÄ</string>
+ <string name="attribute_phone_no">Telefona tuvumÄ nav</string>
+ <string name="attribute_picnic_yes">Piknika galdiņi netÄlu</string>
+ <string name="attribute_picnic_no">Piknika galdiņu nav</string>
+ <string name="attribute_fuel_yes">DUS tuvumÄ</string>
+ <string name="attribute_fuel_no">DUS tuvumÄ nav</string>
+ <string name="attribute_food_yes">Ä’dinÄÅ¡ana tuvumÄ</string>
+ <string name="attribute_food_no">Ä’dinÄÅ¡anas tuvumÄ nav</string>
+ <string name="attribute_railway_yes">TuvumÄ darbojoÅ¡Äs sliedes</string>
+ <string name="attribute_railway_no">TuvumÄ darbojoÅ¡Äs sliedes nav</string>
+ <string name="attribute_webcam_yes">Tīmekļa kamera</string>
+ <string name="attribute_webcam_no">Nav tīmekļa kameras</string>
+ <string name="attribute_puzzle_yes">Puzzle / Mistērijas slēpnis</string>
+ <string name="attribute_puzzle_no">Nav puzzle / mistērija</string>
+ <string name="tts_one_meter">viens metrs</string>
+ <plurals name="tts_meters">
+ <item quantity="zero">%s m</item>
+ <item quantity="one">%s metrs</item>
+ <item quantity="other">%s metri</item>
+ </plurals>
+ <string name="tts_one_mile">viena jūdze</string>
+ <plurals name="tts_miles">
+ <item quantity="zero">%s mile</item>
+ <item quantity="one">%s jūdze</item>
+ <item quantity="other">%s jūdzes</item>
+ </plurals>
+ <string name="tts_one_foot">viena pēda</string>
+ <plurals name="tts_feet">
+ <item quantity="zero">%s pēda</item>
+ <item quantity="one">%s pēda</item>
+ <item quantity="other">%s pēdas</item>
+ </plurals>
+ <string name="tts_one_oclock">one o\'clock</string>
+ <string name="tts_oclock">%s o\'clock</string>
+ <string name="clipboard_copy_ok">Iekopēts starpliktuvē</string>
+ <plurals name="days_ago">
+ <item quantity="zero">%d tikko</item>
+ <item quantity="one">vakar</item>
+ <item quantity="other">pirms %d dienÄm</item>
+ </plurals>
+ <plurals name="favorite_points">
+ <item quantity="zero">%s izlases</item>
+ <item quantity="one">%s izlases</item>
+ <item quantity="other">%s izlases</item>
+ </plurals>
+ <string name="cgeo_shortcut">c:geo saīsne</string>
+ <string name="create_shortcut">Izveidot saīsni</string>
+ <string name="send">Nosūtīt</string>
+ <string name="showcase_logcache_title">Tiek sūtīts apmeklējuma pieraksts</string>
+ <string name="showcase_logcache_text">Atcerieties, ka daudzas komandas ir tagad redzams pogÄs virspusÄ“. Tur jÅ«s atradÄ«siet pogu apmeklÄ“juma pieraksta nosÅ«tÄ«Å¡anai.</string>
+ <string name="showcase_main_title">Jaunas izvēlnes</string>
+ <string name="showcase_main_text">c:geo tagad izvieto izvÄ“lnes elementus pogas tÄpat kÄ citas mÅ«sdienu aplikÄcijas. Daži elementi ir paslÄ“pti aiz punktotÄ simbola. Turiet nospiestu pogu, lai apskatÄ«tu tÄ aprakstu.</string>
+ <string name="showcase_cachelist_title">Saraksti pÄrslÄ“dzas</string>
+ <string name="showcase_cachelist_text">Varat pÄrslÄ“gties starp slÄ“pņu sarakstiem, noklikÅ¡Ä·inot uz saraksta nosaukuma.</string>
+ <string name="confirm_log_title">Neparasts pierakstÄ«Å¡anÄs tips</string>
+ <string name="confirm_log_message">You want to log \'%s\'. Are you sure?</string>
+</resources>
diff --git a/main/res/values-nb/strings.xml b/main/res/values-nb/strings.xml
index b007671..bc12825 100644
--- a/main/res/values-nb/strings.xml
+++ b/main/res/values-nb/strings.xml
@@ -43,7 +43,7 @@
<string name="wp_stage">Steg i multicache</string>
<string name="wp_puzzle">Spørsmål til svar</string>
<string name="wp_pkg">Parkeringsplass</string>
- <string name="wp_trailhead">Startpunkt</string>
+ <string name="wp_trailhead">Stistart</string>
<string name="wp_waypoint">Referansepunkt</string>
<string name="wp_original">Opprinnelige koordinater</string>
<string name="log_found">Funnet</string>
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Besøkte</string>
<string name="log_tb_drop">Legg igjen</string>
<string name="log_tb_changeall">Endre alle</string>
- <string name="log_save">Lagre</string>
+ <string name="log_save">Lagre offline</string>
<string name="log_saving">Lagrer logg…</string>
<string name="log_saving_and_uploading">Sender logg og laster opp bilde…</string>
<string name="log_clear">Tøm</string>
<string name="log_post_not_possible">Laster loggsiden…</string>
+ <string name="log_date_future_not_allowed">Fremtidige loggdatoer er ikke tillatt.</string>
<string name="log_add">Legg til</string>
+ <string name="log_repeat">Gjenta siste logg</string>
<string name="log_no_rating">Ingen rangering</string>
<string name="log_stars_1_description">DÃ¥rlig</string>
<string name="log_stars_15_description">Ganske dårlig</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Passord for logg:</string>
<string name="log_hint_log_password">Angi passordet for logg</string>
<string name="log_oc_team_comment">Kommentar fra OC-teamet</string>
+ <string name="log_your_saved_log">Din lagrede logg</string>
<string-array name="log_image_scales">
<item>Ingen skalering</item>
<item>512 px</item>
@@ -122,12 +125,13 @@
<string name="err_server">Klarte ikke å koble til Geocaching.com (server eller tilkobling nede?)</string>
<string name="err_server_ec">Får ikke kontakt med Extremcaching.com. Nettstedet kan være nede eller Internettilkoblingen fungerer ikke.</string>
<string name="err_login">Ingen innloggingsopplysninger lagret</string>
- <string name="err_login_failed_toast">c:geo kan ikke logge inn. c:geo fungerer frakoblet med lagrede cacher. Sjekk innloggingsinnstillinger eller aktiver Internettforbindelsen.</string>
+ <string name="err_login_failed_toast">c:geo kan ikke logge inn. c:geo fungerer offline med cacher du har lagret. Sjekk innloggingsinnstillinger eller aktiver internettforbindelsen.</string>
<string name="err_unknown">Ukjent feil</string>
+ <string name="err_unknown_address">c:geo klarte ikke finne et sted ut fra denne adressen</string>
<string name="err_comm">Ukjent tilkoblingsfeil</string>
<string name="err_missing_auth">Brukernavn eller passord er ikke oppgitt.</string>
<string name="err_wrong">Feilaktige innloggingsopplysninger</string>
- <string name="err_maintenance">Geocaching.com er nede for vedlikehold. c:geo arbeider frakoblet med lagrede cacher.</string>
+ <string name="err_maintenance">Geocaching.com er nede for vedlikehold. c:geo arbeider offline med lagrede cacher.</string>
<string name="err_license">Brukeren har ikke akseptert Geocaching.com sin lisens. c:geo kan ikke laste cachens koordinater.</string>
<string name="err_unvalidated_account">Du må aktivere kontoen din på Geocaching.com først.</string>
<string name="err_unpublished">Den forespurte cachen er ikke publisert.</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Henting av bilde mislyktes.</string>
<string name="err_tb_display">\"Beklager, c:geo klarte ikke å finne den sporbare du etterspurte. Er det virkelig en sporbar (trackable)?</string>
<string name="err_tb_details_open">Beklager, c:geo klarte ikke å åpne detaljerene til den sporbare.</string>
- <string name="err_tb_forgot_saw">Beklager, c:geo glemte hvilken sporbare du oppdaget.</string>
<string name="err_tb_find">Beklager, c:geo klarte ikke å finne noen sporbare</string>
<string name="err_tb_find_that">Beklager, c:geo finner ikke den sporbare.</string>
<string name="err_waypoint_cache_unknown">c:geo vet ikke hvilken cache du vil legge til et veipunkt for.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo finner ikke din posisjon.</string>
<string name="err_point_no_position_given_title">info kreves</string>
<string name="err_point_no_position_given">Skriv inn minst breddegrad og lengdegrad eller avstand og peiling. Du kan også skrive inn i alle fire felt.</string>
- <string name="err_point_curr_position_unavailable">c:geo har fortsatt ikke riktige koordinater. Vennligst vent…</string>
<string name="err_point_bear_and_dist_title">Trenger du hjelp?</string>
<string name="err_point_bear_and_dist">Skriv inn både retning og avstand. Retning er 0 til 360 grader i forhold til nord. Avstand angis med eller uten enheter.</string>
<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_post_failed">Beklager, c:geo klarte ikke å logge funnet.</string>
- <string name="err_log_post_failed_ec">Din logg ble trolig ikke lastet opp. Du bør sjekke det på Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Bildet til loggen ble trolig ikke lastet opp. Du bør sjekke det på Geocaching.com.</string>
+ <string name="err_log_post_failed">Det ser ut som loggen din ikke ble registrert. Du bør sjekke dette på cachens nettside.</string>
+ <string name="err_logimage_post_failed">Det ser ut som loggbildet ditt ikke ble lastet opp. Du bør sjekke om dette er tilfelle på cachens nettside.</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>
<string name="err_parse_lon">Beklager, c:geo klarte ikke å lese lengdegraden.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Nettverk</string>
<string name="loc_fused">Kombinert</string>
<string name="loc_low_power">Lavt strømforbruk</string>
+ <string name="loc_home">Hjemkoordinater</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Satellitter</string>
<string name="loc_trying">Prøver å lokalisere</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">I nærheten</string>
<string name="advanced_search_button">Søk</string>
<string name="stored_caches_button">Lagret</string>
- <string name="any_button">Finn</string>
+ <string name="any_button">GÃ¥ til</string>
<string name="unknown_scan">Fant ingen GC-koder i det skannede bildet.</string>
<string name="caches_no_cache">ingen cacher</string>
<string name="caches_more_caches">flere cacher</string>
@@ -263,15 +265,22 @@
<string name="caches_sort_finds">Antall funn</string>
<string name="caches_sort_state">Status</string>
<string name="caches_sort_storage">Dato lagret i c:geo</string>
+ <string name="caches_sort_eventdate">Eventdato</string>
<string name="caches_select_mode">Velge-modus</string>
<string name="caches_select_mode_exit">Avslutt velge-modus</string>
<string name="caches_select_invert">Inverter merking</string>
<string name="caches_nearby">I nærheten</string>
<string name="caches_manage">Administrer</string>
<string name="caches_remove_all">Fjern alle</string>
- <string name="caches_remove_all_confirm">Vil du fjerne alle %s cacher fra gjeldende liste?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Vil du fjerne denne cachen fra listen?</item>
+ <item quantity="other">Vil du fjerne alle %d cachene fra listen din?</item>
+ </plurals>
<string name="caches_remove_selected">Fjern valgte</string>
- <string name="caches_remove_selected_confirm">Vil du slette de %s merkede cachene fra enheten?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Vil du fjerne denne cachen fra enheten?</item>
+ <item quantity="other">Vil du slette de %d valgte cachene fra enheten?</item>
+ </plurals>
<string name="caches_remove_progress">Fjerner cacher</string>
<string name="caches_delete_events">Slett gamle eventer</string>
<string name="caches_refresh_selected">Oppdater valgte</string>
@@ -285,19 +294,24 @@
<string name="caches_recaptcha_hint">Tekst fra bilde</string>
<string name="caches_recaptcha_continue">Fortsett</string>
<string name="caches_filter">Filter</string>
- <string name="caches_filter_title">Filtrer etter</string>
+ <string name="caches_filter_title">Filter</string>
<string name="caches_filter_size">Størrelse</string>
<string name="caches_filter_type">Type</string>
<string name="caches_filter_track">Med sporbare</string>
<string name="caches_filter_clear">Nullstill filtre</string>
<string name="caches_filter_modified">Med endrede koordinater</string>
+ <string name="caches_filter_offline_log">Med offlinelogg</string>
<string name="caches_filter_origin">Opprinnelig posisjon</string>
<string name="caches_filter_distance">Avstand</string>
<string name="caches_filter_personal_note">Med personlig notat</string>
<string name="caches_filter_popularity">Favoritter</string>
<string name="caches_filter_popularity_ratio">Favoritter [%]</string>
+ <string name="caches_filter_personal_data">Med personlige data</string>
+ <string name="caches_filter_rating">Med vurdering</string>
+ <string name="caches_filter_own_rating">Med egen vurdering</string>
<string name="caches_removing_from_history">Fjerner fra historikken…</string>
<string name="caches_clear_offlinelogs">Fjern offline-logger</string>
+ <string name="caches_clear_offlinelogs_message">Vil du fjerne offline-loggene?</string>
<string name="caches_clear_offlinelogs_progress">Fjerner offline-logger</string>
<string name="list_menu_create">Opprett ny liste</string>
<string name="list_menu_drop">Fjern liste</string>
@@ -320,13 +334,17 @@
<string name="list_not_available">Listen er ikke lenger tilgjengelig, bytter til standarlisten</string>
<string name="about_version">Versjon</string>
<string name="about_changelog">Oppdateringslogg</string>
+ <string name="about_system">System</string>
<string name="about_donate">Donér</string>
<string name="about_donation_more">Donér til\nutviklerne</string>
<string name="about_contributors">Bidragsytere</string>
<string name="about_license">Lisens</string>
<string name="about_apache_license"><a href="">Apache-lisens, versjon 2.0</a></string>
<string name="about_help">Hjelp</string>
+ <string name="about_system_include">Inkluder den følgende informasjonen når du sender en feilrapport eller ber om mer informasjon fra c:geo:</string>
+ <string name="changelog_github">Liste over alle endringer</string>
<string name="settings_title_services">Tjenester</string>
+ <string name="settings_summary_services">Konfigurer kontoinformasjon og tilgang til tilleggstjenester.</string>
<string name="settings_title_appearance">Utseende</string>
<string name="settings_title_cachedetails">Cache-detaljer</string>
<string name="settings_title_offlinedata">Offline-data</string>
@@ -334,14 +352,17 @@
<string name="settings_title_map">Vis på kartet</string>
<string name="settings_title_map_data">Kartdata</string>
<string name="settings_title_map_content">Kartinnhold</string>
+ <string name="settings_title_gpx">GPX</string>
<string name="settings_title_basicmembers">Alternativer for Basic-medlemmer</string>
<string name="settings_title_navigation">Navigasjon</string>
<string name="settings_title_system">System</string>
<string name="settings_title_navigation_menu">Navigasjonsmenyen</string>
<string name="settings_category_browser">Nettleser</string>
+ <string name="settings_category_geocaching">Geocaching</string>
<string name="settings_category_social">Sosiale medier</string>
<string name="settings_category_logging_other">Andre loggeinnstillinger</string>
<string name="settings_goto_url_button">mer…</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">Aktiver</string>
@@ -355,17 +376,25 @@
<string name="init_oc">Opencaching.de</string>
<string name="settings_activate_oc">Aktiver</string>
<string name="init_oc_de_description">Gi c:geo tilgang til å bruke opencaching.de for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
+ <string name="init_oc_pl">Opencaching.pl</string>
<string name="settings_activate_oc_pl">Aktiver</string>
<string name="init_oc_pl_description">Gi c:geo tilgang til å bruke opencaching.pl for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
+ <string name="init_oc_nl">Opencaching.nl</string>
<string name="settings_activate_oc_nl">Aktiver</string>
<string name="init_oc_nl_description">Gi c:geo tilgang til å bruke opencaching.nl for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
+ <string name="init_oc_us">Opencaching.us</string>
<string name="settings_activate_oc_us">Aktiver</string>
<string name="init_oc_us_description">Gi c:geo tilgang til å bruke opencaching.us for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
+ <string name="init_oc_ro">Opencaching.ro</string>
<string name="settings_activate_oc_ro">Aktiver</string>
<string name="init_oc_ro_description">Gi c:geo tilgang til å bruke opencaching.ro for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
+ <string name="init_oc_uk">Opencaching.org.uk</string>
<string name="settings_activate_oc_uk">Aktiver</string>
<string name="init_oc_uk_description">Gi c:geo tilgang til å bruke opencaching.org.uk for å søke etter cacher og vise/filtrere dine funnede cacher.</string>
<string name="init_gcvote">GCVote.com</string>
+ <string name="init_gcvote_password_description">For å kunne vurdere en cache må du følge instruksjonene på GCVote.com og angi ditt GCVote passord her.</string>
+ <string name="err_gcvote_send_rating">Feil ved sending av vurdering. Sjekk at passordet for GCVote i innstillingene er riktig eller fjern passordet.</string>
+ <string name="gcvote_sent">Stemmegivning sendt</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktiver</string>
<string name="init_username">Brukernavn</string>
@@ -436,6 +465,8 @@
<string name="init_backup_success">Databasen til c:geo ble kopiert til:</string>
<string name="init_backup_failed">Sikkerhetskopi av databasen til c:geo mislyktes.</string>
<string name="init_backup_unnecessary">Databasen er tom, sikkerhetskopiering er ikke nødvendig.</string>
+ <string name="backup_confirm_overwrite">Vil du overskrive den eksisterende sikkerhetskopien fra %s?</string>
+ <string name="restore_confirm_overwrite">Vil du overskrive %s på enheten din med sikkerhetskopien?</string>
<string name="init_restore_success">Gjenoppretting fullført.</string>
<string name="init_restore_failed">Gjenoppretting mislyktes.</string>
<string name="init_restore_running">Gjenoppretter databasen…</string>
@@ -485,10 +516,17 @@
<string name="init_maintenance_directories_note">c:geo lagrer bilder, loggbilder og andre filer knyttet til en cache i en egen mappe. I noen situasjoner (som importering/eksportering av databasen) vil denne mappen inneholde utdaterte filer som kan slettes her.</string>
<string name="init_maintenance_directories">Slett utdaterte filer</string>
<string name="init_location">Geolokasjon</string>
+ <string name="init_location_note">På enheter utstyrt med Google spill tjenester, kan c:geo automatisk bruke en bedre geolocation-leverandør. Men dette forhindrer bruk av en ekstern BlueTooth GPS-mottaker.</string>
<string name="init_location_googleplayservices">Bruk Google Play Services</string>
+ <string name="init_low_power">Strømsparingsmodus</string>
+ <string name="init_low_power_note">Strømsparingsmodus unngår GPS og gyroskop når en svært nøyaktig plassering ikke er strengt nødvendig, men det gir lengere behandlingstid.</string>
+ <string name="init_low_power_mode">Aktivere strømsparingsmodus</string>
<string name="init_create_memory_dump">Opprett minnedump</string>
<string name="init_memory_dump">Minnedump</string>
<string name="init_memory_dumped">Minne dumpet til %s</string>
+ <string name="init_hardware_acceleration_title">Maskinvareakselerert rendering</string>
+ <string name="init_hardware_acceleration_note">Maskinvare-akselerasjon gjengir grafikkelementer raskere på skjermen. Men på noen Android telefoners operativsystem er det noen feil, og noe av teksten kan komme fram som uklare Deaktiver maskinvare-akselerasjonen hvis dette skjer med deg.</string>
+ <string name="init_hardware_acceleration">Aktivere maskinvareakselerasjonen</string>
<string name="settings_open_website">Ã…pne nettside</string>
<string name="settings_settings">Innstillinger</string>
<string name="settings_information">Informasjon</string>
@@ -536,7 +574,7 @@
<string name="auth_ocde">opencaching.de</string>
<string name="auth_dialog_completed_oc">c:geo har nå fått godkjenning til å kommunisere med %s.</string>
<plurals name="cache_counts">
- <item quantity="one">Én cache</item>
+ <item quantity="one">En cache</item>
<item quantity="other">%1$d cacher</item>
</plurals>
<string name="cache_offline">Offline</string>
@@ -581,11 +619,12 @@
<string name="cache_images">Bilder</string>
<string name="cache_waypoints">Veipunkter</string>
<plurals name="waypoints">
- <item quantity="one">1 veipunkt</item>
+ <item quantity="one">Et veipunkt</item>
<item quantity="other">%d veipunkter</item>
</plurals>
<string name="cache_waypoints_add">Legg til veipunkter</string>
<string name="cache_hint">Hint</string>
+ <string name="cache_hint_not_available">Ingen hint tilgjengelig</string>
<string name="cache_logs">Loggbok</string>
<string name="cache_logs_friends_and_own">Venners/egne logger</string>
<string name="cache_dialog_loading_details">Laster cachens detaljer…</string>
@@ -625,9 +664,10 @@
<string name="cache_menu_streetview">Gatevisning</string>
<string name="cache_menu_browser">Ã…pne i nettleseren</string>
<string name="cache_menu_visit">Logg funn</string>
- <string name="cache_menu_visit_offline">Logg besøket offline</string>
+ <string name="cache_menu_visit_offline">Ett-klikks offlinelogg</string>
<string name="cache_menu_spoilers">Bilder</string>
<string name="cache_menu_around">Cacher i nærheten</string>
+ <string name="around">Rundt %s</string>
<string name="cache_menu_event">Eksporter til kalender</string>
<string name="cache_menu_details">Detaljer</string>
<string name="cache_menu_refresh">Oppdater</string>
@@ -636,6 +676,9 @@
<string name="cache_menu_whereyougo">WhereYouGo</string>
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Avgi stemme</string>
+ <string name="cache_menu_checker">Ã…pne Geochecker</string>
+ <string name="cache_menu_ignore">Ignorer cache</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Logg lagret</string>
<string name="cache_status_found">Funnet</string>
@@ -721,6 +764,7 @@
<string name="waypoint_note">Note</string>
<string name="waypoint_visited">Besøkte</string>
<string name="waypoint_save">Save</string>
+ <string name="waypoint_cancel_edit">Avbryt</string>
<string name="waypoint_loading">Laster veipunkt…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Ingen endring i cachens koordinater</string>
<string name="waypoint_set_as_cache_coords">Angi som cachens koordinater i c:geo</string>
@@ -745,6 +789,8 @@
<string name="search_clear_history">Slett historikk</string>
<string name="search_history_cleared">Historikken er slettet</string>
<string name="waypoint_coordinate_formats_plain">Ren tekst</string>
+ <string name="from_clipboard">Fra utklippstavlen.</string>
+ <string name="copy_to_clipboard">Kopier til utklippstavle</string>
<string name="visit_tweet">Del dette funnet på Twitter</string>
<string name="map_map">Kart</string>
<string name="map_live">Live-kart</string>
@@ -776,7 +822,7 @@
<string name="search_address_button">Søk med adresse</string>
<string name="search_geo">Geokode</string>
<string name="search_geo_button">Søk med geokode</string>
- <string name="search_kw">Nøkklord</string>
+ <string name="search_kw">Nøkkelord</string>
<string name="search_kw_prefill">Nøkkelord</string>
<string name="search_kw_button">Søk med nøkkelord</string>
<string name="search_fbu">Funnet av bruker</string>
@@ -786,7 +832,7 @@
<string name="search_hbu_prefill">Eier</string>
<string name="search_hbu_button">Søk med</string>
<string name="search_tb">Sporbar (trackable)</string>
- <string name="search_tb_hint">Identifisering av sporbare</string>
+ <string name="search_tb_hint">Sporingskode</string>
<string name="search_tb_button">Søk etter sporbare</string>
<string name="search_destination">Lokaliser ved hjelp av koordinater</string>
<string name="search_direction_rel">Fra denne plassen</string>
@@ -796,7 +842,7 @@
<string name="search_pocket_title">Pocket Query</string>
<string name="search_pocket_loading">Laster en liste med Pocket Queries</string>
<string name="search_pocket_select">Velg Pocket Query</string>
- <string name="trackable">Sporbar</string>
+ <string name="trackable">Sporbar (TB eller coin)</string>
<string name="trackable_details_loading">Laster detaljene til den sporbare…</string>
<string name="trackable_log_touch">Logg sporbar</string>
<string name="trackable_browser_open">Ã…pne i nettleseren</string>
@@ -849,7 +895,7 @@
<string name="helper_contacts_description">Gjør det mulig å åpne en kontakt (i telefonens adressebok) direkte fra en logg så du enklere kan be om hjelp fra dine venner.</string>
<string name="helper_sendtocgeo_description">Send til c:geo (send2c:geo) er en nettleserutvidelse <strong>for din pc</strong>. PÃ¥ geocaching.com kan du sende cacher til din smarttelefon ved hjelp av en egen knapp i nettleseren.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Enkel, brukervennlig app for å vise online kart, men som også kan laste ned kart til offline bruk. Støtter også spor, POI-håndtering (points of interest) og mange andre nyttige funksjoner.</string>
+ <string name="helper_locus_description">App for utendørs navigasjon til din mobil eller tablet. I appen kan du se topo-kart offline, spore ruten din, lete etter turbokser, bruke en stemmeguide og mye annet.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Du kan bruke radaren i denne appen sammen med c:geo. Den gir mye GPS-relatert informasjon.</string>
<string name="helper_bluetoothgps_title">Blåtann-GPS</string>
@@ -1101,12 +1147,15 @@
<string name="attribute_offset_cache_no">Ikke offset-cache</string>
<string name="quote">For å gjøre geocaching enklere og brukerne latere.</string>
<string name="powered_by">carnero</string>
- <string name="support">e-post adresse: <a href="mailto:support@cgeo.org">support@cgeo.org</a></string>
- <string name="website">web-side: <a href="http://cgeo.org/">cgeo.org</a></string>
- <string name="facebook">facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo i Google Play</a></string>
+ <string name="support_title">Støtte</string>
+ <string name="website_title">Nettside</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href=""> c:geo-siden</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo i Google Play</a></string>
<string name="about_twitter">Ønsker du at <b>c:geo</b> skal poste en status på Twitter hver gang du logger ett funn via <b>c:geo</b>?</string>
+ <string name="faq_title">Ofte Stilte Spørsmål</string>
<string name="status_new_release" tools:ignore="UnusedResources">Ny versjon tilgjengelig. \nKlikk for å installere.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Ny \"nightly build\" er tilgjengelig.\nKlikk for å installere.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Ny \"release candidate\" er tilgjengelig.\nKlikk for å installere.</string>
@@ -1141,9 +1190,9 @@
</plurals>
<plurals name="favorite_points">
<item quantity="one">%s favoritt</item>
- <item quantity="other">%s favoritt</item>
+ <item quantity="other">%s favoritter</item>
</plurals>
- <string name="percent_favorite_points">%\ favoritter</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoritter.</string>
<string name="cgeo_shortcut">c:geo-snartvei</string>
<string name="create_shortcut">Opprett snarvei</string>
<string name="send">Send</string>
@@ -1151,6 +1200,10 @@
<string name="showcase_logcache_text">Husk, mange kommandoer er nå i tittellinjen. Der finner du knappen for å sende den ferdige loggen.</string>
<string name="showcase_main_title">Nye menyer</string>
<string name="showcase_main_text">c:geo har nå plassert menyelementer i tittellinjen, slik som andre moderne app-er. Noen elementer er skjult bak symbolet med prikker. Langt trykk på en knapp viser en beskrivelse av funksjonen.</string>
+ <string name="showcase_cachelist_title">Bytter lister.</string>
+ <string name="showcase_cachelist_text">Du kan bytte mellom geocache lister ved å klikke på tittelen på listen.</string>
+ <string name="showcase_compass_hint_title">Vis hint</string>
+ <string name="showcase_compass_hint_text">Denne nye menyen kan gi deg hjelp til å finne cachen - her vises hintet, hvis det er tilgjengelig.</string>
<string name="confirm_log_title">Uvanlig loggtype</string>
<string name="confirm_log_message">Du vil logge \'%s\'. Er du sikker?</string>
</resources>
diff --git a/main/res/values-nl/strings.xml b/main/res/values-nl/strings.xml
index 76efe6a..60a4243 100644
--- a/main/res/values-nl/strings.xml
+++ b/main/res/values-nl/strings.xml
@@ -41,7 +41,7 @@
<string name="cache_size_very_large">Erg Groot</string>
<string name="wp_final">Eindbestemming</string>
<string name="wp_stage">Multi-cache punt</string>
- <string name="wp_puzzle">Vraag voor antwoord</string>
+ <string name="wp_puzzle">Te beantwoorden vraag</string>
<string name="wp_pkg">Parkeer gelegenheid</string>
<string name="wp_trailhead">Trailhead</string>
<string name="wp_waypoint">Referentie punt</string>
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Bezoek</string>
<string name="log_tb_drop">Hier droppen</string>
<string name="log_tb_changeall">Wijzig alles</string>
- <string name="log_save">Opslaan</string>
+ <string name="log_save">Off line opslaan</string>
<string name="log_saving">Log opslaan…</string>
<string name="log_saving_and_uploading">Verzenden van log en uploaden foto…</string>
<string name="log_clear">Wissen</string>
<string name="log_post_not_possible">Laden Log Pagina…</string>
+ <string name="log_date_future_not_allowed">Log datums in de toekomst zijn niet toegestaan.</string>
<string name="log_add">Toevoegen</string>
+ <string name="log_repeat">Herhaal laatste log</string>
<string name="log_no_rating">Geen beoordeling</string>
<string name="log_stars_1_description">Slecht</string>
<string name="log_stars_15_description">Redelijk slecht</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Log wachtwoord:</string>
<string name="log_hint_log_password">Voer Login Wachtwoord</string>
<string name="log_oc_team_comment">OC Team commentaar</string>
+ <string name="log_your_saved_log">Je opgeslagen log</string>
<string-array name="log_image_scales">
<item>Niet schalen</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Geen login informatie opgeslagen</string>
<string name="err_login_failed_toast">Sorry, c:geo kan niet inloggen. c:geo werkt in offline modus. Controleer je gebruikersnaam en wachtwoord en/of zet de internetverbinding aan.</string>
<string name="err_unknown">Onbekende fout</string>
+ <string name="err_unknown_address">c:geo was niet in staat dit adres te herkennen als bestaande locatie</string>
<string name="err_comm">Onbekende communicatiefout</string>
<string name="err_missing_auth">Geen gebruikersnaam en/of wachtwoord ingesteld.</string>
<string name="err_wrong">Foutieve login informatie</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Verwerven van een foto is mislukt.</string>
<string name="err_tb_display">Sorry, c:geo kan de gezochte trackable niet weergeven. Is het wel een trackable?</string>
<string name="err_tb_details_open">Sorry, c:geo kan de trackable details niet laden.</string>
- <string name="err_tb_forgot_saw">Sorry, c:geo is vergeten welke trackable je gezien hebt.</string>
<string name="err_tb_find">Sorry, c:geo kan de trackable niet vinden</string>
<string name="err_tb_find_that">Sorry, c:geo kan die trackable niet vinden.</string>
<string name="err_waypoint_cache_unknown">Sorry, c:geo weet niet aan welke cache je een waypoint wil toevoegen.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">Sorry, c:geo kan niet bepalen waar je bent.</string>
<string name="err_point_no_position_given_title">Info benodigd</string>
<string name="err_point_no_position_given">Geef op zijn minst lengte- en breedtegraad of afstand en richting. Of vul alle 4 de velden.</string>
- <string name="err_point_curr_position_unavailable">c:geo heeft de huidige coördinaten nog niet. Even geduld a.u.b….</string>
<string name="err_point_bear_and_dist_title">Hulp nodig?</string>
<string name="err_point_bear_and_dist">Vul zowel richting als afstand. Richting is hoek van 0 to 360 graden t.o.v. het noorden. Afstand mag met of zonder eenheid.</string>
<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_post_failed">Sorry, het is c:geo niet gelukt het log te posten.</string>
- <string name="err_log_post_failed_ec">Het lijkt erop dat uw log niet werd gepost. Controleer het op Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Het lijkt erop dat uw log-foto niet geüpload is. Controleer het op Geocaching.com.</string>
+ <string name="err_log_post_failed">Het lijkt erop dat je log niet werd gepost. Controleer het op de cache webpagina.</string>
+ <string name="err_logimage_post_failed">Het lijkt erop dat uw log-afbeelding niet is geüpload. Controleer het op de cache webpagina.</string>
<string name="err_search_address_forgot">Sorry, c:geo is het adres dat je zoekt vergeten.</string>
<string name="err_parse_lat">Sorry, c:geo kan breedtegraad niet verwerken.</string>
<string name="err_parse_lon">Sorry, c:geo kan lengtegraad niet verwerken.</string>
@@ -210,7 +211,8 @@
<string name="loc_last">Laatst bekende</string>
<string name="loc_net">Netwerk</string>
<string name="loc_fused">Gecombineerd</string>
- <string name="loc_low_power">Batterij bijna leeg</string>
+ <string name="loc_low_power">Spaarstand</string>
+ <string name="loc_home">Thuis coördinaten</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Proberen te lokaliseren</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Dichtbij</string>
<string name="advanced_search_button">Zoeken</string>
<string name="stored_caches_button">Opgeslagen</string>
- <string name="any_button">Elke locatie</string>
+ <string name="any_button">Ga naar</string>
<string name="unknown_scan">De gescande afbeelding bevat geen geocode.</string>
<string name="caches_no_cache">Geen caches</string>
<string name="caches_more_caches">Meer caches</string>
@@ -263,15 +265,14 @@
<string name="caches_sort_finds">Aantal keer gevonden</string>
<string name="caches_sort_state">Selectie omkeren</string>
<string name="caches_sort_storage">Datum opgeslagen op apparaat</string>
+ <string name="caches_sort_eventdate">Event datum</string>
<string name="caches_select_mode">Selectie modus</string>
<string name="caches_select_mode_exit">Selectie modus beëindigen</string>
<string name="caches_select_invert">Selectie omkeren</string>
<string name="caches_nearby">Nabij</string>
<string name="caches_manage">Beheer</string>
<string name="caches_remove_all">Verwijder alles</string>
- <string name="caches_remove_all_confirm">Wil je alle %s caches uit de huidige lijst verwijderen?</string>
<string name="caches_remove_selected">Selectie verwijderen</string>
- <string name="caches_remove_selected_confirm">Wil je de geselecteerde %s caches verwijderen van uw apparaat?</string>
<string name="caches_remove_progress">Caches worden verwijderd</string>
<string name="caches_delete_events">Verwijder afgelopen evenementen</string>
<string name="caches_refresh_selected">Ververs geselecteerden</string>
@@ -291,13 +292,18 @@
<string name="caches_filter_track">Met trackables</string>
<string name="caches_filter_clear">Maak filters leeg</string>
<string name="caches_filter_modified">Met aangepaste coordinaten</string>
+ <string name="caches_filter_offline_log">Met offline log</string>
<string name="caches_filter_origin">Oorsprong</string>
<string name="caches_filter_distance">Afstand</string>
<string name="caches_filter_personal_note">Met privé cachenotitie</string>
<string name="caches_filter_popularity">Favorieten</string>
<string name="caches_filter_popularity_ratio">Favorieten [%]</string>
+ <string name="caches_filter_personal_data">Met persoonlijke gegevens</string>
+ <string name="caches_filter_rating">Met rating</string>
+ <string name="caches_filter_own_rating">Met eigen rating</string>
<string name="caches_removing_from_history">Verwijderen uit geschiedenis…</string>
<string name="caches_clear_offlinelogs">Verwijderen offline logs</string>
+ <string name="caches_clear_offlinelogs_message">Wil je de offline logs wissen?</string>
<string name="caches_clear_offlinelogs_progress">Offline logs worden verwijderd</string>
<string name="list_menu_create">Maak nieuwe lijst</string>
<string name="list_menu_drop">Verwijder huidige lijst</string>
@@ -320,13 +326,17 @@
<string name="list_not_available">Lijst is niet langer beschikbaar, wissel naar standaard lijst</string>
<string name="about_version">Versie</string>
<string name="about_changelog">Changelog</string>
+ <string name="about_system">Systeem</string>
<string name="about_donate">Doneren</string>
<string name="about_donation_more">Doneren aan\nontwikkeling</string>
<string name="about_contributors">Bijdragers</string>
<string name="about_license">Licentie</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Help</string>
+ <string name="about_system_include">Voeg volgende systeem informatie toe wanneer je een bug report stuurt of vraagt om meer informatie over c:geo:</string>
+ <string name="changelog_github">Lijst met alle wijzigingen</string>
<string name="settings_title_services">Diensten</string>
+ <string name="settings_summary_services">Gebruikersaccount informatie en toegang tot optionele services configureren.</string>
<string name="settings_title_appearance">Uiterlijk</string>
<string name="settings_title_cachedetails">Cache Details</string>
<string name="settings_title_offlinedata">Offline gegevens</string>
@@ -374,6 +384,9 @@
<string name="settings_activate_oc_uk">Activeren</string>
<string name="init_oc_uk_description">c:geo authoriseren met opencaching.org.uk om naar caches te zoeken en het filteren van gevonden caches.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Om een cache te kunnen beoordelen, volg de instructies op GCVote.com en geef hier uw GCVote wachtwoord op.</string>
+ <string name="err_gcvote_send_rating">Fout bij het verzenden van beoordeling, controleer het GCVote wachtwoord in instellingen of maak deze leeg.</string>
+ <string name="gcvote_sent">Stem succesvol verzonden</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activeren</string>
<string name="init_username">Gebruikersnaam</string>
@@ -444,6 +457,8 @@
<string name="init_backup_success">De database van c:geo was succesvol gekopieerd naar het bestand:</string>
<string name="init_backup_failed">Backup van c:geo database is niet gelukt.</string>
<string name="init_backup_unnecessary">Database is leeg, backup niet nodig.</string>
+ <string name="backup_confirm_overwrite">Wilt je de bestaande backup van %s overschrijven?</string>
+ <string name="restore_confirm_overwrite">Wil je %s op uw apparaat overschrijven met de backup?</string>
<string name="init_restore_success">Herstellen is gelukt.</string>
<string name="init_restore_failed">Herstellen is niet gelukt.</string>
<string name="init_restore_running">Herstellen van de cache database…</string>
@@ -583,7 +598,7 @@
<string name="cache_personal_note_upload">Uploaden</string>
<string name="cache_personal_note_uploading">Uploading persoonlijke notitie</string>
<string name="cache_personal_note_upload_done">Persoonlijke notitie geupload</string>
- <string name="cache_personal_note_upload_cancelled">Persoonlijk notitie uploaden geannulleerd</string>
+ <string name="cache_personal_note_upload_cancelled">Persoonlijke notitie uploaden geannuleerd</string>
<string name="cache_description">Omschrijving</string>
<string name="cache_description_long">Lange omschrijving</string>
<string name="cache_description_table_note">Omschrijving bevat een tabel-layout welke misschien op %s bekeken moet worden.</string>
@@ -606,6 +621,7 @@
</plurals>
<string name="cache_waypoints_add">Waypoint toevoegen</string>
<string name="cache_hint">Hint</string>
+ <string name="cache_hint_not_available">Geen hint beschikbaar</string>
<string name="cache_logs">Logboek</string>
<string name="cache_logs_friends_and_own">Vrienden/Eigen Logs</string>
<string name="cache_dialog_loading_details">Cache details laden…</string>
@@ -645,9 +661,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Open in browser</string>
<string name="cache_menu_visit">Log bezoek</string>
- <string name="cache_menu_visit_offline">Log bezoek offline</string>
+ <string name="cache_menu_visit_offline">Enkele klik offline log</string>
<string name="cache_menu_spoilers">Spoiler afbeeldingen</string>
<string name="cache_menu_around">Caches rondom</string>
+ <string name="around">Rondom %s</string>
<string name="cache_menu_event">Toevoegen aan kalender</string>
<string name="cache_menu_details">Details</string>
<string name="cache_menu_refresh">Verversen</string>
@@ -657,6 +674,10 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_android_wear">Android Wear</string>
+ <string name="cache_menu_vote">Stem</string>
+ <string name="cache_menu_checker">Open Geochecker</string>
+ <string name="cache_menu_ignore">Negeer cache</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Log opgeslagen</string>
<string name="cache_status_found">Gevonden</string>
@@ -742,6 +763,7 @@
<string name="waypoint_note">Notitie</string>
<string name="waypoint_visited">Bezocht</string>
<string name="waypoint_save">Opslaan</string>
+ <string name="waypoint_cancel_edit">Annuleren</string>
<string name="waypoint_loading">Waypoint laden…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Wijzig cachecoördinaten niet</string>
<string name="waypoint_set_as_cache_coords">Zet als cachecoördinaten in c:geo</string>
@@ -766,6 +788,8 @@
<string name="search_clear_history">Maak geschiedenis leeg</string>
<string name="search_history_cleared">Geschiedenis leeggemaakt</string>
<string name="waypoint_coordinate_formats_plain">Plat</string>
+ <string name="from_clipboard">Van klembord</string>
+ <string name="copy_to_clipboard">Kopieer naar klembord</string>
<string name="visit_tweet">Post deze vondst op Twitter</string>
<string name="map_map">Kaart</string>
<string name="map_live">Live kaart</string>
@@ -870,7 +894,7 @@
<string name="helper_contacts_description">Maakt het mogelijk een contactpersoon (uit je adresboek) te openen rechtstreeks vanuit een log, zodat je vrienden makkelijker om hulp kunt vragen.</string>
<string name="helper_sendtocgeo_description">Verzenden naar c:geo is een browserextensie <strong>voor uw PC</strong>. Tijdens het browsen op geocaching.com, kunt u caches verzenden naar uw smartphone met een klik direct in de browser.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Simpele bruikbare applicatie om online kaarten weer te geven en deze voor offline gebruik te downloaden (alleen rasterkarten). Ook ondersteuning voor track recording, poi afhandeling en vele andere handige functies.</string>
+ <string name="helper_locus_description">Outdoor navigatie app voor uw telefoon of Tablet. Topo kaarten offline bekijken, uw route vastleggen, geocaches zoeken, gebruik een stem gids en meer.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">De radar van deze applicatie kan gebruikt worden samen met c:geo. Het bied ook vele andere GPS gerelateerde informatie.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -982,7 +1006,7 @@
<string name="attribute_snowshoes_no">Geen sneeuwschoenen nodig</string>
<string name="attribute_skiis_yes">Langlaufski\'s nodig</string>
<string name="attribute_skiis_no">Langlaufski\'s niet nodig</string>
- <string name="attribute_s_tool_yes">Speciate gereedschappen nodig</string>
+ <string name="attribute_s_tool_yes">Speciale gereedschappen nodig</string>
<string name="attribute_s_tool_no">Geen speciale gereedschappen nodig</string>
<string name="attribute_wirelessbeacon_yes">Draadloos baken</string>
<string name="attribute_wirelessbeacon_no">Geen draadloos baken</string>
@@ -1122,13 +1146,15 @@
<string name="attribute_offset_cache_no">Geen offset cache</string>
<string name="quote">Om geocaching makkelijker en gebruikers luier te maken.</string>
<string name="powered_by">carnero</string>
- <string name="support">Support: <a href="">support@cgeo.org</a></string>
- <string name="website">Website: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo op Google Play</a></string>
+ <string name="support_title">Ondersteuning</string>
+ <string name="website_title">Website</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">c:geo pagina</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo op Google Play</a></string>
<string name="about_twitter">Moet <b>c:geo</b> elke cache vondst publiceren naar Twitter?</string>
- <string name="faq">FAQ: <a href=""> faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Nieuwe release beschikbaar.\nTik om te installeren.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nieuwe nightly-release beschikbaar.\nTik om te installeren.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Nieuwe release-candidaad beschikbaar.\nTik om te installeren.</string>
@@ -1173,7 +1199,7 @@
<item quantity="one">%s favoriet</item>
<item quantity="other">%s favorieten</item>
</plurals>
- <string name="percent_favorite_points">%\ favorieten</string>
+ <string name="more_than_percent_favorite_points">&gt; %d %% favorieten</string>
<string name="cgeo_shortcut">c:geo snelkoppeling</string>
<string name="create_shortcut">Maak snelkoppeling</string>
<string name="send">Verzenden</string>
@@ -1183,6 +1209,8 @@
<string name="showcase_main_text">c:geo plaatst nu menu-items in de titelbalk, zoals veel andere moderne apps. Sommige items zijn verborgen achter het symbool met de drie puntjes. Druk lang op een knop om de beschrijving te zien.</string>
<string name="showcase_cachelist_title">Wisselen van lijst</string>
<string name="showcase_cachelist_text">Je kan wisselen tussen geocache lijsten door te klikken op de titel van de lijst.</string>
+ <string name="showcase_compass_hint_title">Toon hint</string>
+ <string name="showcase_compass_hint_text">Dit nieuwe menu-item kan een idee geven waar de cache gevonden kan worden - het toont de hint, indien beschikbaar.</string>
<string name="confirm_log_title">Ongebruikelijk logtype</string>
<string name="confirm_log_message">Je wilt \'%s\' loggen. Weet je het zeker?</string>
</resources>
diff --git a/main/res/values-pl/strings.xml b/main/res/values-pl/strings.xml
index 9c22836..de70b49 100644
--- a/main/res/values-pl/strings.xml
+++ b/main/res/values-pl/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Odwiedzony</string>
<string name="log_tb_drop">Odłożony</string>
<string name="log_tb_changeall">Zmień wszystko</string>
- <string name="log_save">Zapisz</string>
+ <string name="log_save">Zapisz offline</string>
<string name="log_saving">Zapisuję w dzienniku…</string>
<string name="log_saving_and_uploading">Zapisuję w dzienniku i wysyłam zdjęcie…</string>
<string name="log_clear">Wyczyść</string>
<string name="log_post_not_possible">ÅadujÄ™ dziennik…</string>
+ <string name="log_date_future_not_allowed">Wpisy z przyszłą datą nie są dozwolone.</string>
<string name="log_add">Dodaj</string>
+ <string name="log_repeat">Powtórz ostatni wpis</string>
<string name="log_no_rating">Bez oceny</string>
<string name="log_stars_1_description">SÅ‚aba</string>
<string name="log_stars_15_description">Raczej słaba</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Hasło do logu:</string>
<string name="log_hint_log_password">Wpisz hasło do logu</string>
<string name="log_oc_team_comment">Komentarz zespołu OC</string>
+ <string name="log_your_saved_log">Twój zapisany wpis</string>
<string-array name="log_image_scales">
<item>Brak skalowania</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Brak danych do logowania.</string>
<string name="err_login_failed_toast">c:geo nie może zalogować się. c:geo pracuje offline z zapisanymi skrzynkami. Sprawdź ustawienia logowania i połączenie z internetem.</string>
<string name="err_unknown">Nieznany błąd</string>
+ <string name="err_unknown_address">c:geo nie mógł dopasować adresu do istniejącej lokalizacji</string>
<string name="err_comm">Nieznany błąd w komunikacji</string>
<string name="err_missing_auth">Brak nazwy użytkownika i/lub hasła.</string>
<string name="err_wrong">Niepoprawne dane użytkownika</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Nie można pobrać obrazu.</string>
<string name="err_tb_display">c:geo nie może pokazać przedmiotów podróżnych. Czy to naprawdę jest przedmiot podróżny?</string>
<string name="err_tb_details_open">c:geo nie może otworzyć szczegółów przedmiotu podróżnego.</string>
- <string name="err_tb_forgot_saw">c:geo zapomiał, który przedmiot podróżny widziałeś.</string>
<string name="err_tb_find">c:geo nie może znaleźć przedmiotu podróżnego.</string>
<string name="err_tb_find_that">c:geo nie może znaleźć tego przedmiotu podróżnego.</string>
<string name="err_waypoint_cache_unknown">c:geo nie wie, do której skrzynki chcesz dodać punkt nawigacji.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo nie może określić Twojej lokalizacji.</string>
<string name="err_point_no_position_given_title">Informacje wymagane</string>
<string name="err_point_no_position_given">Wypełnij co najmniej szerokość i długość geograficzną lub odległość i namiar. Możesz również wypełnić wszystkie cztery pola.</string>
- <string name="err_point_curr_position_unavailable">c:geo nadal nie zna aktualnych współrzędnych. Proszę chwilę poczekać…</string>
<string name="err_point_bear_and_dist_title">Potrzebujesz pomocy?</string>
<string name="err_point_bear_and_dist">Wypełnij zarówno namiar i odległość. Biorąc kąt od 0 do 360 stopni w stosunku do północy. Odległość z lub bez jednostki.</string>
<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_post_failed">Wygląda na to, że Twój wpis nie został wysłany. Proszę sprawdź na Geocaching.com.</string>
- <string name="err_log_post_failed_ec">Wygląda na to, że Twój wpis nie został wysłany. Proszę sprawdź na Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Wygląda na to, że Twój obraz nie został dodany. Proszę sprawdź na Geocaching.com.</string>
+ <string name="err_log_post_failed">Wygląda na to, że wpis nie został dodany. Proszę sprawdzić to na stronie internetowej skrzynki.</string>
+ <string name="err_logimage_post_failed">Wygląda na to, że zdjęcie nie zostało przesłane. Proszę sprawdzić to na stronie internetowej skrzynki.</string>
<string name="err_search_address_forgot">c:geo zapomniał adresu, którego szukałeś.</string>
<string name="err_parse_lat">c:geo nie może obliczyć szerokości geograficznej.</string>
<string name="err_parse_lon">c:geo nie może obliczyć długości geograficznej.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Sieć</string>
<string name="loc_fused">Połączona</string>
<string name="loc_low_power">Niski pobór energii</string>
+ <string name="loc_home">Koordynaty domowe</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Próba lokalizacji</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Najbliższe</string>
<string name="advanced_search_button">Szukaj</string>
<string name="stored_caches_button">Zapisane</string>
- <string name="any_button">Współrzędne</string>
+ <string name="any_button">Idź do</string>
<string name="unknown_scan">c:geo nie znalazł żadnego GC-kodu w wynikach skanowania.</string>
<string name="caches_no_cache">Brak skrzynek</string>
<string name="caches_more_caches">Więcej skrzynek</string>
@@ -264,15 +266,14 @@
<string name="caches_sort_finds">Ile razy znaleziona</string>
<string name="caches_sort_state">Stan</string>
<string name="caches_sort_storage">Data zapisania w urzÄ…dzeniu</string>
+ <string name="caches_sort_eventdate">Data wydarzenia</string>
<string name="caches_select_mode">Tryb wyboru</string>
<string name="caches_select_mode_exit">Wyjście z trybu wyboru</string>
<string name="caches_select_invert">Odwróć zaznaczenie</string>
<string name="caches_nearby">Najbliższe</string>
<string name="caches_manage">ZarzÄ…dzaj</string>
<string name="caches_remove_all">Usuń wszystkie</string>
- <string name="caches_remove_all_confirm">Czy chcesz usunąć wszystkie %s skrzynek z aktualnej listy?</string>
<string name="caches_remove_selected">Usuń wybrane</string>
- <string name="caches_remove_selected_confirm">Czy chcesz usunąć wybrane %s skrzynek z urządzenia?</string>
<string name="caches_remove_progress">Usuwanie skrzynek</string>
<string name="caches_delete_events">Usuń minione wydarzenia</string>
<string name="caches_refresh_selected">Odśwież wybrane</string>
@@ -292,13 +293,18 @@
<string name="caches_filter_track">Z przedmiotami podróżnymi</string>
<string name="caches_filter_clear">Usuń filtr</string>
<string name="caches_filter_modified">Zmiany współrzędnych</string>
+ <string name="caches_filter_offline_log">Z wpisami offline</string>
<string name="caches_filter_origin">Źródło</string>
<string name="caches_filter_distance">Odległość</string>
<string name="caches_filter_personal_note">Zawiera notatkÄ™</string>
<string name="caches_filter_popularity">Ulubione</string>
<string name="caches_filter_popularity_ratio">Ulubione [%]</string>
+ <string name="caches_filter_personal_data">Z osobistymi informacjami</string>
+ <string name="caches_filter_rating">Z ocenÄ…</string>
+ <string name="caches_filter_own_rating">Z własną oceną</string>
<string name="caches_removing_from_history">Usuwam z Historii…</string>
<string name="caches_clear_offlinelogs">Usuń wpisy offline</string>
+ <string name="caches_clear_offlinelogs_message">Czy chcesz wyczyścić wpisy offline?</string>
<string name="caches_clear_offlinelogs_progress">Usuwanie wpisów offline</string>
<string name="list_menu_create">Utwórz nową listę</string>
<string name="list_menu_drop">Usuń aktualną listę</string>
@@ -321,13 +327,17 @@
<string name="list_not_available">Lista nie jest już dostępna, przechodzę do standardowej listy</string>
<string name="about_version">Wersja</string>
<string name="about_changelog">Zmiany</string>
+ <string name="about_system">System</string>
<string name="about_donate">Podaruj</string>
<string name="about_donation_more">Darowizna dla\nprogramisty</string>
<string name="about_contributors">Współpracownicy</string>
<string name="about_license">Licencja</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Pomoc</string>
+ <string name="about_system_include">Proszę załączyć następujące informacje o systemie podczas przesyłania raportu błędu albo podczas prośby o więcej informacji odnośnie c:geo:</string>
+ <string name="changelog_github">Lista wszystkich zmian</string>
<string name="settings_title_services">Usługi</string>
+ <string name="settings_summary_services">Konfigurowanie informacji o koncie użytkownika i dostęp do usług opcjonalnych.</string>
<string name="settings_title_appearance">WyglÄ…d</string>
<string name="settings_title_cachedetails">Szczegóły skrzynki</string>
<string name="settings_title_offlinedata">Dane offline</string>
@@ -371,6 +381,9 @@
<string name="settings_activate_oc_uk">Aktywuj</string>
<string name="init_oc_uk_description">Autoryzuj c:geo z opencaching.org.uk aby wyszukiwać skrzynki i mieć dostęp/filtrować znalezione skrzynki.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Aby móc oceniać skrzynki, należy postępować zgodnie z instrukcjami zawartymi na GCVote.com i podać swoje hasło do serwisu tutaj.</string>
+ <string name="err_gcvote_send_rating">Błąd podczas wysyłania oceny, sprawdź swoje hasło do GCVote w ustawieniach albo wyczyść je.</string>
+ <string name="gcvote_sent">Głos pomyślnie oddany</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktywuj</string>
<string name="init_username">Nazwa użytkownika</string>
@@ -441,6 +454,8 @@
<string name="init_backup_success">Baza danych c:geo została pomyślnie skopiowana do pliku</string>
<string name="init_backup_failed">Tworzenie kopii zapasowej bazy danych c:geo nie powiodło się.</string>
<string name="init_backup_unnecessary">Baza danych jest pusta, tworzenie kopii zapasowej nie jest potrzebne.</string>
+ <string name="backup_confirm_overwrite">Czy chcesz nadpisać aktualną kopię zapasową z %s?</string>
+ <string name="restore_confirm_overwrite">Czy chcesz nadpisać %s w twoim urządzeniu kopią zapasową?</string>
<string name="init_restore_success">Odzyskiwanie zakończone.</string>
<string name="init_restore_failed">Odzyskiwanie nie powiodło się.</string>
<string name="init_restore_running">Odzyskiwanie bazy skrzynek…</string>
@@ -601,6 +616,7 @@
</plurals>
<string name="cache_waypoints_add">Dodaj punkt nawigacji</string>
<string name="cache_hint">Wskazówka</string>
+ <string name="cache_hint_not_available">Brak podpowiedzi</string>
<string name="cache_logs">Dziennik</string>
<string name="cache_logs_friends_and_own">Wpisy przyjaciół/własne</string>
<string name="cache_dialog_loading_details">ÅadujÄ™ szczegóły skrzynki…</string>
@@ -643,6 +659,7 @@
<string name="cache_menu_visit_offline">Wpisz wizytÄ™ offline</string>
<string name="cache_menu_spoilers">Zdjęcia spoiler</string>
<string name="cache_menu_around">Skrzynki w pobliżu</string>
+ <string name="around">W pobliżu %s</string>
<string name="cache_menu_event">Dodaj do kalendarza</string>
<string name="cache_menu_details">Szczegóły</string>
<string name="cache_menu_refresh">Odśwież</string>
@@ -652,6 +669,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Zegarek Pebble</string>
+ <string name="cache_menu_vote">GÅ‚osuj</string>
+ <string name="cache_menu_checker">Otwórz Geochecker\'a</string>
+ <string name="cache_menu_ignore">Ignoruj skrzynkÄ™</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Zapamiętany wpis</string>
<string name="cache_status_found">Znaleziona</string>
@@ -737,6 +757,7 @@
<string name="waypoint_note">Notatka</string>
<string name="waypoint_visited">Odwiedzony</string>
<string name="waypoint_save">Zapisz</string>
+ <string name="waypoint_cancel_edit">Anuluj</string>
<string name="waypoint_loading">ÅadujÄ™ punkt nawigacji…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Współrzędne skrzynki bez zmian</string>
<string name="waypoint_set_as_cache_coords">Ustaw jako współrzędne skrzynki w c:geo</string>
@@ -761,6 +782,8 @@
<string name="search_clear_history">Usuń historię</string>
<string name="search_history_cleared">Historia usunięta</string>
<string name="waypoint_coordinate_formats_plain">zwykłe</string>
+ <string name="from_clipboard">Ze schowka</string>
+ <string name="copy_to_clipboard">Kopiuj do schowka</string>
<string name="visit_tweet">Wyślij informację do Twitter</string>
<string name="map_map">Mapa</string>
<string name="map_live">Mapa online</string>
@@ -865,7 +888,7 @@
<string name="helper_contacts_description">Umożliwia Tobie otwarcie kontaktu (z Twojej książki adresowej) bezpośrednio z wpisu do dziennika, więc możesz łatwiej poprosić przyjaciół o pomoc.</string>
<string name="helper_sendtocgeo_description">Wyślij do c:geo jest rozszerzeniem do przeglądarki <strong>na komputer</strong>. Podczas przeglądania Geocaching.com pozwala na wysłanie skrzynek bezpośrednio do telefonu, za pomocą jednego przycisku w przeglądarce.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Bardzo dobra aplikacja do oglądania map online, która pozwala na pobieranie ich bezpośrednio do trybu offline (tylko mapy rastrowe). Pozwala także na zapisywanie ścieżek, obsługę POI oraz ma wiele innych przydatnych funkcji.</string>
+ <string name="helper_locus_description">Program do nawigacji w terenie dla Twojego telefonu lub tabletu. Przeglądaj mapy topograficzne offiline, śledź swoją trasę, poluj na skrzynki geocache, używaj nawigacji głosowej i wiele więcej.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Można wywołać radar bezpośrednio z aplikacji c:geo. Oferuje on również wiele informacji związanych z GPS.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1117,13 +1140,15 @@
<string name="attribute_offset_cache_no">Nie jest to skrzynka Offset</string>
<string name="quote">Aby uczynić geocaching prostszym, a użytkowników bardziej leniwymi.</string>
<string name="powered_by">carnero</string>
- <string name="support">Wsparcie: <a href="">support@cgeo.org</a></string>
- <string name="website">Website: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo strona</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo w Google Play</a></string>
+ <string name="support_title">Pomoc</string>
+ <string name="website_title">Adres strony</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">c:geo na fb</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo w Google Play</a></string>
<string name="about_twitter">Czy chczesz aby <b>c:geo</b> publikował nowy status na Twitter za każdym razem kiedy znajdziesz skrzynkę?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Dostępna nowa wersja.\nKliknij aby zainstalować.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Dostępna nowa codzienna wersja.\nKliknij aby zainstalować.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Dostępny nowy kandydat na nową wersję.\nKliknij aby zainstalować.</string>
@@ -1174,7 +1199,7 @@
<item quantity="few">%s ulubione</item>
<item quantity="other">%s ulubionych</item>
</plurals>
- <string name="percent_favorite_points">%\ ulubionych</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% ulubionych</string>
<string name="cgeo_shortcut">skrót do c:geo</string>
<string name="create_shortcut">Utwórz skrót</string>
<string name="send">Wyślij</string>
@@ -1184,6 +1209,8 @@
<string name="showcase_main_text">c:geo umieszcza teraz opcje menu w pasku tytułowym jak inne współczesne programy. Niektóre opcje są schowane za kropkowanym symbolem. Naciśnij dłużej przycisk by zobaczyć opis.</string>
<string name="showcase_cachelist_title">Przełączanie list</string>
<string name="showcase_cachelist_text">Możesz przełączać między listami skrzynek klikając tytuł listy.</string>
+ <string name="showcase_compass_hint_title">Podpowiedź</string>
+ <string name="showcase_compass_hint_text">Ten nowy element menu może Ci pomóc przy szukaniu skrzynki - pokazuje podpowiedź, o ile jest dostępna.</string>
<string name="confirm_log_title">Niezwykły typ wpisu</string>
<string name="confirm_log_message">Chcesz wpisać \'%s\'. Czy jesteś pewien?</string>
</resources>
diff --git a/main/res/values-pt/strings.xml b/main/res/values-pt/strings.xml
index 6194cce..ea75db1 100644
--- a/main/res/values-pt/strings.xml
+++ b/main/res/values-pt/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Visitei</string>
<string name="log_tb_drop">Deixei aqui</string>
<string name="log_tb_changeall">Alterar todos</string>
- <string name="log_save">Gravar</string>
+ <string name="log_save">Guardar offline</string>
<string name="log_saving">A gravar o registo…</string>
<string name="log_saving_and_uploading">A enviar o registo e a imagem…</string>
<string name="log_clear">Limpar</string>
<string name="log_post_not_possible">A carregar página de registo…</string>
+ <string name="log_date_future_not_allowed">Registos com datas futuras não são permitidos.</string>
<string name="log_add">Adicionar</string>
+ <string name="log_repeat">Repetir último registo</string>
<string name="log_no_rating">Não votar</string>
<string name="log_stars_1_description">Terrível</string>
<string name="log_stars_15_description">Muito má</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Password do registo:</string>
<string name="log_hint_log_password">Inserira a password do registo</string>
<string name="log_oc_team_comment">Comentário da OC Team</string>
+ <string name="log_your_saved_log">O seu registo gravado</string>
<string-array name="log_image_scales">
<item>Não dimensionar</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Informação de login não gravada</string>
<string name="err_login_failed_toast">O c:geo não consegue fazer login. O c:geo funciona offline com as caches Arquivadas. Verifique as definições de login ou habilite a ligação de dados.</string>
<string name="err_unknown">Erro desconhecido</string>
+ <string name="err_unknown_address">c:geo não conseguiu mapear a morada para uma localização existente</string>
<string name="err_comm">Erro de comunicação desconhecido</string>
<string name="err_missing_auth">Sem nome de utilizador/password definidos.</string>
<string name="err_wrong">Dados de login inválidos</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Aquisição de uma imagem falhou.</string>
<string name="err_tb_display">O c:geo não consegue mostrar o trackable pretendido. É mesmo um trackable?</string>
<string name="err_tb_details_open">O c:geo não consegue abrir os detalhes do trackable.</string>
- <string name="err_tb_forgot_saw">O c:geo esqueceu o trackable que viu.</string>
<string name="err_tb_find">O c:geo não encontra o trackable</string>
<string name="err_tb_find_that">O c:geo não encontra esse trackable.</string>
<string name="err_waypoint_cache_unknown">O c:geo não sabe a que cache quer adicionar o ponto de referência.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">O c:geo não conseguiu reconhecer a sua localização.</string>
<string name="err_point_no_position_given_title">Informação requerida</string>
<string name="err_point_no_position_given">Preencha pelo menos a latitude, a longitude, a distância ou a direcção. Também pode preencher os quatro campos.</string>
- <string name="err_point_curr_position_unavailable">O c:geo ainda não possui as coordenadas actuais. Por favor, aguarde um instante…</string>
<string name="err_point_bear_and_dist_title">Precisa de ajuda?</string>
<string name="err_point_bear_and_dist">Preencha a direcção e a distância. A direcção é o ângulo de 0 a 360 graus relativo ao norte. A distância pode ser introduzida com ou sem unidades.</string>
<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_post_failed">O c:geo falhou a publicação do registo.</string>
- <string name="err_log_post_failed_ec">Parece que o seu log não foi publicado. Por favor verifique-o em Extremcaching.com.</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_log_post_failed">Parece que o seu registo não foi publicado. Por favor, verifique a página Web original da cache.</string>
+ <string name="err_logimage_post_failed">Parece que a imagem do seu registo não foi enviada. Por favor, verifique a página Web original da cache.</string>
<string name="err_search_address_forgot">O c:geo esqueceu o endereço que procura.</string>
<string name="err_parse_lat">O c:geo não consegue analisar a latitue.</string>
<string name="err_parse_lon">O c:geo não consegue analisar a logitude.</string>
@@ -209,6 +210,9 @@
<string name="info_cache_saved">A cache foi armazenada localmente</string>
<string name="loc_last">Último conhecido</string>
<string name="loc_net">Rede</string>
+ <string name="loc_fused">Combinados</string>
+ <string name="loc_low_power">Bateria fraca</string>
+ <string name="loc_home">Coordenadas de casa</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">A tentar localizar</string>
@@ -227,7 +231,7 @@
<string name="caches_nearby_button">Por perto</string>
<string name="advanced_search_button">Pesquisar</string>
<string name="stored_caches_button">Arquivo</string>
- <string name="any_button">Destino</string>
+ <string name="any_button">Ir para</string>
<string name="unknown_scan">Sem resultados do scan.</string>
<string name="caches_no_cache">Nenhuma cache</string>
<string name="caches_more_caches">Mais caches</string>
@@ -261,15 +265,18 @@
<string name="caches_sort_finds">Encontradas</string>
<string name="caches_sort_state">Estado</string>
<string name="caches_sort_storage">Data gravada no dispositivo</string>
+ <string name="caches_sort_eventdate">Data do evento</string>
<string name="caches_select_mode">Modo de selecção</string>
<string name="caches_select_mode_exit">Sair do modo de selecção</string>
<string name="caches_select_invert">Inverter selecção</string>
<string name="caches_nearby">Por perto</string>
<string name="caches_manage">Gerir</string>
<string name="caches_remove_all">Remover todas</string>
- <string name="caches_remove_all_confirm">Quer remover todas as %s caches da lista atual?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Quer remover esta cache da lista actual?</item>
+ <item quantity="other">Quer remover todas as %d caches da lista actual?</item>
+ </plurals>
<string name="caches_remove_selected">Remover selecionadas</string>
- <string name="caches_remove_selected_confirm">Quer remover as %s caches selecionadas do seu dispositivo?</string>
<string name="caches_remove_progress">A remover caches</string>
<string name="caches_delete_events">Eliminar eventos passados</string>
<string name="caches_refresh_selected">Actualizar seleccionada</string>
@@ -289,13 +296,18 @@
<string name="caches_filter_track">Com trackables</string>
<string name="caches_filter_clear">Limpar filtros</string>
<string name="caches_filter_modified">Com as coordenadas modificadas</string>
+ <string name="caches_filter_offline_log">Com registo offline</string>
<string name="caches_filter_origin">Origem</string>
<string name="caches_filter_distance">Distância</string>
<string name="caches_filter_personal_note">Com nota pessoal</string>
<string name="caches_filter_popularity">Favoritos</string>
<string name="caches_filter_popularity_ratio">Favoritos [%]</string>
+ <string name="caches_filter_personal_data">Com notas pessoais</string>
+ <string name="caches_filter_rating">Com classificação</string>
+ <string name="caches_filter_own_rating">Com própria classificação</string>
<string name="caches_removing_from_history">A remover do histórico…</string>
<string name="caches_clear_offlinelogs">Limpar registos offline</string>
+ <string name="caches_clear_offlinelogs_message">Quer apagar os registos offline?</string>
<string name="caches_clear_offlinelogs_progress">A limpar registos offline</string>
<string name="list_menu_create">Criar nova lista</string>
<string name="list_menu_drop">Apagar lista actual</string>
@@ -318,13 +330,17 @@
<string name="list_not_available">A lista já não se encontra disponível, alterando para lista padrão</string>
<string name="about_version">Versão</string>
<string name="about_changelog">Changelog</string>
+ <string name="about_system">Sistema</string>
<string name="about_donate">Doar</string>
<string name="about_donation_more">Doar\ndesenvolvimento</string>
<string name="about_contributors">Contribuidores</string>
<string name="about_license">Licença</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Ajuda</string>
+ <string name="about_system_include">Por favor inclua as seguintes informações de sistema ao enviar um relatório de bug ou ao pedir mais informações sobre c:geo:</string>
+ <string name="changelog_github">Lista de todas as alterações</string>
<string name="settings_title_services">Serviços</string>
+ <string name="settings_summary_services">Configure a informação da conta de utilizador e o acesso a serviços opcionais.</string>
<string name="settings_title_appearance">Aparência</string>
<string name="settings_title_cachedetails">Detalhos da Cache</string>
<string name="settings_title_offlinedata">Dados Offline</string>
@@ -371,6 +387,9 @@
<string name="settings_activate_oc_uk">Ativar</string>
<string name="init_oc_uk_description">Autorizar o c:geo em opencaching.org.uk para que pesquise por caches e aceder/filtrar as suas caches encontradas.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Para poder classificar uma cache, tem que seguir as instruções em GCVote.com e digitar a sua senha GCVote aqui.</string>
+ <string name="err_gcvote_send_rating">Erro ao enviar a classificação, verifique a senha do GCVote nas configurações ou limpe a mesma.</string>
+ <string name="gcvote_sent">Votação enviada com sucesso</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activar</string>
<string name="init_username">Nome de utilizador</string>
@@ -441,6 +460,8 @@
<string name="init_backup_success">A base de dados do c:geo foi copiada com sucesso</string>
<string name="init_backup_failed">O backup da base de dados do c:geo falhou.</string>
<string name="init_backup_unnecessary">Base de dados vazia, não é necessário um backup.</string>
+ <string name="backup_confirm_overwrite">Quer substituir o backup existente de %s?</string>
+ <string name="restore_confirm_overwrite">Quer substituir %s no seu dispositivo com o backup?</string>
<string name="init_restore_success">Restauro concluído.</string>
<string name="init_restore_failed">O restauro falhou.</string>
<string name="init_restore_running">A restaurar a base de dados de caches…</string>
@@ -489,9 +510,18 @@
<string name="init_maintenance">Manutenção</string>
<string name="init_maintenance_directories_note">c:geo armazena imagens, registo de imagens e outros ficheiros relacionados com uma cache numa pasta separada. Nalguns casos (como ao importar/exportar a base de dados) esta pasta pode conter ficheiros desatualizados, que podem ser apagados aqui.</string>
<string name="init_maintenance_directories">Apagar ficheiros orfãos</string>
+ <string name="init_location">Geolocalização</string>
+ <string name="init_location_note">Em dispositivos equipados com serviços Google Play, o c:geo pode automaticamente usar um melhor fornecedor de geolocalização. No entanto, isso impede o uso de um receptor GPS BlueTooth externo.</string>
+ <string name="init_location_googleplayservices">Utilizar serviços Google Play</string>
+ <string name="init_low_power">Modo de baixo consumo de energia</string>
+ <string name="init_low_power_note">O modo de baixo consumo de energia evita usar o GPS e o giroscópio quando não é necessária uma localização muito precisa, à custa de tempos de fixação mais longos.</string>
+ <string name="init_low_power_mode">Ativar modo de baixo consumo de energia</string>
<string name="init_create_memory_dump">criar dump de memória</string>
<string name="init_memory_dump">dump de memória</string>
<string name="init_memory_dumped">dump de memória em %s</string>
+ <string name="init_hardware_acceleration_title">Renderização acelerada por hardware</string>
+ <string name="init_hardware_acceleration_note">Aceleração por hardware processa elementos gráficos mais rapidamente no ecrã. No entanto, em alguns dispositivos o sistema operativo Android contém erros e algum texto pode aparecer desfocado (nomeadamente caracteres em negrito). Desactive a aceleração por hardware se isso lhe acontecer.</string>
+ <string name="init_hardware_acceleration">Activar renderização acelerada por hardware</string>
<string name="settings_open_website">Abrir o website</string>
<string name="settings_settings">Definições</string>
<string name="settings_information">Informações</string>
@@ -590,6 +620,7 @@
</plurals>
<string name="cache_waypoints_add">Adicionar ponto de referência</string>
<string name="cache_hint">Pista</string>
+ <string name="cache_hint_not_available">Nenhuma pista disponível</string>
<string name="cache_logs">Logbook</string>
<string name="cache_logs_friends_and_own">Registos de amigos/próprios</string>
<string name="cache_dialog_loading_details">A carregar os detalhes da cache…</string>
@@ -629,9 +660,10 @@
<string name="cache_menu_streetview">Vista de rua</string>
<string name="cache_menu_browser">Abrir no browser</string>
<string name="cache_menu_visit">Registar visita</string>
- <string name="cache_menu_visit_offline">Registar visita offline</string>
+ <string name="cache_menu_visit_offline">Registo offline rápido</string>
<string name="cache_menu_spoilers">Imagens spoiler</string>
<string name="cache_menu_around">Caches próximas</string>
+ <string name="around">Perto de %s</string>
<string name="cache_menu_event">Adicionar ao calendário</string>
<string name="cache_menu_details">Detalhes</string>
<string name="cache_menu_refresh">Actualizar</string>
@@ -641,6 +673,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Seixo</string>
+ <string name="cache_menu_vote">Voto</string>
+ <string name="cache_menu_checker">Abrir Geochecker</string>
+ <string name="cache_menu_ignore">Ignorar a cache</string>
<string name="cache_status">Estado</string>
<string name="cache_status_offline_log">Registo gravado</string>
<string name="cache_status_found">Encontrada</string>
@@ -726,6 +761,7 @@
<string name="waypoint_note">Nota</string>
<string name="waypoint_visited">Visitado</string>
<string name="waypoint_save">Gravar</string>
+ <string name="waypoint_cancel_edit">Cancelar</string>
<string name="waypoint_loading">A carregar ponto de referência…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Nenhuma mudança às coordenadas da cache</string>
<string name="waypoint_set_as_cache_coords">Definir como coordenadas da cache no c:geo</string>
@@ -750,6 +786,8 @@
<string name="search_clear_history">Limpar histórico</string>
<string name="search_history_cleared">Histórico limpo</string>
<string name="waypoint_coordinate_formats_plain">Plano</string>
+ <string name="from_clipboard">Da área de transferência</string>
+ <string name="copy_to_clipboard">Copiar para área de transferência</string>
<string name="visit_tweet">Publicar esta descoberta no Twitter</string>
<string name="map_map">Mapa</string>
<string name="map_live">Mapa ao vivo</string>
@@ -854,7 +892,7 @@
<string name="helper_contacts_description">Permite abrir um contacto (da sua agenda telefónica) directamente a partir de um log. Assim será mais fácil de pedir ajuda aos seus amigos.</string>
<string name="helper_sendtocgeo_description">Send to c:geo é uma extensão do navegador <strong>para o seu PC</strong>. Ao navegar geocaching.com, você pode enviar as caches directamente para seu smartphone com o clique de um botão no navegador.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Aplicação simples e útil, que mostra mapas online e permite transferi-los directamente para o modo offline (apenas mapas raster). Também suporta a gravação de caminhos, gestão de PDI e muitas outras funções úteis.</string>
+ <string name="helper_locus_description">Aplicação de navegação ao ar livre para o seu telefone ou tablet. Veja mapas topográficos offline, registe a sua rota, procure geocaches, use um guia de voz e muito mais.</string>
<string name="helper_gpsstatus_title">Estado do GPS</string>
<string name="helper_gpsstatus_description">Pode usar o radar a partir desta aplicação. Também fornece muitas outras informações relacionadas com o GPS.</string>
<string name="helper_bluetoothgps_title">GPS por bluetooth</string>
@@ -1106,13 +1144,15 @@
<string name="attribute_offset_cache_no">Cache sem offset de translação</string>
<string name="quote">Para tornar o geocaching mais fácil, para tornar os utilizadores mais preguiçosos.</string>
<string name="powered_by">carnero</string>
- <string name="support">Suporte: <a href="">support@cgeo.org</a></string>
- <string name="website">Site na internet: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">página do c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo no Google Play</a></string>
+ <string name="support_title">Suporte</string>
+ <string name="website_title">Página Web</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">Página do c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo no Google Play</a></string>
<string name="about_twitter">O <b>c:geo</b> deve publicar no Twitter de cada vez que uma cache foi registrada?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">Perguntas Frequentes</string>
<string name="status_new_release" tools:ignore="UnusedResources">Nova versão disponível.\nClique para instalar.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nova \'nightly build\' disponível.\nClique para instalar.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Nova \'release candidate\' disponível .\nClique para instalar.</string>
@@ -1123,6 +1163,8 @@
<string name="tts_service">Bússola que fala</string>
<string name="tts_start">Comece a falar</string>
<string name="tts_stop">Páre de falar</string>
+ <string name="tts_started">Iniciou fala</string>
+ <string name="tts_stopped">Parou fala</string>
<string name="err_tts_lang_not_supported">A linguagem corrente não é suportada pelo texto em fala.</string>
<string name="tts_one_kilometer">um quilômetro</string>
<plurals name="tts_kilometers">
@@ -1155,8 +1197,17 @@
<item quantity="one">%s favorito</item>
<item quantity="other">%s favoritos</item>
</plurals>
- <string name="percent_favorite_points">%\ favoritos</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoritos</string>
<string name="cgeo_shortcut">Atalho c:geo</string>
<string name="create_shortcut">Criar atalho</string>
<string name="send">Enviar</string>
+ <string name="showcase_logcache_title">Enviando o registo</string>
+ <string name="showcase_logcache_text">Lembre-se, muitos comandos estão agora na barra de título. Lá encontra o botão para enviar o registo terminado.</string>
+ <string name="showcase_main_title">Novos menus</string>
+ <string name="showcase_main_text">c:Geo coloca agora itens de menu na barra de título como outras aplicações modernas. Alguns itens estão escondidos atrás do símbolo dos pontos. Prima longamente um botão para ver sua descrição.</string>
+ <string name="showcase_cachelist_title">A trocar de listas</string>
+ <string name="showcase_cachelist_text">Pode alternar entre listas de caches clicando no título da lista.</string>
+ <string name="showcase_compass_hint_title">Mostrar a dica</string>
+ <string name="confirm_log_title">Tipo de registo invulgar</string>
+ <string name="confirm_log_message">Quer fazer o registo \'%s\'. Tem a certeza?</string>
</resources>
diff --git a/main/res/values-ro/strings.xml b/main/res/values-ro/strings.xml
index 857598f..6385c7a 100644
--- a/main/res/values-ro/strings.xml
+++ b/main/res/values-ro/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Vizitat</string>
<string name="log_tb_drop">Lăsat</string>
<string name="log_tb_changeall">Schimbă toate</string>
- <string name="log_save">Salvează</string>
+ <string name="log_save">Salvează local</string>
<string name="log_saving">Trimitere jurnal…</string>
<string name="log_saving_and_uploading">Trimitre jurnal şi încarcare poze…</string>
<string name="log_clear">Åžterge</string>
<string name="log_post_not_possible">Încărcare pagină însemnări…</string>
+ <string name="log_date_future_not_allowed">Nu sunt permise însemnări datate în viitor.</string>
<string name="log_add">Adaugă</string>
+ <string name="log_repeat">Repetă ultima însemnare</string>
<string name="log_no_rating">Fără voturi</string>
<string name="log_stars_1_description">Foarte slabă</string>
<string name="log_stars_15_description">Slabă</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Parolă:</string>
<string name="log_hint_log_password">Introdu parola pentru jurnal</string>
<string name="log_oc_team_comment">Comentariu din partea echipei OC</string>
+ <string name="log_your_saved_log">Însemnare salvată</string>
<string-array name="log_image_scales">
<item>Fără redimensionare</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Nu există informaţii de autorizare</string>
<string name="err_login_failed_toast">c:geo nu se poate conecta. c:geo va funcţiona deconectat cu cutiile salvate local. Verifică informaţiile de autentificare sau activează conexiunea la internet.</string>
<string name="err_unknown">Eroare necunoscută</string>
+ <string name="err_unknown_address">c:geo nu a putut găsi coordonate pentru această adresă</string>
<string name="err_comm">Eroare necunoscută de comunicaţie</string>
<string name="err_missing_auth">Nu a fost dat numele de utilizator sau parola.</string>
<string name="err_wrong">Informaţii de autentificare incorecte</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Imaginea nu a putut fi obţinută.</string>
<string name="err_tb_display">c:geo nu poate afişa obiectul călător solicitat. Chiar este un obiect călător?</string>
<string name="err_tb_details_open">c:geo nu poate accesa detaliile obiectului călător.</string>
- <string name="err_tb_forgot_saw">c:geo a uitat obiectul călător pe care l-ai văzut.</string>
<string name="err_tb_find">c:geo nu poate găsi obiectul călător</string>
<string name="err_tb_find_that">c:geo nu poate găsi acest obiect călător.</string>
<string name="err_waypoint_cache_unknown">c:geo nu ÅŸtie pentru ce cutie vrei sa adaugi un punct.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo nu poate determina unde te afli.</string>
<string name="err_point_no_position_given_title">Informaţii necesare</string>
<string name="err_point_no_position_given">Introdu cel puţin latitudine şi longitudine sau distanţă şi azimut. Se pot completa şi toate cele patru câmpuri.</string>
- <string name="err_point_curr_position_unavailable">c:geo incă tot nu a obţinut coordonatele poziţiei curente. Te rog, mai aşteaptă puţin…</string>
<string name="err_point_bear_and_dist_title">Ai nevoie de ajutor?</string>
<string name="err_point_bear_and_dist">Completează şi azimutul şi distanţa. Azimutul este unghiul de la 0 la 360 faţă de nord. Distanţa nu necesită unităţi.</string>
<string name="err_log_load_data">c:geo nu poate încărca informaţiile necesare pentru a posta o însemnare.</string>
<string name="err_log_load_data_again">c:geo nu poate încărca informaţiile necesare pentru a posta o însemnare. Te rog încearcă din nou.</string>
<string name="err_log_load_data_still">c:geo încă încarcă informaţiale necesare pentru a posta o însemnare. Te rog mai aşteaptă.</string>
- <string name="err_log_post_failed">Se pare că însemnarea nu a fost postată. Verifică pe Geocaching.com.</string>
- <string name="err_log_post_failed_ec">Se pare că însemnarea nu a fost postată. Verifică pe Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Se pare că imaginea ataşată însemnării nu a fost postată. Verifică pe Geocaching.com.</string>
+ <string name="err_log_post_failed">Se pare că însemnarea ta nu a fost postată. Te rog verifică pe site-ul pe care se află publicată această geocutie.</string>
+ <string name="err_logimage_post_failed">Se pare că imaginea pe care încercai să o trimiţi odată cu însemnarea nu a putut fi încărcată. Te rog verifică însemnarea în jurnalul geocutiei pe site-ul unde este publicată.</string>
<string name="err_search_address_forgot">c:geo a uitat adresa pe care o căutai.</string>
<string name="err_parse_lat">c:geo nu înţelege latitudinea.</string>
<string name="err_parse_lon">c:geo nu înţelege longitudinea.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Reţea</string>
<string name="loc_fused">Combinat</string>
<string name="loc_low_power">Mod economic</string>
+ <string name="loc_home">Coordonatele de acasă</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Încerc să determin poziţia</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">ÃŽn apropiere</string>
<string name="advanced_search_button">Caută</string>
<string name="stored_caches_button">Stocate</string>
- <string name="any_button">Orice destinaţie</string>
+ <string name="any_button">Coordonate</string>
<string name="unknown_scan">Nu a fost găsit nici un geocod în rezultatul scanării.</string>
<string name="caches_no_cache">Nici o cutie</string>
<string name="caches_more_caches">Încarcă mai multe cutii</string>
@@ -256,7 +258,7 @@
<string name="caches_sort_favorites_ratio">Favorite [%]</string>
<string name="caches_sort_name">Nume</string>
<string name="caches_sort_geocode">Geo Cod</string>
- <string name="caches_sort_rating">Rating</string>
+ <string name="caches_sort_rating">Voturi</string>
<string name="caches_sort_vote">Vot (propriul vot)</string>
<string name="caches_sort_inventory">Total inventar</string>
<string name="caches_sort_date_hidden">Data ascunderii</string>
@@ -264,15 +266,24 @@
<string name="caches_sort_finds">Găsite</string>
<string name="caches_sort_state">Stare</string>
<string name="caches_sort_storage">Data salvării pe acest dispozitiv</string>
+ <string name="caches_sort_eventdate">Data evenimentului</string>
<string name="caches_select_mode">Mod selecţie</string>
<string name="caches_select_mode_exit">Renunţă la modul selecţie</string>
<string name="caches_select_invert">Inversează selecţia</string>
<string name="caches_nearby">ÃŽn apropiere</string>
<string name="caches_manage">Gestionează</string>
<string name="caches_remove_all">Șterge toate</string>
- <string name="caches_remove_all_confirm">Vrei să ştergi toate cele %s cutii din lista curenă?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Vrei să ştergi această geocutie din lista curentă?</item>
+ <item quantity="few">Vrei să ştergi toate cele %d geocutii din lista curentă?</item>
+ <item quantity="other">Vrei să ştergi toate cele %d geocutii din lista curentă?</item>
+ </plurals>
<string name="caches_remove_selected">Åžterge geocutiile selectate</string>
- <string name="caches_remove_selected_confirm">Vrei să ştergi cele %s cutii selectate din dispozitiv?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Vrei să ştergi această geocutie din dispozitivul tău?</item>
+ <item quantity="few">Vrei să ştergi cele %d geocutii selectate din dispozitivul tău?</item>
+ <item quantity="other">Vrei să ştergi cele %d geocutii selectate din dispozitivul tău?</item>
+ </plurals>
<string name="caches_remove_progress">Åžtergere geocutii</string>
<string name="caches_delete_events">Åžterge evenimentele trecute</string>
<string name="caches_refresh_selected">Reîncarcă cutiile selectate</string>
@@ -292,13 +303,18 @@
<string name="caches_filter_track">Conţine obiecte călătoare</string>
<string name="caches_filter_clear">Anulează filtrele</string>
<string name="caches_filter_modified">Cu coordonate modificate</string>
+ <string name="caches_filter_offline_log">Cu însemnări salvate</string>
<string name="caches_filter_origin">Origine</string>
<string name="caches_filter_distance">Distanţă</string>
<string name="caches_filter_personal_note">Scrie notă personală</string>
<string name="caches_filter_popularity">Favorite</string>
<string name="caches_filter_popularity_ratio">Favorite [%]</string>
+ <string name="caches_filter_personal_data">Cu date personalizate</string>
+ <string name="caches_filter_rating">Cu voturi</string>
+ <string name="caches_filter_own_rating">Cu votul tău</string>
<string name="caches_removing_from_history">Şterge din istoric…</string>
<string name="caches_clear_offlinelogs">Şterge însemnări stocate local</string>
+ <string name="caches_clear_offlinelogs_message">Vrei să ştergi însemnările stocate local?</string>
<string name="caches_clear_offlinelogs_progress">Ştergere însemnări stocate local</string>
<string name="list_menu_create">Crează listă nouă</string>
<string name="list_menu_drop">Şterge lista curentă</string>
@@ -321,13 +337,17 @@
<string name="list_not_available">Lista nu mai există, revenire la lista standard</string>
<string name="about_version">Versiune</string>
<string name="about_changelog">Istoric modificări</string>
+ <string name="about_system">Sistem</string>
<string name="about_donate">Donează</string>
<string name="about_donation_more">Donează pentru\ndezvoltare</string>
<string name="about_contributors">Contribuitori</string>
<string name="about_license">Licenţă</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Ajutor</string>
+ <string name="about_system_include">Te rog include urmatoarele informaţii despre sistem atunci când trimiţi o sesizare sau întrebi despre c:geo:</string>
+ <string name="changelog_github">Afişează toate modificările</string>
<string name="settings_title_services">Servicii internet</string>
+ <string name="settings_summary_services">Configurează-ţi contul şi accesul la servicii opţionale.</string>
<string name="settings_title_appearance">Aspect vizual</string>
<string name="settings_title_cachedetails">Detalii cutie</string>
<string name="settings_title_offlinedata">Informaţii păstrate locale</string>
@@ -374,6 +394,9 @@
<string name="settings_activate_oc_uk">Activează</string>
<string name="init_oc_uk_description">Autorizează c:geo cu opencaching.org.uk pentru a putea căuta geocutii şi a putea accesa/filtra pe cele găsite de tine.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Pentru a putea evalua o geocutie, trebuie să urmezi instrucţiunile de la GCVote.com şi să introduci aici parola GCVote.</string>
+ <string name="err_gcvote_send_rating">Eroare la trimiterea evaluării, verifică-ţi parola GCVote din configuraţie sau şterge această parolă.</string>
+ <string name="gcvote_sent">Votul a fost trimis</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activează</string>
<string name="init_username">Utilizator</string>
@@ -444,6 +467,8 @@
<string name="init_backup_success">Baza de date a c:geo a fost copiată aici:</string>
<string name="init_backup_failed">Salvarea bazei de date a eÅŸuat.</string>
<string name="init_backup_unnecessary">Baza de date este goală. Nu este necesară o salvare de siguranţă.</string>
+ <string name="backup_confirm_overwrite">Vrei să scrii peste salvarea de siguranţă din %s?</string>
+ <string name="restore_confirm_overwrite">Vrei să înlocuieşti %s din dispozitivul tău cu cele din salvarea de siguranţă?</string>
<string name="init_restore_success">Restaurare finalizată.</string>
<string name="init_restore_failed">Restaurarea nu a reușit.</string>
<string name="init_restore_running">Restaurare bază de date cutii…</string>
@@ -596,6 +621,7 @@
<string name="cache_waypoints">Puncte</string>
<string name="cache_waypoints_add">Adaugă punct</string>
<string name="cache_hint">Indiciu</string>
+ <string name="cache_hint_not_available">Fără indiciu</string>
<string name="cache_logs">Jurnal</string>
<string name="cache_logs_friends_and_own">Însemnări proprii/de la prieteni</string>
<string name="cache_dialog_loading_details">Încărcare detaliile cutiei…</string>
@@ -635,9 +661,10 @@
<string name="cache_menu_streetview">Vedere stradală</string>
<string name="cache_menu_browser">Afişează în browser</string>
<string name="cache_menu_visit">Jurnal</string>
- <string name="cache_menu_visit_offline">Jurnal salvat</string>
+ <string name="cache_menu_visit_offline">Însemnare locală cu un singur clic</string>
<string name="cache_menu_spoilers">Imagini (indicii?)</string>
<string name="cache_menu_around">Cutii din împrejurimi</string>
+ <string name="around">Aproximativ %s</string>
<string name="cache_menu_event">Adaugă la calendar</string>
<string name="cache_menu_details">Detalii</string>
<string name="cache_menu_refresh">Împrospătează</string>
@@ -647,6 +674,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Ceas \"Pebble\"</string>
+ <string name="cache_menu_vote">Votează</string>
+ <string name="cache_menu_checker">Accesează Geochecker</string>
+ <string name="cache_menu_ignore">Ignoră geocutia</string>
<string name="cache_status">Stare</string>
<string name="cache_status_offline_log">Jurnal salvat</string>
<string name="cache_status_found">Găsit</string>
@@ -732,6 +762,7 @@
<string name="waypoint_note">Notă</string>
<string name="waypoint_visited">Vizitat</string>
<string name="waypoint_save">Salvează</string>
+ <string name="waypoint_cancel_edit">Anulează</string>
<string name="waypoint_loading">Încărcare punct…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Nu se modifică coordonatele cutiei</string>
<string name="waypoint_set_as_cache_coords">Salvează ca coordonatele geocutiei în c:geo</string>
@@ -756,6 +787,8 @@
<string name="search_clear_history">Åžterge istoric</string>
<string name="search_history_cleared">Istoric ÅŸters</string>
<string name="waypoint_coordinate_formats_plain">Simplu</string>
+ <string name="from_clipboard">Din memoria temporară</string>
+ <string name="copy_to_clipboard">Copiază în memoria temporară</string>
<string name="visit_tweet">Publică pe Twitter</string>
<string name="map_map">Hartă</string>
<string name="map_live">Hartă</string>
@@ -860,7 +893,7 @@
<string name="helper_contacts_description">Permite să afişezi contacte (din agenda de contacte) direct din formularul pentru însemnări, astfel încţt să ăti poţi întreba mai uşor prietenii.</string>
<string name="helper_sendtocgeo_description">Send to c:geo este o extensie pentru browser-ul <strong>de pe PC</strong>. Când vizitezi geocaching.com, poţi trimite geocutii direct către dispozitivul tău apăsând un simplu buton.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Aplicaţie simplă care afişează hărţi de pe internet şi îţi permite să le salvezi local (doar caimagini cu hărţi). Mai ştie să înregistreze trasee, gestiune de puncte de interes şi alte funcţii utile.</string>
+ <string name="helper_locus_description">Aplicaţie de navigare pentru telefon sau tabletă. Vezi hărţi salvate, urmăreşte-ţi traseul, caută geocutii, foloseşte ghidare vocală şi multe altele.</string>
<string name="helper_gpsstatus_title">Stare GPS</string>
<string name="helper_gpsstatus_description">Poţi folosi ecranul Radar din această aplicaţie împreună cu c:geo. Oferă şi multe alte informaţii legate de GPS.</string>
<string name="helper_bluetoothgps_title">GPS prin Bluetooth</string>
@@ -1112,13 +1145,15 @@
<string name="attribute_offset_cache_no">Nu este geocutie decalată</string>
<string name="quote">Pentru geocaching mai uşor, pentru căutători mai leneşi.</string>
<string name="powered_by">carnero</string>
- <string name="support">Suport: <a href="">support@cgeo.org</a></string>
- <string name="website">Site: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">pagina c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo pe Google Play</a></string>
+ <string name="support_title">Suport</string>
+ <string name="website_title">Pagină Web</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">pagina c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo pe Google Play</a></string>
<string name="about_twitter">Ar trebui ca <b>c:geo</b> să publice un statut nou pe Twitter de fiecare dată când scrii o însemnare pentru o geocutie?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">ÃŽntrebari frecvente</string>
<string name="status_new_release" tools:ignore="UnusedResources">A apărut o versiune nouă.\nApasă aici pentru a instala.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">A apărut o nouă versiune zilnică.\nApasă aici pentru a instala.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">A apărut o un candidat pentru o versiune nouă.\nApasă aici pentru a instala.</string>
@@ -1138,8 +1173,8 @@
<string name="tts_one_foot">un picior</string>
<string name="tts_one_oclock">ora unu</string>
<string name="tts_oclock">ora %s</string>
- <string name="clipboard_copy_ok">Copiat</string>
- <string name="percent_favorite_points">%\ favorite</string>
+ <string name="clipboard_copy_ok">Copiat în memoria temporară</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favorite</string>
<string name="cgeo_shortcut">legătură la c:geo</string>
<string name="create_shortcut">Crează scurtătură</string>
<string name="send">Trimite</string>
@@ -1149,6 +1184,8 @@
<string name="showcase_main_text">c:geo foloseşte meniu în bara de titlu precum alte aplicaţii moderne. Unele elemente sunt ascunse în spatele simbolului punctat. O apăsare prelungită pe un buton afişează descrierea acestuia.</string>
<string name="showcase_cachelist_title">Comutare între liste</string>
<string name="showcase_cachelist_text">Poţi să schimbi lista afişată apăsând pe titlul listei.</string>
+ <string name="showcase_compass_hint_title">Arată indiciu</string>
+ <string name="showcase_compass_hint_text">Această opţiune îţi poate da informaţii suplimentare despre unde ar putea fi ascunsă geocutia - afişează indiciul, dacă există.</string>
<string name="confirm_log_title">Tip neobişnuit de însemnare</string>
<string name="confirm_log_message">Vrei să scrii o însemnare pentru \'%s\'. Eşti sigur?</string>
</resources>
diff --git a/main/res/values-sk/strings.xml b/main/res/values-sk/strings.xml
index 57706e4..b796eeb 100644
--- a/main/res/values-sk/strings.xml
+++ b/main/res/values-sk/strings.xml
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Navštívené</string>
<string name="log_tb_drop">Nechať tu</string>
<string name="log_tb_changeall">Zmeniť všetko</string>
- <string name="log_save">Uložiť</string>
+ <string name="log_save">Uložiť offline</string>
<string name="log_saving">Ukladanie logu…</string>
<string name="log_saving_and_uploading">Odosielanie logu a nahrávanie obrázku…</string>
<string name="log_clear">VyÄistiÅ¥</string>
<string name="log_post_not_possible">NaÄítanie stránky s logmi…</string>
+ <string name="log_date_future_not_allowed">Log s budúcim dátumom nie je povolený.</string>
<string name="log_add">Pridať</string>
+ <string name="log_repeat">Zopakovať posledný log</string>
<string name="log_no_rating">Nehlasovať</string>
<string name="log_stars_1_description">slabé</string>
<string name="log_stars_15_description">dosť slabé</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Logovacie heslo:</string>
<string name="log_hint_log_password">Zadajte svoje logovacie heslo</string>
<string name="log_oc_team_comment">Komentár tímu OC</string>
+ <string name="log_your_saved_log">Tvoj uložený log</string>
<string-array name="log_image_scales">
<item>Bez zmeny mierky</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Nie sú uložené žiadne prihlasovacie údaje.</string>
<string name="err_login_failed_toast">PrepáÄte, c:geo sa nepodarilo prihlásiÅ¥. c:geo funguje v offline režime. Skontrolujte vaÅ¡e prihlasovacie údaje v nastaveniach alebo povoľte pripojenie k Internetu.</string>
<string name="err_unknown">Neznáma chyba</string>
+ <string name="err_unknown_address">c:geo nedokázal nájsť miesto k daným súradniciam</string>
<string name="err_comm">Neznáma chyba pri komunikácii</string>
<string name="err_missing_auth">Nevyplnené používateľské meno a/alebo heslo.</string>
<string name="err_wrong">Prihlasovacie údaje sú nesprávne</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Získavanie obrázku zlyhalo.</string>
<string name="err_tb_display">PrepáÄte, c:geo nemôže zobraziÅ¥ trasovateľný predmet. Je to naozaj trasovateľný predmet?</string>
<string name="err_tb_details_open">PrepáÄte, c:geo nemôže otvoriÅ¥ podrobnosti k trasovateľnému predmetu.</string>
- <string name="err_tb_forgot_saw">c:geo zabudlo, ktorý trasovateľný predmet ste videli.</string>
<string name="err_tb_find">c:geo nemôže nájsť trasovateľný predmet.</string>
<string name="err_tb_find_that">c:geo nemôže nájsť tento trasovateľný predmet.</string>
<string name="err_waypoint_cache_unknown">c:geo nevie, ku ktorej skrýši chcete pridať bod trasy.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">c:geo nevie, kde ste.</string>
<string name="err_point_no_position_given_title">Popis je požadovaný</string>
<string name="err_point_no_position_given">Vyplňte aspoň zemepisnú šírku a dĺžku alebo vzdialenosť a azimut. Môžete tiež vyplniť všetky štyri polia.</string>
- <string name="err_point_curr_position_unavailable">c:geo stále nepozná aktuálnu polohu. Prosím, Äakajte…</string>
<string name="err_point_bear_and_dist_title">Potrebujete poradiť?</string>
<string name="err_point_bear_and_dist">Vyplňte azimut aj vzdialenosť. Azimut je uhol 0 až 360 stupňov vzhľadom k severu. Vzdialenosť môžete zadať bez jednotiek.</string>
<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_post_failed">c:geo pravdepodobne nemohlo odoslať log. Skontrolujte to, prosím, na Geocaching.com.</string>
- <string name="err_log_post_failed_ec">c:geo pravdepodobne nemohlo odoslať log. Skontrolujte to, prosím, na Extremcaching.com.</string>
- <string name="err_logimage_post_failed">Obrázok k logu sa pravdepodobne nepodarilo nahrať. Skontrolujte to, prosím, na Geocaching.com.</string>
+ <string name="err_log_post_failed">Zdá sa že tvoj log nebol uverejnený. Skontroluj to na stránke keše.</string>
+ <string name="err_logimage_post_failed">Zdá sa že obrázok logu nebol nahratý. Skontroluj to na stránke keše.</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 zistiť zemepisnú šírku.</string>
<string name="err_parse_lon">c:geo nemôže dopoÄítaÅ¥ zemepisnú dĺžku.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">sieť</string>
<string name="loc_fused">ZlúÄené</string>
<string name="loc_low_power">Nízka spotreba</string>
+ <string name="loc_home">Súradnice domova</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">sat</string>
<string name="loc_trying">zisťovanie polohy</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">V okolí</string>
<string name="advanced_search_button">Hľadanie</string>
<string name="stored_caches_button">Uložené</string>
- <string name="any_button">Ciele</string>
+ <string name="any_button">ChoÄ k</string>
<string name="unknown_scan">Nepodarilo sa nájsÅ¥ geokód v naÄítanom výsledku.</string>
<string name="caches_no_cache">Žiadne skrýše</string>
<string name="caches_more_caches">NaÄítaÅ¥ ÄalÅ¡ie skrýše</string>
@@ -259,15 +261,24 @@
<string name="caches_sort_finds">poÄtu nájdení</string>
<string name="caches_sort_state">stavu</string>
<string name="caches_sort_storage">dátumu uloženia v zariadení</string>
+ <string name="caches_sort_eventdate">Dátum Eventu</string>
<string name="caches_select_mode">Mód výberu</string>
<string name="caches_select_mode_exit">Opustiť mód výberu</string>
<string name="caches_select_invert">Inverzný výber</string>
<string name="caches_nearby">V okolí</string>
<string name="caches_manage">Spravovať</string>
<string name="caches_remove_all">Odstrániť všetky</string>
- <string name="caches_remove_all_confirm">Chcete odstrániť všetky %s skrýše z aktuálneho zoznamu?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Chcete odstrániť túto skrýšu z tohoto zoznamu?</item>
+ <item quantity="few">Chcete odstrániť tieto %d skrýše z tohoto zoznamu?</item>
+ <item quantity="other">Chcete odstrániť týchto %d skrýš z tohoto zoznamu?</item>
+ </plurals>
<string name="caches_remove_selected">Odstrániť vybraté</string>
- <string name="caches_remove_selected_confirm">Chcete odstrániť %s vybraté skrýše z vášho zariadenia?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Chcete odstrániť túto skrýšu zo zariadenia?</item>
+ <item quantity="few">Chcete odstrániť tieto %d skrýše zo zariadenia?</item>
+ <item quantity="other">Chcete odstrániť týchto %d skrýš zo zariadenia?</item>
+ </plurals>
<string name="caches_remove_progress">Odstraňovanie skrýše</string>
<string name="caches_delete_events">Odstrániť minulé Eventy</string>
<string name="caches_refresh_selected">Obnoviť vybraté</string>
@@ -287,13 +298,18 @@
<string name="caches_filter_track">S trasovateľnými predmetmi</string>
<string name="caches_filter_clear">Bez filtrovania</string>
<string name="caches_filter_modified">S upravenými súradnicami</string>
+ <string name="caches_filter_offline_log">S offline logmi</string>
<string name="caches_filter_origin">Pôvod</string>
<string name="caches_filter_distance">Vzdialenosť</string>
<string name="caches_filter_personal_note">S osobnou poznámkou</string>
<string name="caches_filter_popularity">Obľúbené</string>
<string name="caches_filter_popularity_ratio">Obľúbené [%]</string>
+ <string name="caches_filter_personal_data">S osobnými údajmi</string>
+ <string name="caches_filter_rating">S hodnotením</string>
+ <string name="caches_filter_own_rating">S vlastným hodnotením</string>
<string name="caches_removing_from_history">Odstraňovanie z histórie…</string>
<string name="caches_clear_offlinelogs">Vymazať offline záznamy</string>
+ <string name="caches_clear_offlinelogs_message">Prajete si vymazať offline logy?</string>
<string name="caches_clear_offlinelogs_progress">Vymazanie logov v režime offline</string>
<string name="list_menu_create">Vytvoriť nový zoznam</string>
<string name="list_menu_drop">Odstrániť tento zoznam</string>
@@ -316,13 +332,17 @@
<string name="list_not_available">Zoznam nie je k dispozícii, prechod na štandardný zoznam</string>
<string name="about_version">Verzia</string>
<string name="about_changelog">Zmeny</string>
+ <string name="about_system">Systém</string>
<string name="about_donate">Podpora vývoja</string>
<string name="about_donation_more">Podporte\nvývoj</string>
<string name="about_contributors">Prispievatelia</string>
<string name="about_license">Licencia</string>
<string name="about_apache_license"><a href=""> Apache License, verzia 2.0</a></string>
<string name="about_help">Pomoc</string>
+ <string name="about_system_include">KeÄ budete posielaÅ¥ správu o chybe alebo budete chcieÅ¥ vedieÅ¥ viac o c:geo, uveÄte, prosím, nasledujúce systémové informácie:</string>
+ <string name="changelog_github">Zoznam všetkých zmien</string>
<string name="settings_title_services">Služby</string>
+ <string name="settings_summary_services">Konfigurovať informácie o používateľskom konte a prístup k voliteľným službám.</string>
<string name="settings_title_appearance">Vzhľad</string>
<string name="settings_title_cachedetails">Detaily skrýše</string>
<string name="settings_title_offlinedata">Údaje v režime offline</string>
@@ -370,6 +390,9 @@
<string name="settings_activate_oc_uk">Aktivovať</string>
<string name="init_oc_uk_description">Autorizovať c:geo pre opencaching.org.uk na vyhľadávanie, zobrazenie a filtrovanie nájdených skrýš.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">Ak chcete hodnotiť keše, postupujte podľa pokynov na GCVote.com a potom sem zadajte svoje GCVote heslo.</string>
+ <string name="err_gcvote_send_rating">Chyba pri odosielaní hodnotenia, skontrolujte GCVote heslo v nastaveniach alebo ho ponechajte prázdne.</string>
+ <string name="gcvote_sent">Hlasovanie úspešne odoslané</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktivovať</string>
<string name="init_username">používateľské meno</string>
@@ -440,6 +463,8 @@
<string name="init_backup_success">Databáza c:geo bola úspešne skopírovaná do:</string>
<string name="init_backup_failed">Záloha databázy c:geo zlyhala.</string>
<string name="init_backup_unnecessary">Databáza je prázdna, záloha nie je potrebná.</string>
+ <string name="backup_confirm_overwrite">Naozaj chceš prepísať existujúcu zálohu z %s?</string>
+ <string name="restore_confirm_overwrite">Naozaj chceš prepísať %s na tvojom zariadení zálohou?</string>
<string name="init_restore_success">Úspešne obnovené.</string>
<string name="init_restore_failed">Obnova zlyhala.</string>
<string name="init_restore_running">Obnovovanie databázy skrýš…</string>
@@ -599,6 +624,7 @@
</plurals>
<string name="cache_waypoints_add">Pridať bod</string>
<string name="cache_hint">Nápoveda</string>
+ <string name="cache_hint_not_available">Žiadna nápoveda</string>
<string name="cache_logs">Logbook</string>
<string name="cache_logs_friends_and_own">Logy priateľov/vlastné</string>
<string name="cache_dialog_loading_details">NaÄítanie detailov skrýše…</string>
@@ -637,10 +663,11 @@
<string name="cache_menu_map_ext">Zobraziť na externej mape</string>
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">OtvoriÅ¥ v prehliadaÄi</string>
- <string name="cache_menu_visit">Zapísať návštevu</string>
- <string name="cache_menu_visit_offline">Zapísať návševu offline</string>
+ <string name="cache_menu_visit">Zalogovať návštevu</string>
+ <string name="cache_menu_visit_offline">Zalogovať offline</string>
<string name="cache_menu_spoilers">Obrázky s nápovedou</string>
<string name="cache_menu_around">Skrýše v okolí</string>
+ <string name="around">Okolo %s</string>
<string name="cache_menu_event">Pridať do kalendára</string>
<string name="cache_menu_details">Detaily</string>
<string name="cache_menu_refresh">Obnoviť</string>
@@ -650,6 +677,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_vote">Hlasovať</string>
+ <string name="cache_menu_checker">Otvoriť Geochecker</string>
+ <string name="cache_menu_ignore">Ignorovať keš</string>
<string name="cache_status">Stav</string>
<string name="cache_status_offline_log">Uložený log</string>
<string name="cache_status_found">Nájdená</string>
@@ -735,6 +765,7 @@
<string name="waypoint_note">poznámka</string>
<string name="waypoint_visited">navštívený</string>
<string name="waypoint_save">Uložiť</string>
+ <string name="waypoint_cancel_edit">Zrušiť</string>
<string name="waypoint_loading">NaÄítanie bodu trasy…</string>
<string name="waypoint_do_not_touch_cache_coordinates">Bez zmeny súradníc skrýše</string>
<string name="waypoint_set_as_cache_coords">Nastaviť ako súradnice skrýše v c:geo</string>
@@ -759,6 +790,8 @@
<string name="search_clear_history">Zmazať históriu</string>
<string name="search_history_cleared">História zmazaná</string>
<string name="waypoint_coordinate_formats_plain">Iba text</string>
+ <string name="from_clipboard">Zo schránky</string>
+ <string name="copy_to_clipboard">Kopírovať do schránky</string>
<string name="visit_tweet">Informovať o nájdení na Twitteri</string>
<string name="map_map">Mapa</string>
<string name="map_live">Aktívna mapa</string>
@@ -863,7 +896,7 @@
<string name="helper_contacts_description">Umožňuje otvorenie karty kontaktu (z adresára) priamo z logbooku, takže môžete ľahko požiadať priateľov o pomoc.</string>
<string name="helper_sendtocgeo_description">PoslaÅ¥ do c:geo je rozšírenie prehliadaÄa <strong>pre vaÅ¡e PC</strong>. Pri browsovaní geocaching.com, môžete poslaÅ¥ cache do vášho smartphone kliknutím na tlaÄidlo priamo v prehliadaÄi.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">UžitoÄná aplikácia zobrazujúca Online i Offline mapy a umožňujúca ich stiahnutie priamo do Offline režimu (iba rastrové online mapy). Tiež podporuje nahrávanie trasy, správu bodov záujmu (POI) a mnoho iných užitoÄných funkcií.</string>
+ <string name="helper_locus_description">NavigaÄná aplikácia pre tvoj mobil alebo tablet. Zmapuj okolie cez offline topografické mapy, zaznamenávaj svoju cestu, hľadaj geocache, používaj hlasovú navigáciu a rob eÅ¡te oveľa viac.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Radar z tejto aplikácie môžete použiť v c:geo. Poskytuje tiež mnoho iných informácií súvisiacich s GPS.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -889,8 +922,8 @@
<string name="export_gpx">GPX</string>
<string name="export_gpx_info">Súbor GPX bude exportovaný do %1$s s názvom súboru podľa aktuálneho dátumu a Äasu.</string>
<string name="export_gpx_to">Odoslať exportovaný GPX súbor do</string>
- <string name="attribute_dogs_yes">Psi povolené</string>
- <string name="attribute_dogs_no">Psi nepovolené</string>
+ <string name="attribute_dogs_yes">Psy povolené</string>
+ <string name="attribute_dogs_no">Psy nepovolené</string>
<string name="attribute_bicycles_yes">Bicykle povolené</string>
<string name="attribute_bicycles_no">Bicykle nepovolené</string>
<string name="attribute_motorcycles_yes">Motorky povolené</string>
@@ -1115,13 +1148,15 @@
<string name="attribute_offset_cache_no">Nie je offset cache</string>
<string name="quote">Pre jednoduchšie hľadanie skrýš a používateľov lenivších.</string>
<string name="powered_by">carnero</string>
- <string name="support">Podpora: <a href="">support@cgeo.org</a></string>
- <string name="website">Web: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href=""> c:geo na Google Play</a></string>
+ <string name="support_title">Podpora</string>
+ <string name="website_title">Webová stránka</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">stránka c:geo</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo na Google Play</a></string>
<string name="about_twitter">Chcete, aby <b>c:geo</b> napísalo na váš Twitter vždy, keÄ zapíšete nájdenie skrýše?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Je dostupné nové vydanie.\nKliknite pre inštaláciu.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Je dostupná nová noÄná zostava.\nKliknite pre inÅ¡taláciu.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Je dostupná nová verzia „release candidate“.\nKliknite pre inštaláciu.</string>
@@ -1172,7 +1207,7 @@
<item quantity="few">%s obľúbené</item>
<item quantity="other">%s obľúbených</item>
</plurals>
- <string name="percent_favorite_points">% \ obľúbených</string>
+ <string name="more_than_percent_favorite_points">&gt; %d %% obľúbených</string>
<string name="cgeo_shortcut">c:Geo odkaz</string>
<string name="create_shortcut">Vytvoriť odkaz</string>
<string name="send">Odoslať</string>
@@ -1182,6 +1217,8 @@
<string name="showcase_main_text">c:geo teraz umiestňuje položky menu v záhlaví, ako iné moderné aplikácie. Niektoré položky sú skryté za symbolom bodiek. Dlhým podržaním tlaÄidla sa zobrazí jeho popis.</string>
<string name="showcase_cachelist_title">Prepínanie zoznamov</string>
<string name="showcase_cachelist_text">Môžete prepínať medzi svojimi zoznamami skrýš kliknutím na názov zoznamu.</string>
+ <string name="showcase_compass_hint_title">Zobraziť nápovedu</string>
+ <string name="showcase_compass_hint_text">Táto vec ti môže pomôcť pri hľadaní skrýše - zobrazí nápovedu ak je dostupná.</string>
<string name="confirm_log_title">NezvyÄajný typ logu</string>
<string name="confirm_log_message">ChceÅ¡ zalogovaÅ¥ \'%s\'. UrÄite?</string>
</resources>
diff --git a/main/res/values-sl/strings.xml b/main/res/values-sl/strings.xml
index b6cd540..65fe770 100644
--- a/main/res/values-sl/strings.xml
+++ b/main/res/values-sl/strings.xml
@@ -74,7 +74,6 @@
<string name="log_tb_visit">Obisk</string>
<string name="log_tb_drop">Pusti v zakladu</string>
<string name="log_tb_changeall">Spremeni vse</string>
- <string name="log_save">Shrani</string>
<string name="log_saving">Pošiljam…</string>
<string name="log_saving_and_uploading">Pošiljam zapis in nalagam sliko…</string>
<string name="log_clear">PoÄisti</string>
@@ -158,7 +157,6 @@
<string name="err_acquire_image_failed">Pridobivanje slike ni uspelo.</string>
<string name="err_tb_display">c:geo ne more prikazati željenega sledljivÄka. Ali je res sledljivÄek?</string>
<string name="err_tb_details_open">c:geo ne more pokazati podatke sledljivÄka.</string>
- <string name="err_tb_forgot_saw">c:geo je pozabil kateri sledljivÄek hoÄete.</string>
<string name="err_tb_find">c:geo ni naÅ¡el sledljivÄka.</string>
<string name="err_tb_find_that">c:geo ni naÅ¡el tega sledljivÄka.</string>
<string name="err_waypoint_cache_unknown">c:geo ne ve h kateremu zakladu želite dodati toÄko.</string>
@@ -166,15 +164,11 @@
<string name="err_point_unknown_position">c:geo ne ve kje ste.</string>
<string name="err_point_no_position_given_title">Potrebne informacije</string>
<string name="err_point_no_position_given">Vnesite vsaj koordinate ali pa razdaljo in smer. Izpolnete lahko tudi vsa polja.</string>
- <string name="err_point_curr_position_unavailable">c:geo Å¡e vedno nima trenutnih koordinat. Prosimo poÄakajte…</string>
<string name="err_point_bear_and_dist_title">Potrebujete pomoÄ?</string>
<string name="err_point_bear_and_dist">Vnesite smer in razdaljo. Smer je kot med 0 in 360 stopinjami od severa. Razdalja je lahko z ali brez enot.</string>
<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_post_failed">Izgleda, kot da zapis ni bil objavljen. Preverite na Geocaching.com.</string>
- <string name="err_log_post_failed_ec">Izgleda, da vaš zapis ni bil objavljen. Preverite na Extremcaching.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>
<string name="err_parse_lat">c:geo ni razumel geografske Å¡irine.</string>
<string name="err_parse_lon">c:geo ni razumel geografske dolžine.</string>
@@ -229,7 +223,6 @@
<string name="caches_nearby_button">V bližini</string>
<string name="advanced_search_button">Iskanje</string>
<string name="stored_caches_button">Shranjeni</string>
- <string name="any_button">Destinacije</string>
<string name="unknown_scan">Iskanje žal ni obrodilo sadov.</string>
<string name="caches_no_cache">Ni zakladov</string>
<string name="caches_more_caches">Naloži veÄ zakladov</string>
@@ -271,9 +264,7 @@
<string name="caches_nearby">V bližini</string>
<string name="caches_manage">Upravljaj</string>
<string name="caches_remove_all">Odstrani vse</string>
- <string name="caches_remove_all_confirm">Ali želite odstraniti vseh %s zakladov iz trenutnega seznama?</string>
<string name="caches_remove_selected">Odstrani izbrane</string>
- <string name="caches_remove_selected_confirm">Ali želite odstraniti %s oznaÄenih zakladov iz vaÅ¡e naprave?</string>
<string name="caches_remove_progress">Odstranjujem zaklade</string>
<string name="caches_delete_events">IzbriÅ¡i pretekla sreÄanja</string>
<string name="caches_refresh_selected">Osveži izbrane</string>
@@ -643,7 +634,6 @@
<string name="cache_menu_streetview">Pogled ulic</string>
<string name="cache_menu_browser">Odpri v brskalniku</string>
<string name="cache_menu_visit">Objavi zapis</string>
- <string name="cache_menu_visit_offline">Shrani zapis</string>
<string name="cache_menu_spoilers">Spoiler slike</string>
<string name="cache_menu_around">Zakladi v bližini</string>
<string name="cache_menu_event">Dodaj na koledar</string>
@@ -868,7 +858,6 @@
<string name="helper_contacts_description">OmogoÄa vam odpiranje vizitke kontakta (v vaÅ¡em adresarju) direktno iz zapisa, tako da lahko lažje vpraÅ¡ate prijatelje za pomoÄ.</string>
<string name="helper_sendtocgeo_description">Send to c:geo je razÅ¡iritev za vaÅ¡ brskalnik <strong>na vaÅ¡em raÄunalniku</strong>. Ko brskate na geocaching.com, lahko iz spletne strani poÅ¡ljete zaklad direktno na vaÅ¡o napravo s klikom na gumb znotraj brskalnika.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Aplikacija Locus vam omogoÄa prikaz zemljevidov brez povezave in prenos zemljevidov direktno na napravo (samo rasterski zemljevidi). OmogoÄa tudi beleženje lokacije, uporavljanje s toÄkami zanimivosti in drugimi uporabnimi funkcionalnostmi.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Aplikacija GPS Status vam omogoÄa prikaz radarja in uporabljate jo lahko z aplikacijo c:geo. OmogoÄa tudi prikaz veliko drugih informacij povezanih z GPS in njihovimi orodji.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1120,13 +1109,7 @@
<string name="attribute_offset_cache_no">Ni Offset zaklad</string>
<string name="quote">Za lažji geocaching in bolj lene zakladolovce.</string>
<string name="powered_by">carnero</string>
- <string name="support">Podpora: <a href="">support@cgeo.org</a></string>
- <string name="website">Spletna stran: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo stran</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo na Google Play</a></string>
<string name="about_twitter">Naj <b>c:geo</b> objavi nov status na Twitter, ko objavite nov zapis pri zakladu?</string>
- <string name="faq">Pogosto zastavljena vprašanja: <a href="">faq.cgeo.org</a></string>
<string name="status_new_release" tools:ignore="UnusedResources">Na voljo je nova razliÄica.\nKliknite za namestitev.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Na voljo je nova dnevna razliÄica.\nKliknite za namestitev.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Na voljo je nova preizkusna razliÄica.\nKliknite za namestitev.</string>
@@ -1183,7 +1166,6 @@
<item quantity="few">%s favoritov</item>
<item quantity="other">%s favoritov</item>
</plurals>
- <string name="percent_favorite_points">%\ favoritov</string>
<string name="cgeo_shortcut">Bližnjica c:geo</string>
<string name="create_shortcut">Ustvari bližnjico</string>
<string name="send">Pošlji</string>
diff --git a/main/res/values-sv/strings.xml b/main/res/values-sv/strings.xml
index e32e45a..3ed622f 100644
--- a/main/res/values-sv/strings.xml
+++ b/main/res/values-sv/strings.xml
@@ -17,7 +17,7 @@
<string name="letterbox">Letterbox hybrid</string>
<string name="event">Event cache</string>
<string name="mega">Mega-event cache</string>
- <string name="giga">Giga-Event Cache</string>
+ <string name="giga">Giga-Event cache</string>
<string name="earth">Earthcache</string>
<string name="cito">Cache in trash out event</string>
<string name="webcam">Webcam cache</string>
@@ -74,12 +74,14 @@
<string name="log_tb_visit">Besök</string>
<string name="log_tb_drop">Lämna här</string>
<string name="log_tb_changeall">Ändra alla</string>
- <string name="log_save">Spara</string>
+ <string name="log_save">Spara offline</string>
<string name="log_saving">Sparar logg…</string>
<string name="log_saving_and_uploading">Sparar logg och laddar upp bild…</string>
<string name="log_clear">Rensa</string>
<string name="log_post_not_possible">Laddar loggningssida…</string>
+ <string name="log_date_future_not_allowed">Framtida loggdatum är inte tillåtna.</string>
<string name="log_add">Lägg till</string>
+ <string name="log_repeat">Upprepa senaste loggen</string>
<string name="log_no_rating">Inget betyg</string>
<string name="log_stars_1_description">DÃ¥lig</string>
<string name="log_stars_15_description">Halvdålig</string>
@@ -107,6 +109,7 @@
<string name="log_password_title">Logglösenord:</string>
<string name="log_hint_log_password">Ange ditt lösenord för loggning</string>
<string name="log_oc_team_comment">Meddelande från OC Team</string>
+ <string name="log_your_saved_log">Din sparade logg</string>
<string-array name="log_image_scales">
<item>Ingen skalning</item>
<item>512 px</item>
@@ -124,6 +127,7 @@
<string name="err_login">Inloggningsinformationen ej sparad</string>
<string name="err_login_failed_toast">Tyvärr kan c:geo inte logga in. c:geo kommer att köra i offline läge med sparade cacher. Kontrollera dina inloggningsuppgifter och aktivera din internetanslutning.</string>
<string name="err_unknown">Okänt fel</string>
+ <string name="err_unknown_address">c:geo kunde inte associera adressen till en plats</string>
<string name="err_comm">Okänt kommunikationsfel</string>
<string name="err_missing_auth">Användarnamn och/eller lösenord saknas.</string>
<string name="err_wrong">Felaktiga inloggningsuppgifter</string>
@@ -158,7 +162,6 @@
<string name="err_acquire_image_failed">Hämtning av bilden misslyckades.</string>
<string name="err_tb_display">Tyvärr kan c:geo inte visa den trackable du önskar. Är den verkligen trackable?</string>
<string name="err_tb_details_open">Tyvärr kan c:geo inte öppna detaljer för trackable.</string>
- <string name="err_tb_forgot_saw">Tyvärr glömde c:geo vilken trackable du såg.</string>
<string name="err_tb_find">Tyvärr kunde c:geo inte hitta trackable</string>
<string name="err_tb_find_that">Tyvärr kan c:geo inte hitta önskad trackable.</string>
<string name="err_waypoint_cache_unknown">Tyvärr vet inte c:geo till vilken cache du vill lägga till en punkt.</string>
@@ -166,15 +169,13 @@
<string name="err_point_unknown_position">Tyvärr kan c:geo inte bestämma din position.</string>
<string name="err_point_no_position_given_title">Mer info krävs</string>
<string name="err_point_no_position_given">Ange minst latitud och longitud eller avstånd och riktning. Du kan också ange alla fyra.</string>
- <string name="err_point_curr_position_unavailable">c:geo har ännu inte nuvarande koordinater. Vänta en stund…</string>
<string name="err_point_bear_and_dist_title">Tips!</string>
<string name="err_point_bear_and_dist">Ange både riktning och avstånd. Rikting är en vinkel mellan 0 och 360 grader relativt norr. Avstånd anges med eller utan enhet.</string>
<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_post_failed">Tyvärr misslyckades c:geo att posta loggen.</string>
- <string name="err_log_post_failed_ec">Det verkar som att din logg inte kunde laddas upp. Kontrollera loggen på Extremcaching.com.</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_log_post_failed">Det verkar som att din logg inte kunde postas. Kontrollera loggen på cachens ursprungliga hemsida.</string>
+ <string name="err_logimage_post_failed">Det verkar som att din logg bild inte kunde laddas upp. Kontrollera bilden på cachens hemsida.</string>
<string name="err_search_address_forgot">Tyvärr glömde c:geo adressen du sökte efter.</string>
<string name="err_parse_lat">Tyvärr kan c:geo inte tolka latitud.</string>
<string name="err_parse_lon">Tyvärr kan c:geo inte tolka longitud.</string>
@@ -211,6 +212,7 @@
<string name="loc_net">Nätverk</string>
<string name="loc_fused">Kombinerad</string>
<string name="loc_low_power">Strömspar</string>
+ <string name="loc_home">Hemkoordinater</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Försöker hitta plats</string>
@@ -229,7 +231,7 @@
<string name="caches_nearby_button">Nära</string>
<string name="advanced_search_button">Sök</string>
<string name="stored_caches_button">Sparade</string>
- <string name="any_button">Valfritt mål</string>
+ <string name="any_button">GÃ¥ till</string>
<string name="unknown_scan">Hittade inte någon geokod i scanningen.</string>
<string name="caches_no_cache">Det finns ingen cache</string>
<string name="caches_more_caches">Ladda fler cacher</string>
@@ -263,15 +265,18 @@
<string name="caches_sort_finds">Antal som hittat</string>
<string name="caches_sort_state">Status</string>
<string name="caches_sort_storage">Tid för sparandet i enheten</string>
+ <string name="caches_sort_eventdate">Eventdatum</string>
<string name="caches_select_mode">Markeringsläge</string>
<string name="caches_select_mode_exit">Avsluta markeringsläge</string>
<string name="caches_select_invert">Invertera valda</string>
<string name="caches_nearby">Nära</string>
<string name="caches_manage">Hantera</string>
<string name="caches_remove_all">Ta bort alla</string>
- <string name="caches_remove_all_confirm">Vill du ta bort alla %s cacher från denna lista?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Vill du radera denna cachen från den här listan?</item>
+ <item quantity="other">Vill du radera dessa %d cacher från den här listan?</item>
+ </plurals>
<string name="caches_remove_selected">Ta bort valda</string>
- <string name="caches_remove_selected_confirm">Vill du ta bort de %s markerade cacherna från enheten?</string>
<string name="caches_remove_progress">Tar bort cacher</string>
<string name="caches_delete_events">Ta bort gamla event</string>
<string name="caches_refresh_selected">Uppdatera valda</string>
@@ -291,13 +296,18 @@
<string name="caches_filter_track">Med trackables</string>
<string name="caches_filter_clear">Rensa filter</string>
<string name="caches_filter_modified">Med tillagda koordinater</string>
+ <string name="caches_filter_offline_log">Med offlinelogg</string>
<string name="caches_filter_origin">Ursprung</string>
<string name="caches_filter_distance">Avstånd</string>
<string name="caches_filter_personal_note">Med personlig anteckning</string>
<string name="caches_filter_popularity">Favoriter</string>
<string name="caches_filter_popularity_ratio">Favoriter [%]</string>
+ <string name="caches_filter_personal_data">Med personlig info</string>
+ <string name="caches_filter_rating">Med betyg</string>
+ <string name="caches_filter_own_rating">Med eget betyg</string>
<string name="caches_removing_from_history">Tar bort från historik…</string>
<string name="caches_clear_offlinelogs">Rensa offline loggar</string>
+ <string name="caches_clear_offlinelogs_message">Vill du rensa offline loggarna?</string>
<string name="caches_clear_offlinelogs_progress">Rensar offline loggar</string>
<string name="list_menu_create">Skapa en ny lista</string>
<string name="list_menu_drop">Ta bort den här listan</string>
@@ -320,13 +330,17 @@
<string name="list_not_available">Listan är inte längre tillgänglig, byter till standardlistan</string>
<string name="about_version">Version</string>
<string name="about_changelog">Historik</string>
+ <string name="about_system">System</string>
<string name="about_donate">Stöd c:geo</string>
<string name="about_donation_more">Donera till\nutveckling</string>
<string name="about_contributors">Medarbetare</string>
<string name="about_license">Licens</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Hjälp</string>
+ <string name="about_system_include">Vänligen inkludera följande systeminformation när du skickar en felrapport eller ber om mer information om c:geo:</string>
+ <string name="changelog_github">Lista över alla ändringar</string>
<string name="settings_title_services">Tjänster</string>
+ <string name="settings_summary_services">Ställ in kontoinformation och tillgång till valbara tjänster.</string>
<string name="settings_title_appearance">Utseende</string>
<string name="settings_title_cachedetails">Cachedetaljer</string>
<string name="settings_title_offlinedata">Offlinedata</string>
@@ -374,6 +388,9 @@
<string name="settings_activate_oc_uk">Aktivera</string>
<string name="init_oc_uk_description">Använd c:geo med opencaching.org.uk för att söka efter cacher samt för att filtrera dina funna cacher.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">För att kunna betygsätta en cache måste du följa instruktionerna på GCVote.com och ange ditt lösenord till GCVote här.</string>
+ <string name="err_gcvote_send_rating">Fel uppstod när betyg skulle sparas, kontrollera eller ta bort lösenordet för GCVote i inställningarna.</string>
+ <string name="gcvote_sent">Röst skickades</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Aktivera</string>
<string name="init_username">Användare</string>
@@ -444,6 +461,8 @@
<string name="init_backup_success">Databasen som används av c:geo har kopierats till filen</string>
<string name="init_backup_failed">Kopieringen av c:geos databas misslyckades.</string>
<string name="init_backup_unnecessary">Databasen är tom, säkerhetkopiering behövs inte.</string>
+ <string name="backup_confirm_overwrite">Vill du skriva över den befintliga säkerhetskopian från %s?</string>
+ <string name="restore_confirm_overwrite">Vill du skriva över %s på enheten med säkerhetskopian?</string>
<string name="init_restore_success">Återställning klar.</string>
<string name="init_restore_failed">Återställningen misslyckades.</string>
<string name="init_restore_running">Återställer databasen med cacher…</string>
@@ -606,6 +625,7 @@
</plurals>
<string name="cache_waypoints_add">Lägg till punkt</string>
<string name="cache_hint">Tips</string>
+ <string name="cache_hint_not_available">Ingen ledtråd tillgänglig</string>
<string name="cache_logs">Loggbok</string>
<string name="cache_logs_friends_and_own">Vänners/egna loggar</string>
<string name="cache_dialog_loading_details">Laddar detaljer om cachen…</string>
@@ -645,9 +665,10 @@
<string name="cache_menu_streetview">Gatuvy</string>
<string name="cache_menu_browser">Öppna i webbläsare</string>
<string name="cache_menu_visit">Logga besök</string>
- <string name="cache_menu_visit_offline">Logga besök offline</string>
+ <string name="cache_menu_visit_offline">Snabblogga offline</string>
<string name="cache_menu_spoilers">Spoiler bilder</string>
<string name="cache_menu_around">Cacher i närheten</string>
+ <string name="around">Kring %s</string>
<string name="cache_menu_event">Lägg till i kalender</string>
<string name="cache_menu_details">Detaljer</string>
<string name="cache_menu_refresh">Uppdatera</string>
@@ -657,6 +678,9 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_android_wear">Android Wear</string>
+ <string name="cache_menu_vote">Rösta</string>
+ <string name="cache_menu_ignore">Ignorera cache</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Sparad logg</string>
<string name="cache_status_found">Hittad</string>
@@ -766,6 +790,8 @@
<string name="search_clear_history">Rensa historik</string>
<string name="search_history_cleared">Historiken rensad</string>
<string name="waypoint_coordinate_formats_plain">Standard</string>
+ <string name="from_clipboard">Från Urklipp</string>
+ <string name="copy_to_clipboard">Kopiera till urklipp</string>
<string name="visit_tweet">Skicka att du hittat till Twitter</string>
<string name="map_map">Karta</string>
<string name="map_live">Live karta</string>
@@ -870,7 +896,7 @@
<string name="helper_contacts_description">Gör det möjligt att öppna en kontakt (i telefonens adressbok) direkt från en logg, så att du enkelt kan kontakta vänner för att få hjälp.</string>
<string name="helper_sendtocgeo_description">Skicka till c:geo är ett tillägg till webbläsaren <strong>för din PC</strong>. När du bläddrar geocaching.com, kan du skicka cacher till din telefon med en knapptryckning i webbläsaren.</string>
<string name="helper_locus_title">Locus</string>
- <string name="helper_locus_description">Ett enkelt program för att visa Online kartor men som också medger nedladdning av raster kartor för användning i Offline läge. Stödjer även inspelning av väg (track recording), POI hantering och många andra användbara funktioner.</string>
+ <string name="helper_locus_description">App för navigering utomhus med telefon eller tablet. Visa topo-kartor offline, spåra din rutt, leta geocacher, använd guideröst och mycket mer.</string>
<string name="helper_gpsstatus_title">GPS Status</string>
<string name="helper_gpsstatus_description">Erbjuder många GPS-relaterade funktioner. Radar-funktionen i detta program kan användas i c:geo.</string>
<string name="helper_bluetoothgps_title">Bluetooth GPS</string>
@@ -1122,13 +1148,15 @@
<string name="attribute_offset_cache_no">Ingen offset cache</string>
<string name="quote">To make geocaching easier, to make users lazier.</string>
<string name="powered_by">carnero</string>
- <string name="support">Support: <a href="">support@cgeo.org</a></string>
- <string name="website">Hemsida: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo på Google Play</a></string>
+ <string name="support_title">Support</string>
+ <string name="website_title">Webbsida</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">c:geo på Facebook</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo på Google Play</a></string>
<string name="about_twitter">Ska <b>c:geo</b> publicera ny status på Twitter varje gång en cache loggas?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<string name="status_new_release" tools:ignore="UnusedResources">Ny officiell version finns tillgänglig.\nKlicka för att installera.</string>
<string name="status_new_nightly" tools:ignore="UnusedResources">Nytt nattligt bygge finns tillgängligt.\nKlicka för att installera.</string>
<string name="status_new_rc" tools:ignore="UnusedResources">Ny kandidat till officiellt bygge finns tillgängligt.\nKlicka för att installera.</string>
@@ -1169,11 +1197,11 @@
<item quantity="one">igår</item>
<item quantity="other">%d dagar sedan</item>
</plurals>
- <string name="percent_favorite_points">%\ favoriter</string>
+ <string name="more_than_percent_favorite_points">&gt; %d%% favoriter</string>
<string name="cgeo_shortcut">c:geo genväg</string>
<string name="create_shortcut">Skapa genväg</string>
<string name="send">Skicka</string>
- <string name="showcase_logcache_title">Skickar loggen</string>
+ <string name="showcase_logcache_title">Skicka loggen</string>
<string name="showcase_logcache_text">Kom ihåg, många kommandon hittar du nu i titelraden. Där hittar du knappen för att skicka den avslutade loggen.</string>
<string name="showcase_main_title">Nya menyer</string>
<string name="showcase_main_text">c:geo placerar nu menyalternativ i titelraden likt andra moderna appar. Några alternativ döljs bakom symbolen med prickar. Tryck länge på en knapp för att se dess beskrivning.</string>
diff --git a/main/res/values/changelog_release.xml b/main/res/values/changelog_release.xml
index 364743a..e30807d 100644
--- a/main/res/values/changelog_release.xml
+++ b/main/res/values/changelog_release.xml
@@ -2,68 +2,11 @@
<resources>
<!-- changelog for the release branch -->
<string name="changelog_release" translatable="false">\n
- <b>2014.09.18:</b>\n
- · Fix: Hardware acceleration is unreliable on some devices\n
- · Fix: Return correct error message if a cache is unpublished\n
- · Fix: Better icon for navigation menu in cache details\n
- · Fix: Reloading captcha was not working\n
- · Fix: Minor layout corrections\n
- · Fix: Avoid crashes after screen rotation\n
+ <b>next bugfix release</b>\n
+ · Fix: Wrong log count shown after logging something else than a found\n
+ · Fix: Copy to clipboard not possible on Android 5.1\n
+ · Fix: Cache links in Groundspeaks weekly mails not opening\n
\n
- <b>2014.09.02:</b>\n
- · Fix: Hardware acceleration is unreliable on Android &lt; 4.2 and on some devices\n
- · Fix: Recognize new date formats on geocaching.com\n
- · Fix: Date for event caches are not available in search results\n
- · Fix: Favorite points should not be given to event caches\n
- · Fix: Force English does not work on main screen\n
- · Fix: Trackables are not included in search on main screen\n
- · Fix: Trackables images are too small\n
- · Fix: Default coordinates format for new installations should be degrees and decimal minutes\n
- · Fix: Several non-frequent causes of crashes\n
- \n
- <b>2014.08.29:</b>\n
- · Fix: Stored found or owned caches shown on map although set to hidden\n
- \n
- <b>2014.08.28:</b>\n
- · New: Option to disable hardware acceleration on problematic devices\n
- · Various bugfixes\n
- \n
- <b>2014.08.27a:</b>\n
- \n
- <font size="16"><b>IMPORTANT CHANGE</b></font>\n
- · New: Actionbar menus (Long press action buttons for a description)\n
- <a href="http://faq.cgeo.org/#10_83">Please do read our FAQ to learn more about the new menu!</a>\n
- \n
- · New: Show also own logs on friends log page\n
- · New: Navigate - WhereYouGo will invoke automatic cartridge download in WhereYouGo\n
- · New: Filter for caches which are not found\n
- · New: Show \"Import from web\" also if not yet registered\n
- · New: Popup list of changes on first start after upgrade\n
- · New: Android Beam (NFC Sharing)\n
- · New: Debugging option to save memory dumps on user demand\n
- · New: Load Greokrety inventory for OC caches\n
- · New: Autosave caches if user modifies waypoints\n
- · New: Show recently viewed caches when clicking search icon on main screen\n
- · New: Add support for opencaching.org.uk\n
- · New: Improved sorting of waypoints depending on waypoint category\n
- · New: Have a link to \"related webpage\" in cache details\n
- · Fix: Hiding own caches on opencaching\n
- · Fix: Webcam caches not marked as found after posting log\n
- · Fix: Archived caches now also hidden if hiding disabled caches is active\n
- · Fix: Filter invalid characters in GPX files\n
- · Fix: All caches shown as owned if no username stored\n
- · Fix: GPX import from mail failing on some devices\n
- · Fix: Updating cache history should not ask for list to save caches\n
- · Fix: Speed now always shown in km or miles per hour\n
- · Fix: USER template now shows the correct username for the site where the cache is hosted\n
- · Fix: Keep filter active if user switches the list\n
- · Fix: Cache names with special chars not shown\n
- · Fix: Improve static maps resolution and scaling depending on the screen resolution\n
- · Fix: Will attend logs not counted in log summary of OC caches\n
- · Fix: Improved loading of listing images\n
- · Fix: Empty personal note not uploaded to gc.com\n
- \n
- <a href="https://github.com/cgeo/cgeo/issues?q=milestone%3A%22Next+feature+release%22+is%3Aclosed">Detailed list of all changes</a>\n
\n
<b>Known Limitations/Bugs:</b>\n
· Device menu button not working on map popup\n
diff --git a/main/res/values/dimens.xml b/main/res/values/dimens.xml
index 9ef3b56..ab09412 100644
--- a/main/res/values/dimens.xml
+++ b/main/res/values/dimens.xml
@@ -5,4 +5,8 @@
<dimen name="actionbar_separator_height">37dip</dimen>
<dimen name="actionbar_separator_width">2dip</dimen>
+ <!-- Dimensions for Samsung Multi-Window support -->
+ <dimen name="app_defaultsize_w">632.0dip</dimen>
+ <dimen name="app_defaultsize_h">598.0dip</dimen>
+
</resources> \ No newline at end of file
diff --git a/main/res/values/ids.xml b/main/res/values/ids.xml
index e8cb74b..99a2311 100644
--- a/main/res/values/ids.xml
+++ b/main/res/values/ids.xml
@@ -24,6 +24,7 @@
<item name="cache_app_show_static_maps" type="id"/>
<item name="cache_app_locus" type="id"/>
<item name="cache_app_pebble" type="id"/>
+ <item name="cache_app_android_wear" type="id"/>
<item name="cache_app_mapswithme" type="id"/>
-</resources> \ No newline at end of file
+</resources>
diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml
index e6ef67a..6335df3 100644
--- a/main/res/values/preference_keys.xml
+++ b/main/res/values/preference_keys.xml
@@ -49,7 +49,7 @@
<string name="pref_skin">skin</string>
<string name="pref_showaddress">showaddress</string>
<string name="pref_useenglish">useenglish</string>
- <string name="pref_units">units</string>
+ <string name="pref_units_imperial">units</string>
<string name="pref_autoloaddesc">autoloaddesc</string>
<string name="pref_ratingwanted">ratingwanted</string>
<string name="pref_friendlogswanted">friendlogswanted</string>
@@ -92,6 +92,7 @@
<string name="pref_webDeviceCode">webDeviceCode</string>
<string name="pref_maplive">maplive</string>
<string name="pref_lastmapzoom">mapzoom</string>
+ <string name="pref_cache_zoom">cachezoom</string>
<string name="pref_lastmaplat">maplat</string>
<string name="pref_lastmaplon">maplon</string>
<string name="pref_livelist">livelist</string>
@@ -106,9 +107,10 @@
<string name="pref_coordinputformat">coordinputformat</string>
<string name="pref_gccustomdate">gccustomdate</string>
<string name="pref_cookiestore">cookiestore</string>
+ <string name="pref_googleplayservices">googleplayservices</string>
+ <string name="pref_lowpowermode">lowpowerlocation</string>
<string name="pref_lastdetailspage">lastdetailspage</string>
<string name="pref_livemapstrategy">livemapstrategy</string>
- <string name="pref_hidelivemaphint">hidelivemaphint</string>
<string name="pref_livemaphintshowcount">livemaphintshowcount</string>
<string name="pref_settingsversion">settingsversion</string>
<string name="pref_trackableaction">trackableaction</string>
@@ -140,6 +142,7 @@
<string name="pref_navigation_menu_google_maps_directions">navigationMapsDirections</string>
<string name="pref_navigation_menu_where_you_go">navigationWhereYouGo</string>
<string name="pref_navigation_menu_pebble">navigationPebble</string>
+ <string name="pref_navigation_menu_android_wear">navigationAndroidWear</string>
<string name="pref_navigation_menu_mapswithme">navigationMapsWithMe</string>
<string name="pref_ocpl_tokensecret">ocpl_tokensecret</string>
<string name="pref_ocpl_tokenpublic">ocpl_tokenpublic</string>
@@ -180,4 +183,7 @@
<string name="pref_changelog_last_checksum">changelog_last_checksum</string>
<string name="pref_caches_history">caches_history</string>
<string name="pref_hardware_acceleration">hardware_acceleration2</string>
+ <string name="pref_last_cache_log">last_cache_log</string>
+ <string name="pref_last_trackable_log">last_trackable_log</string>
+ <string name="pref_home_location">home_location</string>
</resources>
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index b8c77a2..1d551e9 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -86,12 +86,14 @@
<string name="log_tb_visit">Visited</string>
<string name="log_tb_drop">Dropped Off</string>
<string name="log_tb_changeall">Change All</string>
- <string name="log_save">Save</string>
+ <string name="log_save">Save offline</string>
<string name="log_saving">Sending log…</string>
<string name="log_saving_and_uploading">Sending log and uploading image…</string>
<string name="log_clear">Clear</string>
<string name="log_post_not_possible">Loading Log Page…</string>
+ <string name="log_date_future_not_allowed">Future log dates are not allowed.</string>
<string name="log_add">Add</string>
+ <string name="log_repeat">Repeat last log</string>
<string name="log_no_rating">No rating</string>
<string name="log_stars_1_description">Poor</string>
<string name="log_stars_15_description">Fairly poor</string>
@@ -119,7 +121,8 @@
<string name="log_password_title">Log Password:</string>
<string name="log_hint_log_password">Enter your log password</string>
<string name="log_oc_team_comment">OC Team comment</string>
-
+ <string name="log_your_saved_log">Your saved log</string>
+
<string-array name="log_image_scales">
<item>No scaling</item>
<item>512 px</item>
@@ -141,6 +144,7 @@
<string name="err_login">No Login information stored</string>
<string name="err_login_failed_toast">c:geo can\'t log in. c:geo works offline with Stored caches. Check Login settings or enable your internet connection.</string>
<string name="err_unknown">Unknown error</string>
+ <string name="err_unknown_address">c:geo was unable to map this address to an existing location</string>
<string name="err_comm">Unknown communication error</string>
<string name="err_missing_auth">No username and/or password set.</string>
<string name="err_wrong">Login information incorrect</string>
@@ -175,7 +179,6 @@
<string name="err_acquire_image_failed">Acquiring an image failed.</string>
<string name="err_tb_display">c:geo can\'t display the trackable you want. Is it really a trackable?</string>
<string name="err_tb_details_open">c:geo can\'t open trackable details.</string>
- <string name="err_tb_forgot_saw">c:geo forgot which trackable you saw.</string>
<string name="err_tb_find">c:geo can\'t find trackable</string>
<string name="err_tb_find_that">c:geo can\'t find that trackable.</string>
<string name="err_waypoint_cache_unknown">c:geo doesn\'t know to which cache you want to add a waypoint for.</string>
@@ -183,15 +186,13 @@
<string name="err_point_unknown_position">c:geo can\'t recognize where you are.</string>
<string name="err_point_no_position_given_title">Info required</string>
<string name="err_point_no_position_given">Fill at least latitude and longitude or distance and bearing. You can also fill all four fields.</string>
- <string name="err_point_curr_position_unavailable">c:geo still doesn\'t have current coordinates. Please, wait a while…</string>
<string name="err_point_bear_and_dist_title">Need some help?</string>
<string name="err_point_bear_and_dist">Fill both bearing and distance. Bearing is angle 0 to 360 degrees relative to north. Distance doesn\'t require units.</string>
<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_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>
+ <string name="err_log_post_failed">It seems that your log was not posted. Please check it on the cache originating website.</string>
+ <string name="err_logimage_post_failed">It seems that your log image was not uploaded. Please check it on the cache originating website.</string>
<string name="err_search_address_forgot">c:geo forgot the address you tried to find.</string>
<string name="err_parse_lat">c:geo can\'t parse latitude.</string>
<string name="err_parse_lon">c:geo can\'t parse longitude.</string>
@@ -228,6 +229,9 @@
<!-- location service -->
<string name="loc_last">Last known</string>
<string name="loc_net">Network</string>
+ <string name="loc_fused">Fused</string>
+ <string name="loc_low_power">Low-power</string>
+ <string name="loc_home">Home coordinates</string>
<string name="loc_gps">GPS</string>
<string name="loc_sat">Sat</string>
<string name="loc_trying">Trying to Locate</string>
@@ -251,7 +255,7 @@
<string name="caches_nearby_button">Nearby</string>
<string name="advanced_search_button">Search</string>
<string name="stored_caches_button">Stored</string>
- <string name="any_button">Any destination</string>
+ <string name="any_button">Go to</string>
<string name="unknown_scan">Didn\'t find any geocodes in the scan result.</string>
<!-- caches -->
@@ -295,9 +299,15 @@
<string name="caches_nearby">Nearby</string>
<string name="caches_manage">Manage</string>
<string name="caches_remove_all">Remove all</string>
- <string name="caches_remove_all_confirm">Do you want to remove all %s caches from current list?</string>
+ <plurals name="caches_remove_all_confirm">
+ <item quantity="one">Do you want to remove this cache from current list?</item>
+ <item quantity="other">Do you want to remove all %d caches from current list?</item>
+ </plurals>
<string name="caches_remove_selected">Remove selected</string>
- <string name="caches_remove_selected_confirm">Do you want to remove the selected %s caches from your device?</string>
+ <plurals name="caches_remove_selected_confirm">
+ <item quantity="one">Do you want to remove this cache from your device?</item>
+ <item quantity="other">Do you want to remove the selected %d caches from your device?</item>
+ </plurals>
<string name="caches_remove_progress">Removing caches</string>
<string name="caches_delete_events">Delete past events</string>
<string name="caches_refresh_selected">Refresh selected</string>
@@ -317,13 +327,18 @@
<string name="caches_filter_track">With Trackables</string>
<string name="caches_filter_clear">Clear filters</string>
<string name="caches_filter_modified">With modified coordinates</string>
+ <string name="caches_filter_offline_log">With offline log</string>
<string name="caches_filter_origin">Origin</string>
<string name="caches_filter_distance">Distance</string>
<string name="caches_filter_personal_note">With personal note</string>
<string name="caches_filter_popularity">Favorites</string>
<string name="caches_filter_popularity_ratio">Favorites [%]</string>
+ <string name="caches_filter_personal_data">With personal data</string>
+ <string name="caches_filter_rating">With rating</string>
+ <string name="caches_filter_own_rating">With own rating</string>
<string name="caches_removing_from_history">Removing from History…</string>
<string name="caches_clear_offlinelogs">Clear offline logs</string>
+ <string name="caches_clear_offlinelogs_message">Do you want to clear the offline logs?</string>
<string name="caches_clear_offlinelogs_progress">Clearing offline logs</string>
<!-- caches lists -->
@@ -350,15 +365,19 @@
<!-- about -->
<string name="about_version">Version</string>
<string name="about_changelog">Changelog</string>
+ <string name="about_system">System</string>
<string name="about_donate">Donate</string>
<string name="about_donation_more">Donate\ndevelopment</string>
<string name="about_contributors">Contributors</string>
<string name="about_license">License</string>
<string name="about_apache_license"><a href="">Apache License, Version 2.0</a></string>
<string name="about_help">Help</string>
+ <string name="about_system_include">Please include the following system information when sending a bug report or asking for more information about c:geo:</string>
+ <string name="changelog_github">List of all changes</string>
<!-- settings -->
<string name="settings_title_services">Services</string>
+ <string name="settings_summary_services">Configure user account information and access to optional services.</string>
<string name="settings_title_appearance">Appearance</string>
<string name="settings_title_cachedetails">Cache Details</string>
<string name="settings_title_offlinedata">Offline Data</string>
@@ -409,6 +428,9 @@
<string name="settings_activate_oc_uk">Activate</string>
<string name="init_oc_uk_description">Authorize c:geo with opencaching.org.uk to search for caches and access/filter your found caches.</string>
<string name="init_gcvote">GCvote.com</string>
+ <string name="init_gcvote_password_description">To be able to rate a cache, you need to follow the instructions at GCVote.com and enter your GCVote password here.</string>
+ <string name="err_gcvote_send_rating">Error while sending rating, check GCVote password in settings or empty it.</string>
+ <string name="gcvote_sent">Voting successfully sent</string>
<string name="init_twitter">Twitter</string>
<string name="settings_activate_twitter">Activate</string>
<string name="init_username">Username</string>
@@ -479,6 +501,8 @@
<string name="init_backup_success">c:geo\'s database was successfully copied to:</string>
<string name="init_backup_failed">Backup of c:geo\'s database failed.</string>
<string name="init_backup_unnecessary">Database is empty, no backup necessary.</string>
+ <string name="backup_confirm_overwrite">Do you want to overwrite the existing backup from %s?</string>
+ <string name="restore_confirm_overwrite">Do you want to overwrite %s on your device with the backup?</string>
<string name="init_restore_success">Restoration completed.</string>
<string name="init_restore_failed">Restoration failed.</string>
<string name="init_restore_running">Restoring cache database…</string>
@@ -527,6 +551,12 @@
<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="init_location">Geolocation</string>
+ <string name="init_location_note">On devices equipped with Google Play Services, c:geo can automatically use a better geolocation provider. However, this prevents the use of an external BlueTooth GPS receiver.</string>
+ <string name="init_location_googleplayservices">Use Google Play Services</string>
+ <string name="init_low_power">Low-power mode</string>
+ <string name="init_low_power_note">The low-power mode avoids using the GPS and the gyroscope when a highly accurate location is not strictly necessary, at the cost of longer fixing times.</string>
+ <string name="init_low_power_mode">Activate low-power mode</string>
<string name="init_create_memory_dump">Create memory dump</string>
<string name="init_memory_dump">Memory dump</string>
<string name="init_memory_dumped">Memory dumped to %s</string>
@@ -648,6 +678,7 @@
<string name="cache_waypoints_add">Add Waypoint</string>
<string name="cache_hint">Hint</string>
+ <string name="cache_hint_not_available">No hint available</string>
<string name="cache_logs">Logbook</string>
<string name="cache_logs_friends_and_own">Friends/Own Logs</string>
<string name="cache_dialog_loading_details">Loading cache details…</string>
@@ -687,9 +718,10 @@
<string name="cache_menu_streetview">Street View</string>
<string name="cache_menu_browser">Open in browser</string>
<string name="cache_menu_visit">Log Visit</string>
- <string name="cache_menu_visit_offline">Log Visit offline</string>
+ <string name="cache_menu_visit_offline">One click offline log</string>
<string name="cache_menu_spoilers">Spoiler images</string>
<string name="cache_menu_around">Caches around</string>
+ <string name="around">Around %s</string>
<string name="cache_menu_event">Add to calendar</string>
<string name="cache_menu_details">Details</string>
<string name="cache_menu_refresh">Refresh</string>
@@ -699,6 +731,10 @@
<string name="cache_menu_oruxmaps">OruxMaps</string>
<string name="cache_menu_navigon">Navigon</string>
<string name="cache_menu_pebble">Pebble</string>
+ <string name="cache_menu_android_wear">Android Wear</string>
+ <string name="cache_menu_vote">Vote</string>
+ <string name="cache_menu_checker">Open Geochecker</string>
+ <string name="cache_menu_ignore">Ignore cache</string>
<string name="cache_status">Status</string>
<string name="cache_status_offline_log">Saved Log</string>
<string name="cache_status_found">Found</string>
@@ -825,7 +861,9 @@
<string name="search_clear_history">Clear History</string>
<string name="search_history_cleared">History cleared</string>
<string name="waypoint_coordinate_formats_plain">Plain</string>
-
+ <string name="from_clipboard">From clipboard</string>
+ <string name="copy_to_clipboard">Copy to clipboard</string>
+
<!-- visit -->
<string name="visit_tweet">Post this find to Twitter</string>
@@ -938,11 +976,11 @@
<string name="license_dismiss">Dismiss</string>
<!-- helpers -->
- <string name="helper_calendar_title">c:geo calendar add-on</string>
- <string name="helper_calendar_missing">c:geo calendar add-on not installed.</string>
+ <string name="helper_calendar_title">c:geo calendar plugin</string>
+ <string name="helper_calendar_missing">c:geo calendar plugin 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_title">c:geo contacts plugin</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>
@@ -959,7 +997,7 @@
<string name="helper_google_translate_description">If you download translation packages in the Google Translate app, then you can easily translate cache descriptions in c:geo by a long tap on the cache description text (without an Internet connection).</string>
<!-- add-ons -->
- <string name="addon_missing_title">Missing Add-On</string>
+ <string name="addon_missing_title">Missing plugin</string>
<string name="addon_download_prompt">Get it now from Google Play.</string>
<!-- export -->
@@ -1207,13 +1245,15 @@
<string name="quote">To make geocaching easier, to make users lazier.</string>
<string name="powered_by">carnero</string>
<!-- Note: Links here are just for appearance. See AboutActivity to make changes -->
- <string name="support">Support: <a href="">support@cgeo.org</a></string>
- <string name="website">Website: <a href="">cgeo.org</a></string>
- <string name="facebook">Facebook: <a href="">c:geo page</a></string>
- <string name="twitter">Twitter: <a href="">@android_GC</a></string>
- <string name="market">Android: <a href="">c:geo on Google Play</a></string>
+ <string name="support_title">Support</string>
+ <string name="website_title">Website</string>
+ <string name="facebook_title">Facebook</string>
+ <string name="facebook_link"><a href="">c:geo page</a></string>
+ <string name="twitter_title">Twitter</string>
+ <string name="market_title">Google Play</string>
+ <string name="market_link"><a href="">c:geo on Google Play</a></string>
<string name="about_twitter">Should <b>c:geo</b> publish a new status on Twitter every time you log a cache?</string>
- <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string>
+ <string name="faq_title">FAQ</string>
<!-- status (used via string based resource loading) -->
<string name="status_new_release" tools:ignore="UnusedResources">New release available.\nClick to install.</string>
@@ -1266,7 +1306,7 @@
<item quantity="other">%s favorites</item>
</plurals>
- <string name="percent_favorite_points">%\ favorites</string>
+ <string name="more_than_percent_favorite_points">> %d%% favorites</string>
<!-- shortcuts -->
<string name="cgeo_shortcut">c:geo shortcut</string>
@@ -1279,4 +1319,8 @@
<string name="showcase_main_text">c:geo now places menu items in the title bar like other modern apps. Some items are hidden behind the dotted symbol. Long press a button to see its description.</string>
<string name="showcase_cachelist_title">Switching lists</string>
<string name="showcase_cachelist_text">You can switch between your geocache lists by clicking the title of the list.</string>
+ <string name="showcase_compass_hint_title">Show the hint</string>
+ <string name="showcase_compass_hint_text">This new menu item might give you an idea where to find the cache - it shows the hint, if available.</string>
+ <string name="confirm_log_title">Unusual log type</string>
+ <string name="confirm_log_message">You want to log \'%s\'. Are you sure?</string>
</resources>
diff --git a/main/res/values/strings_not_translatable.xml b/main/res/values/strings_not_translatable.xml
index 585500f..d216715 100644
--- a/main/res/values/strings_not_translatable.xml
+++ b/main/res/values/strings_not_translatable.xml
@@ -76,11 +76,14 @@
· <a href="http://code.google.com/p/mapsforge/">Mapsforge</a> (OSM-rendering)\n
· <a href="http://thenounproject.com/">The Noun Project</a> (basis for attribute icons):\n
&#160;&#160;&#160;· USB by Kenneth Von Alt from The Noun Project\n
+ &#160;&#160;&#160;· new-idea by Artem Korotkikh from The Noun Project\n
· <a href="http://commons.apache.org/">The Apache Commons Project</a>\n
· <a href="http://androidicons.com/">Android Icons</a> (<a href="https://creativecommons.org/licenses/by/3.0/">CC-BY 3.0</a>)\n
· <a href="http://rrze-icon-set.berlios.de/index.html">RRZE Icon set</a> (<a href="http://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA 3.0</a>)\n
· <a href="http://iconfindr.com/1mNr3rl">Layers icon by Cole Bemis</a> (<a href="http://creativecommons.org/licenses/by/3.0/">CC-BY 3.0</a>)\n
· <a href="https://github.com/amlcurran/Showcaseview">ShowcaseView by Alex Curran</a> (<a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</a>)\n
+ · <a href="http://www.mapquest.com/">Geocoding courtesy of MapQuest</a>\n
+ · <a href="http://www.openstreetmap.org/">Geocoding data from OpenStreetMap</a>\n
</string>
<!-- cache menu -->
@@ -88,5 +91,10 @@
<string name="caches_map_mapswithme" translatable="false">Maps.me</string>
<string name="cache_menu_mapswithme" translatable="false">Maps.me</string>
+ <string name="faq_link"><a href="">faq.cgeo.org</a></string>
+ <string name="website_link"><a href="">cgeo.org</a></string>
+ <string name="twitter_link"><a href="">@android_GC</a></string>
+ <string name="support_link"><a href="">support@cgeo.org</a></string>
+
</resources>
diff --git a/main/res/values/styles.xml b/main/res/values/styles.xml
index be1e1a4..5f280f2 100644
--- a/main/res/values/styles.xml
+++ b/main/res/values/styles.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- system definitions -->
@@ -338,4 +338,13 @@
<item name="android:src">@drawable/mark_green</item>
</style>
+ <style name="cacheRatingBar" parent="@android:style/Widget.RatingBar">
+ <item name="android:progressDrawable">@drawable/star_rating</item>
+ <item name="android:minHeight">12dip</item>
+ <item name="android:maxHeight">22dip</item>
+ <item name="android:max">5</item>
+ <item name="android:stepSize">0.5</item>
+ <item name="android:isIndicator">true</item>
+ </style>
+
</resources> \ No newline at end of file
diff --git a/main/res/values/themes.xml b/main/res/values/themes.xml
index 50485b3..751f325 100644
--- a/main/res/values/themes.xml
+++ b/main/res/values/themes.xml
@@ -9,7 +9,7 @@
<style name="cgeo_main.base" parent="@style/Theme.AppCompat">
- <!-- copy the style elements of the Wallpaper theme since AppCombat has no Wallpaper theme -->
+ <!-- copy the style elements of the Wallpaper theme since AppCompat has no Wallpaper theme -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml
index 1ed739d..48d8a21 100644
--- a/main/res/xml/preferences.xml
+++ b/main/res/xml/preferences.xml
@@ -6,7 +6,8 @@
<PreferenceScreen
android:icon="?attr/settings_cloud"
android:key="@string/preference_screen_services"
- android:title="@string/settings_title_services" >
+ android:title="@string/settings_title_services"
+ android:summary="@string/settings_summary_services">
<PreferenceCategory android:title="@string/settings_category_geocaching" >
<PreferenceScreen
android:key="@string/preference_screen_gc"
@@ -325,7 +326,13 @@
android:summary="@string/init_summary_ratingwanted"
android:title="@string/init_ratingwanted" />
+ <cgeo.geocaching.settings.TextPreference
+ android:dependency="@string/pref_ratingwanted"
+ android:layout="@layout/text_preference"
+ android:text="@string/init_gcvote_password_description" />
+
<cgeo.geocaching.settings.EditPasswordPreference
+ android:dependency="@string/pref_ratingwanted"
android:dialogTitle="@string/init_password"
android:hint="@string/init_password"
android:imeOptions="actionDone"
@@ -430,7 +437,7 @@
android:title="@string/init_useenglish" />
<CheckBoxPreference
android:defaultValue="false"
- android:key="@string/pref_units"
+ android:key="@string/pref_units_imperial"
android:summary="@string/init_summary_units"
android:title="@string/init_units" />
</PreferenceScreen>
@@ -697,6 +704,11 @@
<CheckBoxPreference
android:defaultValue="true"
android:enabled="false"
+ android:key="@string/pref_navigation_menu_android_wear"
+ android:title="@string/cache_menu_android_wear" />
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:enabled="false"
android:key="@string/pref_navigation_menu_mapswithme"
android:title="@string/cache_menu_mapswithme" />
</PreferenceScreen>
@@ -745,6 +757,25 @@
android:key="@string/pref_fakekey_preference_maintenance_directories"
android:title="@string/init_maintenance_directories" />
</PreferenceCategory>
+ <PreferenceCategory android:title="@string/init_location">
+ <cgeo.geocaching.settings.TextPreference
+ android:layout="@layout/text_preference"
+ android:text="@string/init_location_note" />
+
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:key="@string/pref_googleplayservices"
+ android:title="@string/init_location_googleplayservices" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/init_low_power">
+ <cgeo.geocaching.settings.TextPreference
+ android:layout="@layout/text_preference"
+ android:text="@string/init_low_power_note" />
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:key="@string/pref_lowpowermode"
+ android:title="@string/init_low_power_mode" />
+ </PreferenceCategory>
<PreferenceCategory android:title="@string/init_hardware_acceleration_title">
<cgeo.geocaching.settings.TextPreference
android:layout="@layout/text_preference"
diff --git a/main/src/cgeo/calendar/CalendarAddon.java b/main/src/cgeo/calendar/CalendarAddon.java
index 4a672fa..88c67a8 100644
--- a/main/src/cgeo/calendar/CalendarAddon.java
+++ b/main/src/cgeo/calendar/CalendarAddon.java
@@ -2,12 +2,13 @@ package cgeo.calendar;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.location.GeopointFormatter;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.ProcessUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.app.Activity;
import android.content.DialogInterface;
@@ -27,10 +28,11 @@ public class CalendarAddon {
return ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST));
}
- public static void addToCalendarWithIntent(final Activity activity, final Geocache cache) {
+ public static void addToCalendarWithIntent(@NonNull final Activity activity, @NonNull final Geocache cache) {
final Resources res = activity.getResources();
if (CalendarAddon.isAvailable()) {
final Date hiddenDate = cache.getHiddenDate();
+ final String startTime = cache.guessEventTimeMinutes() >= 0 ? String.valueOf(cache.guessEventTimeMinutes()) : StringUtils.EMPTY;
final Parameters params = new Parameters(
ICalendar.PARAM_NAME, cache.getName(),
ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()),
@@ -39,7 +41,7 @@ public class CalendarAddon {
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())
+ ICalendar.PARAM_START_TIME_MINUTES, startTime
);
activity.startActivity(new Intent(ICalendar.INTENT,
@@ -51,10 +53,8 @@ public class CalendarAddon {
.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);
+ public void onClick(final DialogInterface dialog, final int id) {
+ ProcessUtils.openMarket(activity, "cgeo.calendar");
}
});
}
diff --git a/main/src/cgeo/calendar/ICalendar.java b/main/src/cgeo/calendar/ICalendar.java
index 6ecb6d5..9001198 100644
--- a/main/src/cgeo/calendar/ICalendar.java
+++ b/main/src/cgeo/calendar/ICalendar.java
@@ -1,19 +1,22 @@
package cgeo.calendar;
+import org.eclipse.jdt.annotation.NonNull;
+
public interface ICalendar {
- static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.calendar";
+ @Deprecated
+ @NonNull static final String CALENDAR_ADDON_URI = "market://details?id=cgeo.calendar";
- static final String INTENT = "cgeo.calendar.RESERVE";
+ @NonNull static final String INTENT = "cgeo.calendar.RESERVE";
- static final String URI_SCHEME = "add";
- static final String URI_HOST = "cgeo.org";
+ @NonNull static final String URI_SCHEME = "add";
+ @NonNull static final String URI_HOST = "cgeo.org";
- static final String PARAM_SHORT_DESC = "shortDesc"; // cache short description
- static final String PARAM_HIDDEN_DATE = "hiddenDate"; // cache hidden date in milliseconds
- static final String PARAM_URL = "url"; // cache URL
- 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 coordinates, or empty string
- static final String PARAM_START_TIME_MINUTES = "time"; // time of start
+ @NonNull static final String PARAM_SHORT_DESC = "shortDesc"; // cache short description
+ @NonNull static final String PARAM_HIDDEN_DATE = "hiddenDate"; // cache hidden date in milliseconds
+ @NonNull static final String PARAM_URL = "url"; // cache URL
+ @NonNull static final String PARAM_NOTE = "note"; // personal note
+ @NonNull static final String PARAM_NAME = "name"; // cache name
+ @NonNull static final String PARAM_LOCATION = "location"; // cache location, or empty string
+ @NonNull static final String PARAM_COORDS = "coords"; // cache coordinates, or empty string
+ @NonNull static final String PARAM_START_TIME_MINUTES = "time"; // time of start
}
diff --git a/main/src/cgeo/contacts/ContactsAddon.java b/main/src/cgeo/contacts/ContactsAddon.java
index 7165a77..6c0dd21 100644
--- a/main/src/cgeo/contacts/ContactsAddon.java
+++ b/main/src/cgeo/contacts/ContactsAddon.java
@@ -3,6 +3,8 @@ package cgeo.contacts;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.ProcessUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
@@ -13,7 +15,7 @@ public class ContactsAddon {
// utility class
}
- public static void openContactCard(Activity context, String userName) {
+ public static void openContactCard(@NonNull final Activity context, @NonNull final String userName) {
final Parameters params = new Parameters(
IContacts.PARAM_NAME, userName
);
diff --git a/main/src/cgeo/contacts/IContacts.java b/main/src/cgeo/contacts/IContacts.java
index d68b78a..5a6c04d 100644
--- a/main/src/cgeo/contacts/IContacts.java
+++ b/main/src/cgeo/contacts/IContacts.java
@@ -1,10 +1,12 @@
package cgeo.contacts;
+import org.eclipse.jdt.annotation.NonNull;
+
public interface IContacts {
- static final String INTENT = "cgeo.contacts.FIND";
+ @NonNull static final String INTENT = "cgeo.contacts.FIND";
- static final String URI_SCHEME = "find";
- static final String URI_HOST = "cgeo.org";
+ @NonNull static final String URI_SCHEME = "find";
+ @NonNull static final String URI_HOST = "cgeo.org";
- static final String PARAM_NAME = "name"; // user name
+ @NonNull static final String PARAM_NAME = "name"; // user name
}
diff --git a/main/src/cgeo/geocaching/AboutActivity.java b/main/src/cgeo/geocaching/AboutActivity.java
index f6d204b..e5a98c2 100644
--- a/main/src/cgeo/geocaching/AboutActivity.java
+++ b/main/src/cgeo/geocaching/AboutActivity.java
@@ -3,9 +3,20 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
+import cgeo.calendar.CalendarAddon;
+import cgeo.contacts.ContactsAddon;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
+import cgeo.geocaching.compatibility.Compatibility;
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.capability.ILogin;
+import cgeo.geocaching.sensors.OrientationProvider;
+import cgeo.geocaching.sensors.RotationProvider;
+import cgeo.geocaching.sensors.Sensors;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
+import cgeo.geocaching.utils.ClipboardUtils;
+import cgeo.geocaching.utils.ProcessUtils;
import cgeo.geocaching.utils.Version;
import org.apache.commons.io.IOUtils;
@@ -17,15 +28,20 @@ import org.apache.commons.lang3.tuple.Pair;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION;
import android.os.Bundle;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
import java.util.Scanner;
public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page> {
@@ -65,6 +81,7 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
@InjectView(R.id.changelog_master) protected TextView changeLogMaster;
@InjectView(R.id.changelog_release) protected TextView changeLogRelease;
+ @InjectView(R.id.changelog_github) protected TextView changeLogLink;
@Override
public ScrollView getDispatchedView(final ViewGroup parentView) {
@@ -77,11 +94,42 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
} else {
changeLogMaster.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
}
+ changeLogLink.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(final View v) {
+ startUrl("https://github.com/cgeo/cgeo/releases");
+ }
+ });
return view;
}
}
+ class SystemViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
+
+ @InjectView(R.id.system) protected TextView system;
+ @InjectView(R.id.copy) protected Button copy;
+
+ @Override
+ public ScrollView getDispatchedView(final ViewGroup parentView) {
+ final ScrollView view = (ScrollView) getLayoutInflater().inflate(R.layout.about_system_page, parentView, false);
+ ButterKnife.inject(this, view);
+ final String systemInfo = systemInformation(AboutActivity.this);
+ system.setText(systemInfo);
+ system.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ Compatibility.setTextIsSelectable(system, true);
+ copy.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View view) {
+ ClipboardUtils.copyToClipboard(systemInfo);
+ showShortToast(getString(R.string.clipboard_copy_ok));
+ }
+ });
+ return view;
+ }
+ }
+
class HelpViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
@InjectView(R.id.support) protected TextView support;
@@ -95,7 +143,8 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
public ScrollView getDispatchedView(final ViewGroup parentView) {
final ScrollView view = (ScrollView) getLayoutInflater().inflate(R.layout.about_help_page, parentView, false);
ButterKnife.inject(this, view);
- setClickListener(support, "mailto:support@cgeo.org?subject=" + Uri.encode("cgeo " + Version.getVersionName(AboutActivity.this)));
+ setClickListener(support, "mailto:support@cgeo.org?subject=" + Uri.encode("cgeo " + Version.getVersionName(AboutActivity.this)) +
+ "&body=" + Uri.encode(systemInformation(AboutActivity.this)) + "\n");
setClickListener(website, "http://www.cgeo.org/");
setClickListener(facebook, "http://www.facebook.com/pages/cgeo/297269860090");
setClickListener(twitter, "http://twitter.com/android_gc");
@@ -104,7 +153,7 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
@Override
public void onClick(final View v) {
- market();
+ ProcessUtils.openMarket(AboutActivity.this, getPackageName());
}
});
return view;
@@ -131,6 +180,7 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
VERSION(R.string.about_version),
HELP(R.string.about_help),
CHANGELOG(R.string.about_changelog),
+ SYSTEM(R.string.about_system),
CONTRIBUTORS(R.string.about_contributors),
LICENSE(R.string.about_license);
@@ -168,12 +218,6 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
}
- final void market() {
- final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName()));
- marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- startActivity(marketIntent);
- }
-
@Override
protected final cgeo.geocaching.activity.AbstractViewPagerActivity.PageViewCreator createViewCreator(final Page page) {
switch (page) {
@@ -183,6 +227,8 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
return new HelpViewCreator();
case CHANGELOG:
return new ChangeLogViewCreator();
+ case SYSTEM:
+ return new SystemViewCreator();
case CONTRIBUTORS:
return new ContributorsViewCreator();
case LICENSE:
@@ -224,4 +270,57 @@ public class AboutActivity extends AbstractViewPagerActivity<AboutActivity.Page>
fromActivity.startActivity(intent);
}
+ private static String presence(final Boolean present) {
+ return present ? "present" : "absent";
+ }
+
+ private static String systemInformation(final Context context) {
+ final boolean googlePlayServicesAvailable = CgeoApplication.getInstance().isGooglePlayServicesAvailable();
+ final StringBuilder body = new StringBuilder("--- System information ---")
+ .append("\nDevice: ").append(Build.MODEL).append(" (").append(Build.PRODUCT).append(", ").append(Build.BRAND).append(")")
+ .append("\nAndroid version: ").append(VERSION.RELEASE)
+ .append("\nAndroid build: ").append(Build.DISPLAY)
+ .append("\nCgeo version: ").append(Version.getVersionName(context))
+ .append("\nGoogle Play services: ").append(googlePlayServicesAvailable ? (Settings.useGooglePlayServices() ? "enabled" : "disabled") : "unavailable")
+ .append("\nLow power mode: ").append(Settings.useLowPowerMode() ? "active" : "inactive")
+ .append("\nCompass capabilities: ").append(Sensors.getInstance().hasCompassCapabilities() ? "yes" : "no")
+ .append("\nRotation sensor: ").append(presence(RotationProvider.hasRotationSensor(context)))
+ .append("\nGeomagnetic rotation sensor: ").append(presence(RotationProvider.hasGeomagneticRotationSensor(context)))
+ .append("\nOrientation sensor: ").append(presence(OrientationProvider.hasOrientationSensor(context)))
+ .append("\nHide own/found: ").append(Settings.isExcludeMyCaches())
+ .append("\nMap strategy: ").append(Settings.getLiveMapStrategy().toString().toLowerCase(Locale.getDefault()))
+ .append("\nHW-acceleration: ").append(Settings.useHardwareAcceleration() ? "enabled" : "disabled")
+ .append(" (").append(Settings.useHardwareAcceleration() != Settings.HW_ACCEL_DISABLED_BY_DEFAULT ? "default state" : "manually changed").append(")");
+ final StringBuilder connectors = new StringBuilder();
+ int connectorCount = 0;
+ for (final ILogin connector : ConnectorFactory.getActiveLiveConnectors()) {
+ connectorCount++;
+ connectors.append("\n - ").append(connector.getName()).append(": ").append(connector.isLoggedIn() ? "logged in" : "not logged in")
+ .append(" (").append(connector.getLoginStatusString()).append(')');
+ if (connector.getName().equals("geocaching.com") && connector.isLoggedIn()) {
+ connectors.append(" / ").append(Settings.getGCMemberStatus());
+ }
+ }
+ body.append("\nGeocaching sites enabled:").append(connectorCount > 0 ? connectors : " none")
+ .append("\nSystem language: ").append(Locale.getDefault());
+ if (Settings.isUseEnglish()) {
+ body.append(" (cgeo forced to English)");
+ }
+ final boolean calendarAddonAvailable = CalendarAddon.isAvailable();
+ final boolean contactsAddonAvailable = ContactsAddon.isAvailable();
+ body.append("\nInstalled cgeo plugins:");
+ if (calendarAddonAvailable || contactsAddonAvailable) {
+ if (calendarAddonAvailable) {
+ body.append(" calendar");
+ }
+ if (contactsAddonAvailable) {
+ body.append(" contacts");
+ }
+ } else {
+ body.append(" none");
+ }
+ body.append("\n--- End of system information ---\n");
+ return body.toString();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/AbstractDialogFragment.java b/main/src/cgeo/geocaching/AbstractDialogFragment.java
index 9277d8c..6e58bd3 100644
--- a/main/src/cgeo/geocaching/AbstractDialogFragment.java
+++ b/main/src/cgeo/geocaching/AbstractDialogFragment.java
@@ -7,10 +7,10 @@ import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.gcvote.GCVote;
import cgeo.geocaching.gcvote.GCVoteRating;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.ui.LoggingUI;
@@ -19,7 +19,7 @@ import cgeo.geocaching.utils.RxUtils;
import rx.Observable;
import rx.Subscription;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.subscriptions.Subscriptions;
@@ -41,7 +41,6 @@ import android.widget.ImageView;
import android.widget.TextView;
public abstract class AbstractDialogFragment extends DialogFragment implements CacheMenuHandler.ActivityInterface, PopupMenu.OnMenuItemClickListener, MenuItem.OnMenuItemClickListener {
- protected CgeoApplication app = null;
protected Resources res = null;
protected String geocode;
protected CacheDetailsCreator details;
@@ -60,7 +59,6 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
res = getResources();
- app = (CgeoApplication) getActivity().getApplication();
setHasOptionsMenu(true);
}
@@ -189,7 +187,7 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
if (!cache.supportsGCVote()) {
return;
}
- AndroidObservable.bindActivity(getActivity(), Observable.defer(new Func0<Observable<GCVoteRating>>() {
+ AppObservable.bindActivity(getActivity(), Observable.defer(new Func0<Observable<GCVoteRating>>() {
@Override
public Observable<GCVoteRating> call() {
final GCVoteRating rating = GCVote.getRating(cache.getGuid(), geocode);
@@ -256,15 +254,15 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
private final GeoDirHandler geoUpdate = new GeoDirHandler() {
@Override
- public void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final GeoData geo) {
try {
- if (geo.getCoords() != null && cache != null && cache.getCoords() != null) {
+ if (cache != null && cache.getCoords() != null) {
cacheDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(cache.getCoords())));
cacheDistance.bringToFront();
}
onUpdateGeoData(geo);
} catch (final RuntimeException e) {
- Log.w("Failed to UpdateLocation location.");
+ Log.w("Failed to update location", e);
}
}
};
@@ -273,7 +271,7 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
* @param geo
* location
*/
- protected void onUpdateGeoData(final IGeoData geo) {
+ protected void onUpdateGeoData(final GeoData geo) {
// do nothing by default
}
@@ -324,7 +322,7 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
try {
CacheMenuHandler.onPrepareOptionsMenu(menu, cache);
LoggingUI.onPrepareOptionsMenu(menu, cache);
- } catch (final RuntimeException e) {
+ } catch (final RuntimeException ignored) {
// nothing
}
}
@@ -342,7 +340,7 @@ public abstract class AbstractDialogFragment extends DialogFragment implements C
showToast(res.getString(R.string.err_location_unknown));
return;
}
- CacheListActivity.startActivityCoordinates((AbstractActivity) getActivity(), coords);
+ CacheListActivity.startActivityCoordinates((AbstractActivity) getActivity(), coords, cache != null ? cache.getName() : null);
getActivity().finish();
}
diff --git a/main/src/cgeo/geocaching/AbstractLoggingActivity.java b/main/src/cgeo/geocaching/AbstractLoggingActivity.java
index 8448e45..cc5546f 100644
--- a/main/src/cgeo/geocaching/AbstractLoggingActivity.java
+++ b/main/src/cgeo/geocaching/AbstractLoggingActivity.java
@@ -2,6 +2,7 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.activity.Keyboard;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCSmiliesProvider;
@@ -11,6 +12,8 @@ import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate;
+import org.apache.commons.lang3.StringUtils;
+
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
@@ -55,6 +58,10 @@ public abstract class AbstractLoggingActivity extends AbstractActionBarActivity
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int id = item.getItemId();
+ if (id == R.id.menu_repeat_last) {
+ replaceLog(getLastLog());
+ return true;
+ }
final LogTemplate template = LogTemplateProvider.getTemplate(id);
if (template != null) {
@@ -71,10 +78,26 @@ public abstract class AbstractLoggingActivity extends AbstractActionBarActivity
return super.onOptionsItemSelected(item);
}
+ /**
+ * @return the last log text used with this logging activity
+ */
+ protected abstract String getLastLog();
+
protected abstract LogContext getLogContext();
protected final void insertIntoLog(final String newText, final boolean moveCursor) {
final EditText log = (EditText) findViewById(R.id.log);
ActivityMixin.insertAtPosition(log, newText, moveCursor);
}
+
+ private void replaceLog(final String newText) {
+ final EditText log = (EditText) findViewById(R.id.log);
+ log.setText(StringUtils.EMPTY);
+ insertIntoLog(newText, true);
+ }
+
+ protected void requestKeyboardForLogging() {
+ new Keyboard(this).show(findViewById(R.id.log));
+ }
+
}
diff --git a/main/src/cgeo/geocaching/AddressListActivity.java b/main/src/cgeo/geocaching/AddressListActivity.java
index dc0239f..4ff48f6 100644
--- a/main/src/cgeo/geocaching/AddressListActivity.java
+++ b/main/src/cgeo/geocaching/AddressListActivity.java
@@ -1,75 +1,55 @@
package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractListActivity;
+import cgeo.geocaching.location.AndroidGeocoder;
+import cgeo.geocaching.location.GCGeocoder;
+import cgeo.geocaching.location.MapQuestGeocoder;
import cgeo.geocaching.ui.AddressListAdapter;
-import cgeo.geocaching.utils.Log;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
+import rx.android.app.AppObservable;
+import rx.functions.Action1;
import android.app.ProgressDialog;
import android.location.Address;
-import android.location.Geocoder;
-import android.os.AsyncTask;
import android.os.Bundle;
import java.util.List;
-import java.util.Locale;
public class AddressListActivity extends AbstractListActivity {
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.addresslist_activity);
- // get parameters
- final String keyword = getIntent().getStringExtra(Intents.EXTRA_KEYWORD);
-
- if (keyword == null) {
- showToast(res.getString(R.string.err_search_address_forgot));
- finish();
- return;
- }
-
final AddressListAdapter adapter = new AddressListAdapter(this);
setListAdapter(adapter);
+ final String keyword = getIntent().getStringExtra(Intents.EXTRA_KEYWORD);
final ProgressDialog waitDialog =
ProgressDialog.show(this, res.getString(R.string.search_address_started), keyword, true);
waitDialog.setCancelable(true);
+ lookupAddressInBackground(keyword, adapter, waitDialog);
+ }
- new AsyncTask<Void, Void, List<Address>>() {
-
+ private void lookupAddressInBackground(final String keyword, final AddressListAdapter adapter, final ProgressDialog waitDialog) {
+ final Observable<Address> geocoderObservable = new AndroidGeocoder(this).getFromLocationName(keyword)
+ .onErrorResumeNext(MapQuestGeocoder.getFromLocationName(keyword))
+ .onErrorResumeNext(GCGeocoder.getFromLocationName(keyword));
+ AppObservable.bindActivity(this, geocoderObservable.toList()).subscribe(new Action1<List<Address>>() {
@Override
- protected List<Address> doInBackground(Void... params) {
- final Geocoder geocoder = new Geocoder(AddressListActivity.this, Locale.getDefault());
- try {
- return geocoder.getFromLocationName(keyword, 20);
- } catch (Exception e) {
- // non Google devices come without the geocoder
- if (StringUtils.containsIgnoreCase(e.getMessage(), "Service not Available")) {
- Log.i("No geocoder available");
- }
- else {
- Log.e("AddressListActivity.doInBackground", e);
- }
- return null;
+ public void call(final List<Address> addresses) {
+ waitDialog.dismiss();
+ for (final Address address : addresses) {
+ adapter.add(address); // don't use addAll, it's only available with API >= 11
}
}
-
+ }, new Action1<Throwable>() {
@Override
- protected void onPostExecute(final List<Address> addresses) {
- waitDialog.dismiss();
- if (CollectionUtils.isNotEmpty(addresses)) {
- for (final Address address : addresses) {
- adapter.add(address); // don't use addAll, it's only available with API >= 11
- }
- } else {
- finish();
- CacheListActivity.startActivityAddress(AddressListActivity.this, null, keyword);
- }
+ public void call(final Throwable throwable) {
+ finish();
+ showToast(res.getString(R.string.err_unknown_address));
}
-
- }.execute();
+ });
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/AttributesGridAdapter.java b/main/src/cgeo/geocaching/AttributesGridAdapter.java
new file mode 100644
index 0000000..fd81339
--- /dev/null
+++ b/main/src/cgeo/geocaching/AttributesGridAdapter.java
@@ -0,0 +1,79 @@
+package cgeo.geocaching;
+
+import cgeo.geocaching.enumerations.CacheAttribute;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.List;
+
+public class AttributesGridAdapter extends BaseAdapter {
+ private final Context context;
+ private final Resources resources;
+ private final List<String> attributes;
+ private final LayoutInflater inflater;
+
+ public AttributesGridAdapter(final Context context, final Geocache cache) {
+ this.context = context;
+ resources = context.getResources();
+ attributes = cache.getAttributes();
+ inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return attributes.size();
+ }
+
+ @Override
+ public Object getItem(final int position) {
+ return attributes.get(position);
+ }
+
+ @Override
+ public long getItemId(final int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+ final FrameLayout attributeLayout;
+ if (convertView == null) {
+ attributeLayout = (FrameLayout) inflater.inflate(R.layout.attribute_image, parent, false);
+ } else {
+ attributeLayout = (FrameLayout) convertView;
+ }
+
+ drawAttribute(attributeLayout, attributes.get(position));
+ return attributeLayout;
+ }
+
+ private void drawAttribute(final FrameLayout attributeLayout, final String attributeName) {
+ final ImageView imageView = (ImageView) attributeLayout.getChildAt(0);
+
+ final boolean strikeThrough = !CacheAttribute.isEnabled(attributeName);
+ final CacheAttribute attrib = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attributeName));
+ if (attrib != null) {
+ Drawable drawable = resources.getDrawable(attrib.drawableId);
+ imageView.setImageDrawable(drawable);
+ if (strikeThrough) {
+ // generate strike through image with same properties as attribute image
+ final ImageView strikeThroughImage = new ImageView(context);
+ strikeThroughImage.setLayoutParams(imageView.getLayoutParams());
+ drawable = resources.getDrawable(R.drawable.attribute__strikethru);
+ strikeThroughImage.setImageDrawable(drawable);
+ attributeLayout.addView(strikeThroughImage);
+ }
+ } else {
+ imageView.setImageDrawable(resources.getDrawable(R.drawable.attribute_unknown));
+ }
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/CacheCache.java b/main/src/cgeo/geocaching/CacheCache.java
index 1913d3c..74e22b5 100644
--- a/main/src/cgeo/geocaching/CacheCache.java
+++ b/main/src/cgeo/geocaching/CacheCache.java
@@ -3,7 +3,7 @@ package cgeo.geocaching;
import cgeo.geocaching.DataStore.StorageLocation;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.LeastRecentlyUsedMap.RemoveHandler;
import cgeo.geocaching.utils.Log;
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java
index 0976b35..4f0c4d2 100644
--- a/main/src/cgeo/geocaching/CacheDetailActivity.java
+++ b/main/src/cgeo/geocaching/CacheDetailActivity.java
@@ -5,29 +5,31 @@ import butterknife.InjectView;
import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.activity.AbstractActivity.ActivitySharingInterface;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
import cgeo.geocaching.activity.INavigationSource;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cache.navi.NavigationSelectionActionProvider;
import cgeo.geocaching.apps.cachelist.MapsWithMeCacheListApp;
-import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.connector.capability.IgnoreCapability;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.enumerations.CacheAttribute;
-import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.gcvote.GCVote;
+import cgeo.geocaching.gcvote.GCVoteDialog;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.network.AndroidBeam;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.SmileyImage;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
@@ -44,7 +46,7 @@ import cgeo.geocaching.ui.OwnerActionsClickListener;
import cgeo.geocaching.ui.WeakReferenceHandler;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.ui.logs.CacheLogsViewCreator;
-import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.CheckerUtils;
import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.ImageUtils;
@@ -66,10 +68,12 @@ import org.eclipse.jdt.annotation.Nullable;
import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
-import rx.android.observables.AndroidObservable;
+import rx.Subscription;
+import rx.android.app.AppObservable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.subscriptions.CompositeSubscription;
+import rx.subscriptions.Subscriptions;
import android.R.color;
import android.app.AlertDialog;
@@ -84,6 +88,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -97,6 +102,7 @@ import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
+import android.text.util.Linkify;
import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.Menu;
@@ -105,16 +111,15 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.FrameLayout;
+import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
+import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TextView.BufferType;
@@ -133,7 +138,7 @@ import java.util.regex.Pattern;
* e.g. details, description, logs, waypoints, inventory...
*/
public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page>
- implements CacheMenuHandler.ActivityInterface, INavigationSource, ActivitySharingInterface, EditNoteDialogListener {
+ implements CacheMenuHandler.ActivityInterface, INavigationSource, AndroidBeam.ActivitySharingInterface, EditNoteDialogListener {
private static final int MESSAGE_FAILED = -1;
private static final int MESSAGE_SUCCEEDED = 1;
@@ -171,6 +176,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
*/
private Waypoint selectedWaypoint;
+ private boolean requireGeodata;
+ private Subscription geoDataSubscription = Subscriptions.empty();
+
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.cachedetail_activity);
@@ -179,12 +187,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// get parameters
final Bundle extras = getIntent().getExtras();
- final Uri uri = getIntent().getData();
+ final Uri uri = AndroidBeam.getUri(getIntent());
// try to get data from extras
String name = null;
String geocode = null;
String guid = null;
+
if (extras != null) {
geocode = extras.getString(Intents.EXTRA_GEOCODE);
name = extras.getString(Intents.EXTRA_NAME);
@@ -196,6 +205,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
geocode = MapsWithMeCacheListApp.getCacheFromMapsWithMe(this, getIntent());
}
+ if (geocode == null && uri != null) {
+ geocode = ConnectorFactory.getGeocodeFromURL(uri.toString());
+ }
+
// try to get data from URI
if (geocode == null && guid == null && uri != null) {
final String uriHost = uri.getHost().toLowerCase(Locale.US);
@@ -227,31 +240,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return;
}
}
- } else if (uriHost.contains("coord.info")) {
- if (StringUtils.startsWith(uriPath, "/gc")) {
- geocode = uriPath.substring(1).toUpperCase(Locale.US);
- } else {
- showToast(res.getString(R.string.err_detail_open));
- finish();
- return;
- }
- } else if (uriHost.contains("opencaching.de")) {
- if (StringUtils.startsWith(uriPath, "/oc")) {
- geocode = uriPath.substring(1).toUpperCase(Locale.US);
- } else {
- geocode = uri.getQueryParameter("wp");
- if (StringUtils.isNotBlank(geocode)) {
- geocode = geocode.toUpperCase(Locale.US);
- } else {
- showToast(res.getString(R.string.err_detail_open));
- finish();
- return;
- }
- }
- } else {
- showToast(res.getString(R.string.err_detail_open));
- finish();
- return;
}
}
@@ -263,7 +251,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
// If we open this cache from a search, let's properly initialize the title bar, even if we don't have cache details
- updateTitleBar(geocode, name, null);
+ setCacheTitleBar(geocode, name, null);
final LoadCacheHandler loadCacheHandler = new LoadCacheHandler(this, progress);
@@ -275,7 +263,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
title = geocode;
}
progress.show(this, title, res.getString(R.string.cache_dialog_loading_details), true, loadCacheHandler.cancelMessage());
- } catch (final RuntimeException e) {
+ } catch (final RuntimeException ignored) {
// nothing, we lost the window
}
@@ -293,8 +281,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (getPage(position) == Page.IMAGES) {
loadCacheImages();
}
+ requireGeodata = getPage(position) == Page.DETAILS;
+ startOrStopGeoDataListener();
+
+ // cancel contextual actions on page change
+ if (currentActionMode != null) {
+ currentActionMode.finish();
+ }
}
});
+ requireGeodata = pageToOpen == 1;
final String realGeocode = geocode;
final String realGuid = guid;
@@ -309,10 +305,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
locationUpdater = new CacheDetailsGeoDirHandler(this);
// If we have a newer Android device setup Android Beam for easy cache sharing
- initializeAndroidBeam(this);
+ AndroidBeam.enable(this, this);
}
@Override
+ @Nullable
public String getAndroidBeamUri() {
return cache != null ? cache.getCgeoUrl() : null;
}
@@ -323,9 +320,17 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
outState.putInt(STATE_PAGE_INDEX, getCurrentItem());
}
+ private void startOrStopGeoDataListener() {
+ geoDataSubscription.unsubscribe();
+ if (requireGeodata) {
+ geoDataSubscription = locationUpdater.start(GeoDirHandler.UPDATE_GEODATA);
+ }
+ }
+
@Override
public void onResume() {
- super.onResume(locationUpdater.start(GeoDirHandler.UPDATE_GEODATA));
+ super.onResume();
+ startOrStopGeoDataListener();
if (refreshOnResume) {
notifyDataSetChanged();
@@ -334,6 +339,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
@Override
+ public void onPause() {
+ geoDataSubscription.unsubscribe();
+ super.onPause();
+ }
+
+ @Override
public void onDestroy() {
createSubscriptions.unsubscribe();
super.onDestroy();
@@ -389,17 +400,43 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return true;
case R.id.menu_waypoint_duplicate:
ensureSaved();
- if (cache.duplicateWaypoint(selectedWaypoint)) {
- DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
- notifyDataSetChanged();
- }
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(final Void... params) {
+ if (cache.duplicateWaypoint(selectedWaypoint)) {
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onPostExecute(final Boolean result) {
+ if (result) {
+ notifyDataSetChanged();
+ }
+ }
+ }.execute();
return true;
case R.id.menu_waypoint_delete:
ensureSaved();
- if (cache.deleteWaypoint(selectedWaypoint)) {
- DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
- notifyDataSetChanged();
- }
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(final Void... params) {
+ if (cache.deleteWaypoint(selectedWaypoint)) {
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onPostExecute(final Boolean result) {
+ if (result) {
+ notifyDataSetChanged();
+ }
+ }
+ }.execute();
return true;
case R.id.menu_waypoint_navigate_default:
if (selectedWaypoint != null) {
@@ -413,17 +450,17 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return true;
case R.id.menu_waypoint_caches_around:
if (selectedWaypoint != null) {
- CacheListActivity.startActivityCoordinates(this, selectedWaypoint.getCoords());
+ CacheListActivity.startActivityCoordinates(this, selectedWaypoint.getCoords(), selectedWaypoint.getName());
}
return true;
case R.id.menu_waypoint_reset_cache_coords:
ensureSaved();
if (ConnectorFactory.getConnector(cache).supportsOwnCoordinates()) {
- createResetCacheCoordinatesDialog(cache, selectedWaypoint).show();
+ createResetCacheCoordinatesDialog(selectedWaypoint).show();
} else {
final ProgressDialog progressDialog = ProgressDialog.show(this, getString(R.string.cache), getString(R.string.waypoint_reset), true);
final HandlerResetCoordinates handler = new HandlerResetCoordinates(this, progressDialog, false);
- new ResetCoordsThread(cache, handler, selectedWaypoint, true, false, progressDialog).start();
+ resetCoords(cache, handler, selectedWaypoint, true, false, progressDialog);
}
return true;
case R.id.menu_calendar:
@@ -441,13 +478,12 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
CacheMenuHandler.addMenuItems(this, menu, cache);
- MenuItem menuItem = menu.findItem(R.id.menu_default_navigation);
+ final MenuItem menuItem = menu.findItem(R.id.menu_default_navigation);
final NavigationActionProvider navAction = (NavigationActionProvider) MenuItemCompat.getActionProvider(menuItem);
if (navAction != null) {
navAction.setNavigationSource(this);
}
- menuItem = menu.findItem(R.id.menu_navigate);
- NavigationSelectionActionProvider.initialize(menuItem, cache);
+ NavigationSelectionActionProvider.initialize(menu.findItem(R.id.menu_navigate), cache);
return true;
}
@@ -458,6 +494,18 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
menu.findItem(R.id.menu_store).setVisible(cache != null && !cache.isOffline());
menu.findItem(R.id.menu_delete).setVisible(cache != null && cache.isOffline());
menu.findItem(R.id.menu_refresh).setVisible(cache != null && cache.isOffline());
+ menu.findItem(R.id.menu_gcvote).setVisible(cache != null && GCVote.isVotingPossible(cache));
+ menu.findItem(R.id.menu_checker).setVisible(cache != null && StringUtils.isNotEmpty(CheckerUtils.getCheckerUrl(cache)));
+ // Comment out ignoring capabilities for this release, as this feature needs to be polished and accessible from
+ // other places as well as undo-able.
+ /*
+ if (cache != null) {
+ final IConnector connector = ConnectorFactory.getConnector(cache);
+ if (connector instanceof IgnoreCapability) {
+ menu.findItem(R.id.menu_ignore).setVisible(((IgnoreCapability) connector).canIgnoreCache(cache));
+ }
+ }
+ */
return super.onPrepareOptionsMenu(menu);
}
@@ -479,6 +527,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
case R.id.menu_refresh:
refreshCache();
return true;
+ case R.id.menu_gcvote:
+ showVoteDialog();
+ return true;
+ case R.id.menu_checker:
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(CheckerUtils.getCheckerUrl(cache))));
+ return true;
+ case R.id.menu_ignore:
+ ignoreCache();
+ return true;
default:
if (NavigationAppFactory.onMenuItemSelected(item, this, cache)) {
return true;
@@ -492,6 +549,24 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return super.onOptionsItemSelected(item);
}
+ private void ignoreCache() {
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ ((IgnoreCapability) ConnectorFactory.getConnector(cache)).ignoreCache(cache);
+ }
+ });
+ }
+
+ private void showVoteDialog() {
+ GCVoteDialog.show(this, cache, new Runnable() {
+ @Override
+ public void run() {
+ notifyDataSetChanged();
+ }
+ });
+ }
+
private static final class CacheDetailsGeoDirHandler extends GeoDirHandler {
private final WeakReference<CacheDetailActivity> activityRef;
@@ -500,7 +575,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
@Override
- public void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final GeoData geo) {
final CacheDetailActivity activity = activityRef.get();
if (activity == null) {
return;
@@ -509,7 +584,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return;
}
- if (geo.getCoords() != null && activity.cache != null && activity.cache.getCoords() != null) {
+ if (activity.cache != null && activity.cache.getCoords() != null) {
activity.cacheDistanceView.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(activity.cache.getCoords())));
activity.cacheDistanceView.bringToFront();
}
@@ -570,7 +645,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
private void notifyDataSetChanged() {
- // This might get called asynchronically when the activity is shut down
+ // This might get called asynchronous when the activity is shut down
if (isFinishing()) {
return;
}
@@ -591,7 +666,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// allow cache to notify CacheDetailActivity when it changes so it can be reloaded
cache.setChangeNotificationHandler(new ChangeNotificationHandler(this, progress));
- updateTitleBar(cache.getGeocode(), cache.getName(), cache.getType());
+ setCacheTitleBar(cache);
// reset imagesList so Images view page will be redrawn
imagesList = null;
@@ -604,19 +679,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
Settings.addCacheToHistory(cache.getGeocode());
}
- private void updateTitleBar(@Nullable final String geocode, @Nullable final String name, @Nullable final CacheType type) {
- if (StringUtils.isNotBlank(name)) {
- setTitle(StringUtils.isNotBlank(geocode) ? name + " (" + geocode + ")" : name);
- } else {
- setTitle(StringUtils.isNotBlank(geocode) ? geocode : res.getString(R.string.cache));
- }
- if (type != null) {
- getSupportActionBar().setIcon(getResources().getDrawable(type.markerId));
- } else {
- getSupportActionBar().setIcon(android.R.color.transparent);
- }
- }
-
/**
* Tries to navigate to the {@link Geocache} of this activity using the default navigation tool.
*/
@@ -688,193 +750,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
}
- private class AttributeViewBuilder {
- private ViewGroup attributeIconsLayout; // layout for attribute icons
- private ViewGroup attributeDescriptionsLayout; // layout for attribute descriptions
- private boolean attributesShowAsIcons = true; // default: show icons
- /**
- * If the cache is from a non GC source, it might be without icons. Disable switching in those cases.
- */
- private boolean noAttributeIconsFound = false;
- private int attributeBoxMaxWidth;
-
- public void fillView(final LinearLayout attributeBox) {
- // first ensure that the view is empty
- attributeBox.removeAllViews();
-
- // maximum width for attribute icons is screen width - paddings of parents
- attributeBoxMaxWidth = Compatibility.getDisplayWidth();
- ViewParent child = attributeBox;
- do {
- if (child instanceof View) {
- attributeBoxMaxWidth -= ((View) child).getPaddingLeft() + ((View) child).getPaddingRight();
- }
- child = child.getParent();
- } while (child != null);
-
- // delete views holding description / icons
- attributeDescriptionsLayout = null;
- attributeIconsLayout = null;
-
- attributeBox.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(final View v) {
- // toggle between attribute icons and descriptions
- toggleAttributeDisplay(attributeBox, attributeBoxMaxWidth);
- }
- });
-
- // icons or text?
- //
- // also show icons when noAttributeImagesFound == true. Explanation:
- // 1. no icons could be found in the first invocation of this method
- // 2. user refreshes cache from web
- // 3. now this method is called again
- // 4. attributeShowAsIcons is false but noAttributeImagesFound is true
- // => try to show them now
- if (attributesShowAsIcons || noAttributeIconsFound) {
- showAttributeIcons(attributeBox, attributeBoxMaxWidth);
- } else {
- showAttributeDescriptions(attributeBox);
- }
- }
-
- /**
- * lazy-creates the layout holding the icons of the caches attributes
- * and makes it visible
- */
- private void showAttributeIcons(final LinearLayout attribBox, final int parentWidth) {
- if (attributeIconsLayout == null) {
- attributeIconsLayout = createAttributeIconsLayout(parentWidth);
- // no matching icons found? show text
- if (noAttributeIconsFound) {
- showAttributeDescriptions(attribBox);
- return;
- }
- }
- attribBox.removeAllViews();
- attribBox.addView(attributeIconsLayout);
- attributesShowAsIcons = true;
- }
-
- /**
- * lazy-creates the layout holding the descriptions of the caches attributes
- * and makes it visible
- */
- private void showAttributeDescriptions(final LinearLayout attribBox) {
- if (attributeDescriptionsLayout == null) {
- attributeDescriptionsLayout = createAttributeDescriptionsLayout(attribBox);
- }
- attribBox.removeAllViews();
- attribBox.addView(attributeDescriptionsLayout);
- attributesShowAsIcons = false;
- }
-
- /**
- * toggle attribute descriptions and icons
- */
- private void toggleAttributeDisplay(final LinearLayout attribBox, final int parentWidth) {
- // Don't toggle when there are no icons to show.
- if (noAttributeIconsFound) {
- return;
- }
-
- // toggle
- if (attributesShowAsIcons) {
- showAttributeDescriptions(attribBox);
- } else {
- showAttributeIcons(attribBox, parentWidth);
- }
- }
-
- private ViewGroup createAttributeIconsLayout(final int parentWidth) {
- final LinearLayout rows = new LinearLayout(CacheDetailActivity.this);
- rows.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
- rows.setOrientation(LinearLayout.VERTICAL);
-
- LinearLayout attributeRow = newAttributeIconsRow();
- rows.addView(attributeRow);
-
- noAttributeIconsFound = true;
-
- for (final String attributeName : cache.getAttributes()) {
- // check if another attribute icon fits in this row
- attributeRow.measure(0, 0);
- final int rowWidth = attributeRow.getMeasuredWidth();
- final FrameLayout fl = (FrameLayout) getLayoutInflater().inflate(R.layout.attribute_image, attributeRow, false);
- final ImageView iv = (ImageView) fl.getChildAt(0);
- if ((parentWidth - rowWidth) < iv.getLayoutParams().width) {
- // make a new row
- attributeRow = newAttributeIconsRow();
- rows.addView(attributeRow);
- }
-
- final boolean strikeThrough = !CacheAttribute.isEnabled(attributeName);
- final CacheAttribute attrib = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attributeName));
- if (attrib != null) {
- noAttributeIconsFound = false;
- Drawable d = res.getDrawable(attrib.drawableId);
- iv.setImageDrawable(d);
- // strike through?
- if (strikeThrough) {
- // generate strike through image with same properties as attribute image
- final ImageView strikeThroughImage = new ImageView(CacheDetailActivity.this);
- strikeThroughImage.setLayoutParams(iv.getLayoutParams());
- d = res.getDrawable(R.drawable.attribute__strikethru);
- strikeThroughImage.setImageDrawable(d);
- fl.addView(strikeThroughImage);
- }
- } else {
- final Drawable d = res.getDrawable(R.drawable.attribute_unknown);
- iv.setImageDrawable(d);
- }
-
- attributeRow.addView(fl);
- }
-
- return rows;
- }
-
- private LinearLayout newAttributeIconsRow() {
- final LinearLayout rowLayout = new LinearLayout(CacheDetailActivity.this);
- rowLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT));
- rowLayout.setOrientation(LinearLayout.HORIZONTAL);
- return rowLayout;
- }
-
- private ViewGroup createAttributeDescriptionsLayout(final LinearLayout parentView) {
- final LinearLayout descriptions = (LinearLayout) getLayoutInflater().inflate(
- R.layout.attribute_descriptions, parentView, false);
- final TextView attribView = (TextView) descriptions.getChildAt(0);
-
- final StringBuilder buffer = new StringBuilder();
- for (String attributeName : cache.getAttributes()) {
- final boolean enabled = CacheAttribute.isEnabled(attributeName);
- // search for a translation of the attribute
- final CacheAttribute attrib = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attributeName));
- if (attrib != null) {
- attributeName = attrib.getL10n(enabled);
- }
- if (buffer.length() > 0) {
- buffer.append('\n');
- }
- buffer.append(attributeName);
- }
-
- attribView.setText(buffer);
-
- return descriptions;
- }
- }
-
private void refreshCache() {
if (progress.isShowing()) {
showToast(res.getString(R.string.err_detail_still_working));
return;
}
- if (!Network.isNetworkConnected(getApplicationContext())) {
+ if (!Network.isNetworkConnected()) {
showToast(getString(R.string.err_server));
return;
}
@@ -883,7 +765,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
progress.show(this, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true, refreshCacheHandler.cancelMessage());
- cache.refresh(refreshCacheHandler, RxUtils.networkScheduler);
+ cache.refresh(refreshCacheHandler, RxUtils.refreshScheduler);
}
private void dropCache() {
@@ -893,7 +775,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
progress.show(this, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true, null);
- cache.drop(new ChangeNotificationHandler(this, progress), RxUtils.networkScheduler);
+ cache.drop(new ChangeNotificationHandler(this, progress));
}
private void storeCache() {
@@ -910,9 +792,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
public void call(final Integer selectedListId) {
storeCache(selectedListId, new StoreCacheHandler(CacheDetailActivity.this, progress));
}
- }, true, StoredList.TEMPORARY_LIST_ID);
+ }, true, StoredList.TEMPORARY_LIST.id);
} else {
- storeCache(StoredList.TEMPORARY_LIST_ID, new StoreCacheHandler(this, progress));
+ storeCache(StoredList.TEMPORARY_LIST.id, new StoreCacheHandler(this, progress));
}
}
@@ -920,12 +802,9 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
* Creator for details-view.
*/
private class DetailsViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
- /**
- * Reference to the details list, so that the helper-method can access it without an additional argument
- */
+ // Reference to the details list and favorite line, so that the helper-method can access them without an additional argument
private LinearLayout detailsList;
-
- private Thread watchlistThread;
+ private ImmutablePair<RelativeLayout, TextView> favoriteLine;
@Override
public ScrollView getDispatchedView(final ViewGroup parentView) {
@@ -937,7 +816,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_details_page, parentView, false);
// Start loading preview map
- AndroidObservable.bindActivity(CacheDetailActivity.this, previewMap).subscribeOn(RxUtils.networkScheduler)
+ AppObservable.bindActivity(CacheDetailActivity.this, previewMap).subscribeOn(RxUtils.networkScheduler)
.subscribe(new Action1<BitmapDrawable>() {
@Override
public void call(final BitmapDrawable image) {
@@ -962,10 +841,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
span.setSpan(new ForegroundColorSpan(res.getColor(R.color.archived_cache_color)), 0, span.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- addContextMenu(details.add(R.string.cache_name, span));
+ addContextMenu(details.add(R.string.cache_name, span).right);
details.add(R.string.cache_type, cache.getType().getL10n());
details.addSize(cache);
- addContextMenu(details.add(R.string.cache_geocode, cache.getGeocode()));
+ addContextMenu(details.add(R.string.cache_geocode, cache.getGeocode()).right);
details.addCacheState(cache);
details.addDistance(cache, cacheDistanceView);
@@ -976,9 +855,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
details.addRating(cache);
// favorite count
- if (cache.getFavoritePoints() > 0) {
- details.add(R.string.cache_favorite, cache.getFavoritePoints() + "×");
- }
+ favoriteLine = details.add(R.string.cache_favorite, "");
// own rating
if (cache.getMyVote() > 0) {
@@ -987,7 +864,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache author
if (StringUtils.isNotBlank(cache.getOwnerDisplayName()) || StringUtils.isNotBlank(cache.getOwnerUserId())) {
- final TextView ownerView = details.add(R.string.cache_owner, "");
+ final TextView ownerView = details.add(R.string.cache_owner, "").right;
if (StringUtils.isNotBlank(cache.getOwnerDisplayName())) {
ownerView.setText(cache.getOwnerDisplayName(), TextView.BufferType.SPANNABLE);
} else { // OwnerReal guaranteed to be not blank based on above
@@ -1009,17 +886,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// cache coordinates
if (cache.getCoords() != null) {
- final TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString());
+ final TextView valueView = details.add(R.string.cache_coordinates, cache.getCoords().toString()).right;
valueView.setOnClickListener(new CoordinatesFormatSwitcher(cache.getCoords()));
addContextMenu(valueView);
}
// cache attributes
- if (!cache.getAttributes().isEmpty()) {
- final LinearLayout innerLayout = ButterKnife.findById(view, R.id.attributes_innerbox);
- new AttributeViewBuilder().fillView(innerLayout);
- view.findViewById(R.id.attributes_box).setVisibility(View.VISIBLE);
- }
+ updateAttributesText();
+ updateAttributesIcons();
+ ButterKnife.findById(view, R.id.attributes_box).setVisibility(cache.getAttributes().isEmpty() ? View.GONE : View.VISIBLE);
updateOfflineBox(view, cache, res, new RefreshCacheClickListener(), new DropCacheClickListener(), new StoreCacheClickListener());
@@ -1058,6 +933,61 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return view;
}
+ private void updateAttributesIcons() {
+ final GridView gridView = ButterKnife.findById(view, R.id.attributes_grid);
+ final List<String> attributes = cache.getAttributes();
+ if (attributes.isEmpty()) {
+ gridView.setVisibility(View.GONE);
+ return;
+ }
+ gridView.setAdapter(new AttributesGridAdapter(CacheDetailActivity.this, cache));
+ gridView.setVisibility(View.VISIBLE);
+ gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(final android.widget.AdapterView<?> parent, final View view, final int position, final long id) {
+ toggleAttributesView();
+ }
+ });
+ }
+
+ protected void toggleAttributesView() {
+ final View textView = ButterKnife.findById(view, R.id.attributes_text);
+ textView.setVisibility(textView.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
+ final View gridView = ButterKnife.findById(view, R.id.attributes_grid);
+ gridView.setVisibility(gridView.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
+ }
+
+ private void updateAttributesText() {
+ final TextView attribView = ButterKnife.findById(view, R.id.attributes_text);
+ final List<String> attributes = cache.getAttributes();
+ if (attributes.isEmpty()) {
+ attribView.setVisibility(View.GONE);
+ return;
+ }
+ final StringBuilder text = new StringBuilder();
+ for (String attributeName : attributes) {
+ final boolean enabled = CacheAttribute.isEnabled(attributeName);
+ // search for a translation of the attribute
+ final CacheAttribute attrib = CacheAttribute.getByRawName(CacheAttribute.trimAttributeName(attributeName));
+ if (attrib != null) {
+ attributeName = attrib.getL10n(enabled);
+ }
+ if (text.length() > 0) {
+ text.append('\n');
+ }
+ text.append(attributeName);
+ }
+ attribView.setText(text);
+ attribView.setVisibility(View.GONE);
+ attribView.setOnClickListener(new OnClickListener() {
+
+ @Override
+ public void onClick(final View v) {
+ toggleAttributesView();
+ }
+ });
+ }
+
private class StoreCacheClickListener implements View.OnClickListener {
@Override
public void onClick(final View arg0) {
@@ -1083,164 +1013,133 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
/**
* Abstract Listener for add / remove buttons for watchlist
*/
- private abstract class AbstractWatchlistClickListener implements View.OnClickListener {
- public void doExecute(final int titleId, final int messageId, final Thread thread) {
+ private abstract class AbstractPropertyListener implements View.OnClickListener {
+
+ private final SimpleCancellableHandler handler = new SimpleCancellableHandler(CacheDetailActivity.this, progress) {
+ @Override
+ public void handleRegularMessage(final Message message) {
+ super.handleRegularMessage(message);
+ updateWatchlistBox();
+ updateFavPointBox();
+ }
+ };
+
+ public void doExecute(final int titleId, final int messageId, final Action1<SimpleCancellableHandler> action) {
if (progress.isShowing()) {
showToast(res.getString(R.string.err_watchlist_still_managing));
return;
}
progress.show(CacheDetailActivity.this, res.getString(titleId), res.getString(messageId), true, null);
-
- if (watchlistThread != null) {
- watchlistThread.interrupt();
- }
-
- watchlistThread = thread;
- watchlistThread.start();
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ action.call(handler);
+ }
+ });
}
}
/**
* Listener for "add to watchlist" button
*/
- private class AddToWatchlistClickListener extends AbstractWatchlistClickListener {
+ private class AddToWatchlistClickListener extends AbstractPropertyListener {
@Override
public void onClick(final View arg0) {
doExecute(R.string.cache_dialog_watchlist_add_title,
R.string.cache_dialog_watchlist_add_message,
- new WatchlistAddThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress)));
+ new Action1<SimpleCancellableHandler>() {
+ @Override
+ public void call(final SimpleCancellableHandler simpleCancellableHandler) {
+ watchListAdd(simpleCancellableHandler);
+ }
+ });
}
}
/**
* Listener for "remove from watchlist" button
*/
- private class RemoveFromWatchlistClickListener extends AbstractWatchlistClickListener {
+ private class RemoveFromWatchlistClickListener extends AbstractPropertyListener {
@Override
public void onClick(final View arg0) {
doExecute(R.string.cache_dialog_watchlist_remove_title,
R.string.cache_dialog_watchlist_remove_message,
- new WatchlistRemoveThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress)));
+ new Action1<SimpleCancellableHandler>() {
+ @Override
+ public void call(final SimpleCancellableHandler simpleCancellableHandler) {
+ watchListRemove(simpleCancellableHandler);
+ }
+ });
}
}
- /** Thread to add this cache to the watchlist of the user */
- private class WatchlistAddThread extends Thread {
- private final Handler handler;
-
- public WatchlistAddThread(final Handler handler) {
- this.handler = handler;
- }
-
- @Override
- public void run() {
- watchlistThread = null;
- Message msg;
- if (ConnectorFactory.getConnector(cache).addToWatchlist(cache)) {
- msg = Message.obtain(handler, MESSAGE_SUCCEEDED);
- } else {
- msg = Message.obtain(handler, MESSAGE_FAILED);
- final Bundle bundle = new Bundle();
- bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_watchlist_failed));
- msg.setData(bundle);
- }
- handler.sendMessage(msg);
+ /** Add this cache to the watchlist of the user */
+ private void watchListAdd(final SimpleCancellableHandler handler) {
+ if (ConnectorFactory.getConnector(cache).addToWatchlist(cache)) {
+ handler.obtainMessage(MESSAGE_SUCCEEDED).sendToTarget();
+ } else {
+ handler.sendTextMessage(MESSAGE_FAILED, R.string.err_watchlist_failed);
}
}
- /** Thread to remove this cache from the watchlist of the user */
- private class WatchlistRemoveThread extends Thread {
- private final Handler handler;
-
- public WatchlistRemoveThread(final Handler handler) {
- this.handler = handler;
- }
-
- @Override
- public void run() {
- watchlistThread = null;
- Message msg;
- if (ConnectorFactory.getConnector(cache).removeFromWatchlist(cache)) {
- msg = Message.obtain(handler, MESSAGE_SUCCEEDED);
- } else {
- msg = Message.obtain(handler, MESSAGE_FAILED);
- final Bundle bundle = new Bundle();
- bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_watchlist_failed));
- msg.setData(bundle);
- }
- handler.sendMessage(msg);
+ /** Remove this cache from the watchlist of the user */
+ private void watchListRemove(final SimpleCancellableHandler handler) {
+ if (ConnectorFactory.getConnector(cache).removeFromWatchlist(cache)) {
+ handler.obtainMessage(MESSAGE_SUCCEEDED).sendToTarget();
+ } else {
+ handler.sendTextMessage(MESSAGE_FAILED, R.string.err_watchlist_failed);
}
}
- /** Thread to add this cache to the favorite list of the user */
- private class FavoriteAddThread extends Thread {
- private final Handler handler;
-
- public FavoriteAddThread(final Handler handler) {
- this.handler = handler;
- }
-
- @Override
- public void run() {
- watchlistThread = null;
- Message msg;
- if (GCConnector.addToFavorites(cache)) {
- msg = Message.obtain(handler, MESSAGE_SUCCEEDED);
- } else {
- msg = Message.obtain(handler, MESSAGE_FAILED);
- final Bundle bundle = new Bundle();
- bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_favorite_failed));
- msg.setData(bundle);
- }
- handler.sendMessage(msg);
+ /** Add this cache to the favorite list of the user */
+ private void favoriteAdd(final SimpleCancellableHandler handler) {
+ if (GCConnector.addToFavorites(cache)) {
+ handler.obtainMessage(MESSAGE_SUCCEEDED).sendToTarget();
+ } else {
+ handler.sendTextMessage(MESSAGE_FAILED, R.string.err_favorite_failed);
}
}
- /** Thread to remove this cache to the favorite list of the user */
- private class FavoriteRemoveThread extends Thread {
- private final Handler handler;
-
- public FavoriteRemoveThread(final Handler handler) {
- this.handler = handler;
- }
-
- @Override
- public void run() {
- watchlistThread = null;
- Message msg;
- if (GCConnector.removeFromFavorites(cache)) {
- msg = Message.obtain(handler, MESSAGE_SUCCEEDED);
- } else {
- msg = Message.obtain(handler, MESSAGE_FAILED);
- final Bundle bundle = new Bundle();
- bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, res.getString(R.string.err_favorite_failed));
- msg.setData(bundle);
- }
- handler.sendMessage(msg);
+ /** Remove this cache to the favorite list of the user */
+ private void favoriteRemove(final SimpleCancellableHandler handler) {
+ if (GCConnector.removeFromFavorites(cache)) {
+ handler.obtainMessage(MESSAGE_SUCCEEDED).sendToTarget();
+ } else {
+ handler.sendTextMessage(MESSAGE_FAILED, R.string.err_favorite_failed);
}
}
/**
* Listener for "add to favorites" button
*/
- private class FavoriteAddClickListener extends AbstractWatchlistClickListener {
+ private class FavoriteAddClickListener extends AbstractPropertyListener {
@Override
public void onClick(final View arg0) {
doExecute(R.string.cache_dialog_favorite_add_title,
R.string.cache_dialog_favorite_add_message,
- new FavoriteAddThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress)));
+ new Action1<SimpleCancellableHandler>() {
+ @Override
+ public void call(final SimpleCancellableHandler simpleCancellableHandler) {
+ favoriteAdd(simpleCancellableHandler);
+ }
+ });
}
}
/**
* Listener for "remove from favorites" button
*/
- private class FavoriteRemoveClickListener extends AbstractWatchlistClickListener {
+ private class FavoriteRemoveClickListener extends AbstractPropertyListener {
@Override
public void onClick(final View arg0) {
doExecute(R.string.cache_dialog_favorite_remove_title,
R.string.cache_dialog_favorite_remove_message,
- new FavoriteRemoveThread(new SimpleUpdateHandler(CacheDetailActivity.this, progress)));
+ new Action1<SimpleCancellableHandler>() {
+ @Override
+ public void call(final SimpleCancellableHandler simpleCancellableHandler) {
+ favoriteRemove(simpleCancellableHandler);
+ }
+ });
}
}
@@ -1249,7 +1148,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
*/
private class ChangeListClickListener implements View.OnClickListener {
@Override
- public void onClick(final View view) {
+ public void onClick(final View v) {
new StoredList.UserInterface(CacheDetailActivity.this).promptForListSelection(R.string.list_title,
new Action1<Integer>() {
@Override
@@ -1277,7 +1176,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
/**
- * shows/hides buttons, sets text in watchlist box
+ * Show/hide buttons, set text in watchlist box
*/
private void updateWatchlistBox() {
final LinearLayout layout = ButterKnife.findById(view, R.id.watchlist_box);
@@ -1307,13 +1206,20 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
buttonRemove.setEnabled(false);
buttonRemove.setVisibility(View.GONE);
}
-
}
/**
- * shows/hides buttons, sets text in watchlist box
+ * Show/hide buttons, set text in favorite line and box
*/
private void updateFavPointBox() {
+ // Favorite counts
+ if (cache.getFavoritePoints() > 0) {
+ favoriteLine.left.setVisibility(View.VISIBLE);
+ favoriteLine.right.setText(cache.getFavoritePoints() + "×");
+ } else {
+ favoriteLine.left.setVisibility(View.GONE);
+ }
+
final LinearLayout layout = ButterKnife.findById(view, R.id.favpoint_box);
final boolean supportsFavoritePoints = cache.supportsFavoritePoints();
layout.setVisibility(supportsFavoritePoints ? View.VISIBLE : View.GONE);
@@ -1356,12 +1262,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
// update text
final TextView text = ButterKnife.findById(view, R.id.list_text);
final StoredList list = DataStore.getList(cache.getListId());
- if (list != null) {
- text.setText(res.getString(R.string.cache_list_text) + " " + list.title);
- } else {
- // this should not happen
- text.setText(R.string.cache_list_unknown);
- }
+ text.setText(res.getString(R.string.cache_list_text) + " " + list.title);
} else {
// hide box
box.setVisibility(View.GONE);
@@ -1395,6 +1296,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
});
+ /**
+ * Reflect the (contextual) action mode of the action bar.
+ */
+ protected ActionMode currentActionMode;
+
protected class DescriptionViewCreator extends AbstractCachingPageViewCreator<ScrollView> {
@InjectView(R.id.personalnote) protected TextView personalNoteView;
@@ -1517,19 +1423,26 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
return view;
}
- Thread currentThread;
-
private void uploadPersonalNote() {
final SimpleCancellableHandler myHandler = new SimpleCancellableHandler(CacheDetailActivity.this, progress);
final Message cancelMessage = myHandler.cancelMessage(res.getString(R.string.cache_personal_note_upload_cancelled));
progress.show(CacheDetailActivity.this, res.getString(R.string.cache_personal_note_uploading), res.getString(R.string.cache_personal_note_uploading), true, cancelMessage);
- if (currentThread != null) {
- currentThread.interrupt();
- }
- currentThread = new UploadPersonalNoteThread(cache, myHandler);
- currentThread.start();
+ myHandler.unsubscribeIfCancelled(RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ final IConnector con = ConnectorFactory.getConnector(cache);
+ if (con.supportsPersonalNote()) {
+ con.uploadPersonalNote(cache);
+ }
+ final Message msg = Message.obtain();
+ final Bundle bundle = new Bundle();
+ bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, CgeoApplication.getInstance().getString(R.string.cache_personal_note_upload_done));
+ msg.setData(bundle);
+ myHandler.sendMessage(msg);
+ }
+ }));
}
private void loadLongDescription() {
@@ -1563,9 +1476,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
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);
+ if (StringUtils.isNotEmpty(cache.getUrl())) {
+ 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);
+ }
}
}
/**
@@ -1597,13 +1512,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (null != loadingIndicatorView) {
loadingIndicatorView.setVisibility(View.GONE);
}
- } catch (final Exception e) {
+ } catch (final Exception ignored) {
showToast(res.getString(R.string.err_load_descr_failed));
}
}
private static void fixTextColor(final String descriptionString, final IndexOutOfBoundsAvoidingTextView descriptionView) {
- int backcolor;
+ final int backcolor;
if (Settings.isLightSkin()) {
backcolor = color.white;
@@ -1653,12 +1568,18 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (!cache.isOffline()) {
showToast(getString(R.string.info_cache_saved));
cache.setListId(StoredList.STANDARD_LIST_ID);
- DataStore.saveCache(cache, LoadFlags.SAVE_ALL);
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ DataStore.saveCache(cache, LoadFlags.SAVE_ALL);
+ return null;
+ }
+ }.execute();
}
}
private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> {
- private final int VISITED_INSET = (int) (6.6f * CgeoApplication.getInstance().getResources().getDisplayMetrics().density + 0.5f);
+ private final int visitedInset = (int) (6.6f * CgeoApplication.getInstance().getResources().getDisplayMetrics().density + 0.5f);
@Override
public ListView getDispatchedView(final ViewGroup parentView) {
@@ -1741,15 +1662,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
} else {
nameView.setText(res.getString(R.string.waypoint));
}
- setWaypointIcon(res, nameView, wpt);
+ setWaypointIcon(nameView, wpt);
// visited
if (wpt.isVisited()) {
- final TypedValue a = new TypedValue();
- getTheme().resolveAttribute(R.attr.text_color_grey, a, true);
- if (a.type >= TypedValue.TYPE_FIRST_COLOR_INT && a.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ final TypedValue typedValue = new TypedValue();
+ getTheme().resolveAttribute(R.attr.text_color_grey, typedValue, true);
+ if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
// really should be just a color!
- nameView.setTextColor(a.data);
+ nameView.setTextColor(typedValue.data);
}
}
@@ -1759,7 +1680,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
noteView.setOnClickListener(new DecryptTextClickListener(noteView));
noteView.setVisibility(View.VISIBLE);
if (TextUtils.containsHtml(wpt.getNote())) {
- noteView.setText(Html.fromHtml(wpt.getNote()), TextView.BufferType.SPANNABLE);
+ noteView.setText(Html.fromHtml(wpt.getNote(), new SmileyImage(cache.getGeocode(), noteView), new UnknownTagsHandler()), TextView.BufferType.SPANNABLE);
}
else {
noteView.setText(wpt.getNote());
@@ -1805,15 +1726,15 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
});
}
- private void setWaypointIcon(final Resources res, final TextView nameView, final Waypoint wpt) {
+ private void setWaypointIcon(final TextView nameView, final Waypoint wpt) {
final WaypointType waypointType = wpt.getWaypointType();
final Drawable icon;
if (wpt.isVisited()) {
final LayerDrawable ld = new LayerDrawable(new Drawable[] {
res.getDrawable(waypointType.markerId),
res.getDrawable(R.drawable.tick) });
- ld.setLayerInset(0, 0, 0, VISITED_INSET, VISITED_INSET);
- ld.setLayerInset(1, VISITED_INSET, VISITED_INSET, 0, 0);
+ ld.setLayerInset(0, 0, 0, visitedInset, visitedInset);
+ ld.setLayerInset(1, visitedInset, visitedInset, 0, 0);
icon = ld;
} else {
icon = res.getDrawable(waypointType.markerId);
@@ -1880,10 +1801,14 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public boolean onLongClick(final View v) {
- startSupportActionMode(new ActionMode.Callback() {
+ currentActionMode = startSupportActionMode(new ActionMode.Callback() {
@Override
public boolean onPrepareActionMode(final ActionMode actionMode, final Menu menu) {
+ return prepareClipboardActionMode(view, actionMode, menu);
+ }
+
+ private boolean prepareClipboardActionMode(final View view, final ActionMode actionMode, final Menu menu) {
switch (view.getId()) {
case R.id.value: // coordinates, gc-code, name
assert view instanceof TextView;
@@ -1892,29 +1817,25 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
buildDetailsContextMenu(actionMode, menu, itemTitle, true);
return true;
case R.id.shortdesc:
- assert view instanceof TextView;
- clickedItemText = ((TextView) view).getText();
+ clickedItemText = cache.getShortDescription();
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_description), false);
return true;
case R.id.longdesc:
- assert view instanceof TextView;
// combine short and long description
final String shortDesc = cache.getShortDescription();
if (StringUtils.isBlank(shortDesc)) {
- clickedItemText = ((TextView) view).getText();
+ clickedItemText = cache.getDescription();
} else {
- clickedItemText = shortDesc + "\n\n" + ((TextView) view).getText();
+ clickedItemText = shortDesc + "\n\n" + cache.getDescription();
}
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_description), false);
return true;
case R.id.personalnote:
- assert view instanceof TextView;
- clickedItemText = ((TextView) view).getText();
+ clickedItemText = cache.getPersonalNote();
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_personal_note), true);
return true;
case R.id.hint:
- assert view instanceof TextView;
- clickedItemText = ((TextView) view).getText();
+ clickedItemText = cache.getHint();
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_hint), false);
return true;
case R.id.log:
@@ -1923,8 +1844,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_logs), false);
return true;
case R.id.date: // event date
- assert view instanceof TextView;
- clickedItemText = ((TextView) view).getText();
+ clickedItemText = Formatter.formatHiddenDate(cache);
buildDetailsContextMenu(actionMode, menu, res.getString(R.string.cache_event), true);
menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar());
return true;
@@ -1934,13 +1854,13 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void onDestroyActionMode(final ActionMode actionMode) {
- // do nothing
+ currentActionMode = null;
}
@Override
public boolean onCreateActionMode(final ActionMode actionMode, final Menu menu) {
actionMode.getMenuInflater().inflate(R.menu.details_context, menu);
-
+ prepareClipboardActionMode(view, actionMode, menu);
// Return true so that the action mode is shown
return true;
}
@@ -1974,7 +1894,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
/**
* A dialog to allow the user to select reseting coordinates local/remote/both.
*/
- private AlertDialog createResetCacheCoordinatesDialog(final Geocache cache, final Waypoint wpt) {
+ private AlertDialog createResetCacheCoordinatesDialog(final Waypoint wpt) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.waypoint_reset_cache_coords);
@@ -1987,13 +1907,16 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
dialog.dismiss();
final ProgressDialog progressDialog = ProgressDialog.show(CacheDetailActivity.this, getString(R.string.cache), getString(R.string.waypoint_reset), true);
final HandlerResetCoordinates handler = new HandlerResetCoordinates(CacheDetailActivity.this, progressDialog, which == 1);
- new ResetCoordsThread(cache, handler, wpt, which == 0 || which == 1, which == 1, progressDialog).start();
+ resetCoords(cache, handler, wpt, which == 0 || which == 1, which == 1, progressDialog);
}
});
return builder.create();
}
private static class HandlerResetCoordinates extends WeakReferenceHandler<CacheDetailActivity> {
+ public static final int LOCAL = 0;
+ public static final int ON_WEBSITE = 1;
+
private boolean remoteFinished = false;
private boolean localFinished = false;
private final ProgressDialog progressDialog;
@@ -2007,7 +1930,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void handleMessage(final Message msg) {
- if (msg.what == ResetCoordsThread.LOCAL) {
+ if (msg.what == LOCAL) {
localFinished = true;
} else {
remoteFinished = true;
@@ -2024,94 +1947,53 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
}
- private class ResetCoordsThread extends Thread {
-
- private final Geocache cache;
- private final Handler handler;
- private final boolean local;
- private final boolean remote;
- private final Waypoint wpt;
- private final ProgressDialog progress;
- public static final int LOCAL = 0;
- public static final int ON_WEBSITE = 1;
-
- public ResetCoordsThread(final Geocache cache, final Handler handler, final Waypoint wpt, final boolean local, final boolean remote, final ProgressDialog progress) {
- this.cache = cache;
- this.handler = handler;
- this.local = local;
- this.remote = remote;
- this.wpt = wpt;
- this.progress = progress;
- }
-
- @Override
- public void run() {
-
- if (local) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- progress.setMessage(res.getString(R.string.waypoint_reset_cache_coords));
- }
- });
- cache.setCoords(wpt.getCoords());
- cache.setUserModifiedCoords(false);
- cache.deleteWaypointForce(wpt);
- DataStore.saveChangedCache(cache);
- handler.sendEmptyMessage(LOCAL);
- }
-
- final IConnector con = ConnectorFactory.getConnector(cache);
- if (remote && con.supportsOwnCoordinates()) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- progress.setMessage(res.getString(R.string.waypoint_coordinates_being_reset_on_website));
- }
- });
-
- final boolean result = con.deleteModifiedCoordinates(cache);
-
- runOnUiThread(new Runnable() {
+ private void resetCoords(final Geocache cache, final Handler handler, final Waypoint wpt, final boolean local, final boolean remote, final ProgressDialog progress) {
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ if (local) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ progress.setMessage(res.getString(R.string.waypoint_reset_cache_coords));
+ }
+ });
+ cache.setCoords(wpt.getCoords());
+ cache.setUserModifiedCoords(false);
+ cache.deleteWaypointForce(wpt);
+ DataStore.saveChangedCache(cache);
+ handler.sendEmptyMessage(HandlerResetCoordinates.LOCAL);
+ }
- @Override
- public void run() {
- if (result) {
- showToast(getString(R.string.waypoint_coordinates_has_been_reset_on_website));
- } else {
- showToast(getString(R.string.waypoint_coordinates_upload_error));
+ final IConnector con = ConnectorFactory.getConnector(cache);
+ if (remote && con.supportsOwnCoordinates()) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ progress.setMessage(res.getString(R.string.waypoint_coordinates_being_reset_on_website));
}
- handler.sendEmptyMessage(ON_WEBSITE);
- notifyDataSetChanged();
- }
+ });
- });
+ final boolean result = con.deleteModifiedCoordinates(cache);
- }
- }
- }
+ runOnUiThread(new Runnable() {
- private static class UploadPersonalNoteThread extends Thread {
- private Geocache cache = null;
- private CancellableHandler handler = null;
+ @Override
+ public void run() {
+ if (result) {
+ showToast(getString(R.string.waypoint_coordinates_has_been_reset_on_website));
+ } else {
+ showToast(getString(R.string.waypoint_coordinates_upload_error));
+ }
+ handler.sendEmptyMessage(HandlerResetCoordinates.ON_WEBSITE);
+ notifyDataSetChanged();
+ }
- public UploadPersonalNoteThread(final Geocache cache, final CancellableHandler handler) {
- this.cache = cache;
- this.handler = handler;
- }
+ });
- @Override
- public void run() {
- final IConnector con = ConnectorFactory.getConnector(cache);
- if (con.supportsPersonalNote()) {
- con.uploadPersonalNote(cache);
+ }
}
- final Message msg = Message.obtain();
- final Bundle bundle = new Bundle();
- bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, CgeoApplication.getInstance().getString(R.string.cache_personal_note_upload_done));
- msg.setData(bundle);
- handler.sendMessage(msg);
- }
+ });
}
@Override
@@ -2186,7 +2068,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (cache.isOffline()) {
final long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.getDetailedUpdate() / (60 * 1000)); // minutes
- String ago;
+ final String ago;
if (diff < 15) {
ago = res.getString(R.string.cache_offline_time_mins_few);
} else if (diff < 50) {
@@ -2232,7 +2114,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
updateStatusMsg(R.string.cache_dialog_offline_save_message, (String) msg.obj);
} else {
- notifyDatasetChanged(activityRef);
+ notifyDataSetChanged(activityRef);
}
}
}
@@ -2248,7 +2130,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
if (UPDATE_LOAD_PROGRESS_DETAIL == msg.what && msg.obj instanceof String) {
updateStatusMsg(R.string.cache_dialog_refresh_message, (String) msg.obj);
} else {
- notifyDatasetChanged(activityRef);
+ notifyDataSetChanged(activityRef);
}
}
}
@@ -2261,27 +2143,11 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void handleMessage(final Message msg) {
- notifyDatasetChanged(activityRef);
- }
- }
-
- private static final class SimpleUpdateHandler extends SimpleHandler {
-
- public SimpleUpdateHandler(final CacheDetailActivity activity, final Progress progress) {
- super(activity, progress);
- }
-
- @Override
- public void handleMessage(final Message msg) {
- if (msg.what == MESSAGE_FAILED) {
- super.handleMessage(msg);
- } else {
- notifyDatasetChanged(activityRef);
- }
+ notifyDataSetChanged(activityRef);
}
}
- private static void notifyDatasetChanged(final WeakReference<AbstractActivity> activityRef) {
+ private static void notifyDataSetChanged(final WeakReference<AbstractActivity> activityRef) {
final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
if (activity != null) {
activity.notifyDataSetChanged();
@@ -2308,18 +2174,29 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void onFinishEditNoteDialog(final String note) {
- cache.setPersonalNote(note);
- cache.parseWaypointsFromNote();
final TextView personalNoteView = ButterKnife.findById(this, R.id.personalnote);
setPersonalNote(personalNoteView, note);
- DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
- notifyDataSetChanged();
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(final Void... params) {
+ cache.setPersonalNote(note);
+ cache.parseWaypointsFromNote();
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(final Void v) {
+ notifyDataSetChanged();
+ }
+ }.execute();
}
private static void setPersonalNote(final TextView personalNoteView, final String personalNote) {
personalNoteView.setText(personalNote, TextView.BufferType.SPANNABLE);
if (StringUtils.isNotBlank(personalNote)) {
personalNoteView.setVisibility(View.VISIBLE);
+ Linkify.addLinks(personalNoteView, Linkify.ALL);
} else {
personalNoteView.setVisibility(View.GONE);
}
@@ -2337,6 +2214,10 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc
@Override
public void cachesAround() {
- CacheListActivity.startActivityCoordinates(this, cache.getCoords());
+ CacheListActivity.startActivityCoordinates(this, cache.getCoords(), cache.getName());
+ }
+
+ public void setNeedsRefresh() {
+ refreshOnResume = true;
}
}
diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java
index 522004e..bedb737 100644
--- a/main/src/cgeo/geocaching/CacheListActivity.java
+++ b/main/src/cgeo/geocaching/CacheListActivity.java
@@ -9,7 +9,9 @@ import cgeo.geocaching.activity.FilteredActivity;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.activity.ShowcaseViewBuilder;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.apps.cachelist.CacheListAppFactory;
+import cgeo.geocaching.apps.cachelist.CacheListApp;
+import cgeo.geocaching.apps.cachelist.CacheListApps;
+import cgeo.geocaching.apps.cachelist.ListNavigationSelectionActionProvider;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.gc.RecaptchaHandler;
import cgeo.geocaching.enumerations.CacheListType;
@@ -19,15 +21,14 @@ import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.export.FieldnoteExport;
import cgeo.geocaching.export.GpxExport;
import cgeo.geocaching.files.GPXImporter;
-import cgeo.geocaching.filter.FilterUserInterface;
+import cgeo.geocaching.filter.FilterActivity;
import cgeo.geocaching.filter.IFilter;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.AbstractList;
+import cgeo.geocaching.list.ListNameMemento;
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;
@@ -36,14 +37,15 @@ import cgeo.geocaching.loaders.NextPageGeocacheListLoader;
import cgeo.geocaching.loaders.OfflineGeocacheListLoader;
import cgeo.geocaching.loaders.OwnerGeocacheListLoader;
import cgeo.geocaching.loaders.PocketGeocacheListLoader;
-import cgeo.geocaching.loaders.RemoveFromHistoryLoader;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.CGeoMap;
import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.network.DownloadProgress;
import cgeo.geocaching.network.Network;
-import cgeo.geocaching.network.Parameters;
-import cgeo.geocaching.sensors.DirectionProvider;
+import cgeo.geocaching.network.Send2CgeoDownloader;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.sorting.CacheComparator;
@@ -52,25 +54,33 @@ import cgeo.geocaching.ui.CacheListAdapter;
import cgeo.geocaching.ui.LoggingUI;
import cgeo.geocaching.ui.WeakReferenceHandler;
import cgeo.geocaching.ui.dialog.Dialogs;
+import cgeo.geocaching.utils.AngleUtils;
import cgeo.geocaching.utils.AsyncTaskWithProgress;
+import cgeo.geocaching.utils.CalendarUtils;
import cgeo.geocaching.utils.CancellableHandler;
-import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.Log;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
+import cgeo.geocaching.utils.RxUtils;
import com.github.amlcurran.showcaseview.targets.ActionViewTarget;
import com.github.amlcurran.showcaseview.targets.ActionViewTarget.Type;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Scheduler.Worker;
+import rx.Subscriber;
import rx.Subscription;
+import rx.functions.Action0;
import rx.functions.Action1;
+import rx.functions.Func1;
import rx.schedulers.Schedulers;
+import rx.subjects.ReplaySubject;
+import rx.subscriptions.CompositeSubscription;
+import rx.subscriptions.Subscriptions;
import android.app.Activity;
import android.app.AlertDialog;
@@ -83,6 +93,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -104,21 +115,15 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
public class CacheListActivity extends AbstractListActivity implements FilteredActivity, LoaderManager.LoaderCallbacks<SearchResult> {
private static final int MAX_LIST_ITEMS = 1000;
- private static final int MSG_DONE = -1;
- private static final int MSG_SERVER_FAIL = -2;
- private static final int MSG_NO_REGISTRATION = -3;
- private static final int MSG_WAITING = 0;
- private static final int MSG_LOADING = 1;
- private static final int MSG_LOADED = 2;
-
private static final int REQUEST_CODE_IMPORT_GPX = 1;
private CacheListType type = null;
@@ -132,30 +137,28 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private final Progress progress = new Progress();
private String title = "";
private int detailTotal = 0;
- private int detailProgress = 0;
+ private final AtomicInteger detailProgress = new AtomicInteger(0);
private long detailProgressTime = 0L;
- private int listId = StoredList.TEMPORARY_LIST_ID; // Only meaningful for the OFFLINE type
+ private int listId = StoredList.TEMPORARY_LIST.id; // Only meaningful for the OFFLINE type
private final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@Override
public void updateDirection(final float direction) {
if (Settings.isLiveList()) {
- adapter.setActualHeading(DirectionProvider.getDirectionNow(direction));
+ adapter.setActualHeading(AngleUtils.getDirectionNow(direction));
}
}
@Override
- public void updateGeoData(final IGeoData geoData) {
- final Geopoint coords = geoData.getCoords();
- if (coords != null) {
- adapter.setActualCoordinates(coords);
- }
+ public void updateGeoData(final GeoData geoData) {
+ adapter.setActualCoordinates(geoData.getCoords());
}
};
private ContextMenuInfo lastMenuInfo;
private String contextMenuGeocode = "";
private Subscription resumeSubscription;
+ private final ListNameMemento listNameMemento = new ListNameMemento();
// FIXME: This method has mostly been replaced by the loaders. But it still contains a license agreement check.
public void handleCachesLoaded() {
@@ -276,42 +279,49 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
refreshSpinnerAdapter();
}
- private final CancellableHandler loadDetailsHandler = new CancellableHandler() {
+ private class LoadDetailsHandler extends CancellableHandler {
@Override
public void handleRegularMessage(final Message msg) {
updateAdapter();
- if (msg.what > -1) {
- cacheList.get(msg.what).setStatusChecked(false);
+ if (msg.what == DownloadProgress.MSG_LOADED) {
+ ((Geocache) msg.obj).setStatusChecked(false);
adapter.notifyDataSetChanged();
+ final int dp = detailProgress.get();
final int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
- final int minutesRemaining = ((detailTotal - detailProgress) * secondsElapsed / ((detailProgress > 0) ? detailProgress : 1) / 60);
+ final int minutesRemaining = ((detailTotal - dp) * secondsElapsed / ((dp > 0) ? dp : 1) / 60);
- progress.setProgress(detailProgress);
+ progress.setProgress(dp);
if (minutesRemaining < 1) {
progress.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
} else {
progress.setMessage(res.getString(R.string.caches_downloading) + " " + res.getQuantityString(R.plurals.caches_eta_mins, minutesRemaining, minutesRemaining));
}
} else {
- if (search != null) {
- final Set<Geocache> cacheListTmp = search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
- if (CollectionUtils.isNotEmpty(cacheListTmp)) {
- cacheList.clear();
- cacheList.addAll(cacheListTmp);
+ new AsyncTask<Void, Void, Set<Geocache>>() {
+ @Override
+ protected Set<Geocache> doInBackground(final Void... params) {
+ return search != null ? search.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB) : null;
}
- }
- setAdapterCurrentCoordinates(false);
+ @Override
+ protected void onPostExecute(final Set<Geocache> result) {
+ if (CollectionUtils.isNotEmpty(result)) {
+ cacheList.clear();
+ cacheList.addAll(result);
+ }
+ setAdapterCurrentCoordinates(false);
- showProgress(false);
- progress.dismiss();
+ showProgress(false);
+ progress.dismiss();
+ }
+ }.execute();
}
}
- };
+ }
/**
* TODO Possibly parts should be a Thread not a Handler
@@ -324,22 +334,22 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
adapter.notifyDataSetChanged();
switch (msg.what) {
- case MSG_WAITING: //no caches
+ case DownloadProgress.MSG_WAITING: //no caches
progress.setMessage(res.getString(R.string.web_import_waiting));
break;
- case MSG_LOADING: //cache downloading
+ case DownloadProgress.MSG_LOADING: //cache downloading
progress.setMessage(res.getString(R.string.web_downloading) + " " + msg.obj + '…');
break;
- case MSG_LOADED: //Cache downloaded
+ case DownloadProgress.MSG_LOADED: //Cache downloaded
progress.setMessage(res.getString(R.string.web_downloaded) + " " + msg.obj + '…');
refreshCurrentList();
break;
- case MSG_SERVER_FAIL:
+ case DownloadProgress.MSG_SERVER_FAIL:
progress.dismiss();
showToast(res.getString(R.string.sendToCgeo_download_fail));
finish();
break;
- case MSG_NO_REGISTRATION:
+ case DownloadProgress.MSG_NO_REGISTRATION:
progress.dismiss();
showToast(res.getString(R.string.sendToCgeo_no_registration));
finish();
@@ -374,7 +384,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
};
private AbstractSearchLoader currentLoader;
- private String newListName = StringUtils.EMPTY;
public CacheListActivity() {
super(true);
@@ -392,8 +401,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
// get parameters
Bundle extras = getIntent().getExtras();
if (extras != null) {
- final Object typeObject = extras.get(Intents.EXTRA_LIST_TYPE);
- type = (typeObject instanceof CacheListType) ? (CacheListType) typeObject : CacheListType.OFFLINE;
+ type = Intents.getListType(getIntent());
coords = extras.getParcelable(Intents.EXTRA_COORDS);
}
else {
@@ -405,6 +413,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
coords = Geopoint.ZERO;
}
}
+ if (type == CacheListType.NEAREST) {
+ coords = Sensors.getInstance().currentGeo().getCoords();
+ }
setTitle(title);
@@ -513,7 +524,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
public void onResume() {
super.onResume();
- resumeSubscription = geoDirHandler.start(GeoDirHandler.UPDATE_GEODATA | GeoDirHandler.UPDATE_DIRECTION);
+ resumeSubscription = geoDirHandler.start(GeoDirHandler.UPDATE_GEODATA | GeoDirHandler.UPDATE_DIRECTION | GeoDirHandler.LOW_POWER, 250, TimeUnit.MILLISECONDS);
adapter.setSelectMode(false);
setAdapterCurrentCoordinates(true);
@@ -533,12 +544,9 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void setAdapterCurrentCoordinates(final boolean forceSort) {
- final Geopoint coordsNow = app.currentGeo().getCoords();
- if (coordsNow != null) {
- adapter.setActualCoordinates(coordsNow);
- if (forceSort) {
- adapter.forceSort();
- }
+ adapter.setActualCoordinates(Sensors.getInstance().currentGeo().getCoords());
+ if (forceSort) {
+ adapter.forceSort();
}
}
@@ -552,8 +560,8 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.cache_list_options, menu);
- CacheListAppFactory.addMenuItems(menu, this, res);
sortProvider = (SortActionProvider) MenuItemCompat.getActionProvider(menu.findItem(R.id.menu_sort));
+ assert sortProvider != null; // We set it in the XML file
sortProvider.setSelection(adapter.getCacheComparator());
sortProvider.setClickListener(new Action1<CacheComparator>() {
@@ -572,6 +580,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
sortProvider.setSelection(selectedComparator);
}
});
+
+ ListNavigationSelectionActionProvider.initialize(menu.findItem(R.id.menu_cache_list_app_provider), new ListNavigationSelectionActionProvider.Callback() {
+
+ @Override
+ public void onListNavigationSelected(final CacheListApp app) {
+ app.invoke(cacheList, CacheListActivity.this, getFilteredSearch());
+ }
+ });
+
return true;
}
@@ -632,6 +649,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
setMenuItemLabel(menu, R.id.menu_remove_from_history, R.string.cache_remove_from_history, R.string.cache_clear_history);
menu.findItem(R.id.menu_import_android).setVisible(Compatibility.isStorageAccessFrameworkAvailable() && isOffline);
+
+ final List<CacheListApp> listNavigationApps = CacheListApps.getActiveApps();
+ menu.findItem(R.id.menu_cache_list_app_provider).setVisible(listNavigationApps.size() > 1);
+ menu.findItem(R.id.menu_cache_list_app).setVisible(listNavigationApps.size() == 1);
+
} catch (final RuntimeException e) {
Log.e("CacheListActivity.onPrepareOptionsMenu", e);
}
@@ -641,7 +663,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
private boolean containsPastEvents() {
for (final Geocache cache : adapter.getCheckedOrAllCaches()) {
- if (DateUtils.isPastEvent(cache)) {
+ if (CalendarUtils.isPastEvent(cache)) {
return true;
}
}
@@ -672,9 +694,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
- if (super.onOptionsItemSelected(item)) {
- return true;
- }
switch (item.getItemId()) {
case R.id.menu_show_on_map:
goMap();
@@ -698,23 +717,23 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
case R.id.menu_import_android:
importGpxFromAndroid();
invalidateOptionsMenuCompatible();
- return false;
+ return true;
case R.id.menu_create_list:
- new StoredList.UserInterface(this).promptForListCreation(getListSwitchingRunnable(), newListName);
+ new StoredList.UserInterface(this).promptForListCreation(getListSwitchingRunnable(), listNameMemento.getTerm());
refreshSpinnerAdapter();
invalidateOptionsMenuCompatible();
- return false;
+ return true;
case R.id.menu_drop_list:
removeList(false);
invalidateOptionsMenuCompatible();
- return false;
+ return true;
case R.id.menu_rename_list:
renameList();
- return false;
+ return true;
case R.id.menu_invert_selection:
adapter.invertSelection();
invalidateOptionsMenuCompatible();
- return false;
+ return true;
case R.id.menu_filter:
showFilterMenu(null);
return true;
@@ -730,7 +749,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
case R.id.menu_remove_from_history:
removeFromHistoryCheck();
invalidateOptionsMenuCompatible();
- return false;
+ return true;
case R.id.menu_move_to_list:
moveCachesToOtherList();
invalidateOptionsMenuCompatible();
@@ -744,13 +763,12 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
invalidateOptionsMenuCompatible();
return true;
case R.id.menu_cache_list_app:
- if (!cacheToShow()) {
- return false;
+ if (cacheToShow()) {
+ CacheListApps.getActiveApps().get(0).invoke(cacheList, this, getFilteredSearch());
}
- return CacheListAppFactory.onMenuItemSelected(item, cacheList, this, getFilteredSearch());
- default:
- return CacheListAppFactory.onMenuItemSelected(item, cacheList, this, search);
+ return true;
}
+ return super.onOptionsItemSelected(item);
}
private boolean cacheToShow() {
@@ -762,26 +780,28 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private SearchResult getFilteredSearch() {
- final Set<String> geocodes = new HashSet<>();
- for (final Geocache cache : adapter.getFilteredList()) {
- geocodes.add(cache.getGeocode());
- }
- return new SearchResult(geocodes);
+ return new SearchResult(Geocache.getGeocodes(adapter.getFilteredList()));
}
- public void deletePastEvents() {
+ private void deletePastEvents() {
final List<Geocache> deletion = new ArrayList<>();
for (final Geocache cache : adapter.getCheckedOrAllCaches()) {
- if (DateUtils.isPastEvent(cache)) {
+ if (CalendarUtils.isPastEvent(cache)) {
deletion.add(cache);
}
}
- new DropDetailsTask().execute(deletion.toArray(new Geocache[deletion.size()]));
+ new DropDetailsTask(0).execute(deletion.toArray(new Geocache[deletion.size()]));
}
- public void clearOfflineLogs() {
- progress.show(this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.cancelMessage());
- new ClearOfflineLogsThread(clearOfflineLogsHandler).start();
+ private void clearOfflineLogs() {
+ Dialogs.confirmYesNo(this, R.string.caches_clear_offlinelogs, R.string.caches_clear_offlinelogs_message, new OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ progress.show(CacheListActivity.this, null, res.getString(R.string.caches_clear_offlinelogs_progress), true, clearOfflineLogsHandler.cancelMessage());
+ clearOfflineLogs(clearOfflineLogsHandler, adapter.getCheckedOrAllCaches());
+ }
+ });
}
/**
@@ -789,12 +809,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
*/
@Override
public void showFilterMenu(final View view) {
- new FilterUserInterface(this).selectFilter(new Action1<IFilter>() {
- @Override
- public void call(@Nullable final IFilter selectedFilter) {
- setFilter(selectedFilter);
- }
- });
+ FilterActivity.selectFilter(this);
}
private void setComparator(final CacheComparator comparator) {
@@ -886,13 +901,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
CacheDetailActivity.startActivity(this, cache.getGeocode(), cache.getName());
break;
case R.id.menu_drop_cache:
+ final int lastListPosition = getListView().getFirstVisiblePosition();
cache.drop(new Handler() {
@Override
public void handleMessage(final Message msg) {
adapter.notifyDataSetChanged();
refreshCurrentList();
+ getListView().setSelection(lastListPosition);
}
- }, Schedulers.io());
+ });
break;
case R.id.menu_move_to_list:
new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new Action1<Integer>() {
@@ -903,7 +920,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
adapter.setSelectMode(false);
refreshCurrentList();
}
- }, true, listId, newListName);
+ }, true, listId, listNameMemento);
break;
case R.id.menu_store_cache:
case R.id.menu_refresh:
@@ -1037,8 +1054,14 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
new GPXImporter(this, listId, importGpxAttachementFinishedHandler).importGPX(uri, null, getDisplayName(uri));
}
}
+ else if (requestCode == FilterActivity.REQUEST_SELECT_FILTER && resultCode == Activity.RESULT_OK) {
+ final int[] filterIndex = data.getIntArrayExtra(FilterActivity.EXTRA_FILTER_RESULT);
+ setFilter(FilterActivity.getFilterFromPosition(filterIndex[0], filterIndex[1]));
+ }
- refreshCurrentList();
+ if (type == CacheListType.OFFLINE) {
+ refreshCurrentList();
+ }
}
private String getDisplayName(final Uri uri) {
@@ -1062,7 +1085,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
- if (!Network.isNetworkConnected(getApplicationContext())) {
+ if (!Network.isNetworkConnected()) {
showToast(getString(R.string.err_server));
return;
}
@@ -1079,11 +1102,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
refreshStoredInternal(caches);
}
- }, true, StoredList.TEMPORARY_LIST_ID, newListName);
+ }, true, StoredList.TEMPORARY_LIST.id, listNameMemento);
} else {
if (type != CacheListType.OFFLINE) {
for (final Geocache geocache : caches) {
- if (geocache.getListId() == StoredList.TEMPORARY_LIST_ID) {
+ if (geocache.getListId() == StoredList.TEMPORARY_LIST.id) {
geocache.setListId(StoredList.STANDARD_LIST_ID);
}
}
@@ -1093,25 +1116,25 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
private void refreshStoredInternal(final List<Geocache> caches) {
- detailProgress = 0;
+ detailProgress.set(0);
showProgress(false);
final int etaTime = ((detailTotal * 25) / 60);
- String message;
+ final String message;
if (etaTime < 1) {
message = res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm);
} else {
message = res.getString(R.string.caches_downloading) + " " + res.getQuantityString(R.plurals.caches_eta_mins, etaTime, etaTime);
}
+ final LoadDetailsHandler loadDetailsHandler = new LoadDetailsHandler();
progress.show(this, null, message, ProgressDialog.STYLE_HORIZONTAL, loadDetailsHandler.cancelMessage());
progress.setMaxProgressAndReset(detailTotal);
detailProgressTime = System.currentTimeMillis();
- final LoadDetailsThread threadDetails = new LoadDetailsThread(loadDetailsHandler, caches);
- threadDetails.start();
+ loadDetails(loadDetailsHandler, caches);
}
public void removeFromHistoryCheck() {
@@ -1126,18 +1149,17 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
});
}
- public void removeFromHistory() {
+ private void removeFromHistory() {
final List<Geocache> caches = adapter.getCheckedOrAllCaches();
final String[] geocodes = new String[caches.size()];
for (int i = 0; i < geocodes.length; i++) {
geocodes[i] = caches.get(i).getGeocode();
}
- final Bundle b = new Bundle();
- b.putStringArray(Intents.EXTRA_CACHELIST, geocodes);
- getSupportLoaderManager().initLoader(CacheListLoaderType.REMOVE_FROM_HISTORY.getLoaderId(), b, this);
+ DataStore.clearVisitDate(geocodes);
+ refreshCurrentList();
}
- public void importWeb() {
+ private void importWeb() {
// menu is also shown with no device connected
if (!Settings.isRegisteredForSend2cgeo()) {
Dialogs.confirm(this, R.string.web_import_title, R.string.init_sendToCgeo_description, new OnClickListener() {
@@ -1150,146 +1172,92 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
- detailProgress = 0;
+ detailProgress.set(0);
showProgress(false);
final DownloadFromWebHandler downloadFromWebHandler = new DownloadFromWebHandler();
progress.show(this, null, res.getString(R.string.web_import_waiting), true, downloadFromWebHandler.cancelMessage());
-
- final LoadFromWebThread threadWeb = new LoadFromWebThread(downloadFromWebHandler, listId);
- threadWeb.start();
+ Send2CgeoDownloader.loadFromWeb(downloadFromWebHandler, listId);
}
- public void dropStored() {
+ private void dropStored() {
final int titleId = (adapter.getCheckedCount() > 0) ? R.string.caches_remove_selected : R.string.caches_remove_all;
- final int messageId = (adapter.getCheckedCount() > 0) ? R.string.caches_remove_selected_confirm : R.string.caches_remove_all_confirm;
- final String message = getString(messageId, adapter.getCheckedOrAllCount());
+ final int count = adapter.getCheckedOrAllCount();
+ final String message = res.getQuantityString(adapter.getCheckedCount() > 0 ? R.plurals.caches_remove_selected_confirm : R.plurals.caches_remove_all_confirm, count, count);
Dialogs.confirmYesNo(this, titleId, message, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int id) {
final List<Geocache> selected = adapter.getCheckedOrAllCaches();
- new DropDetailsTask().execute(selected.toArray(new Geocache[selected.size()]));
+ final int lastListPosition = getListView().getFirstVisiblePosition();
+ new DropDetailsTask(lastListPosition).execute(selected.toArray(new Geocache[selected.size()]));
dialog.cancel();
}
});
}
/**
- * Thread to refresh the cache details.
+ * Method to asynchronously refresh the caches details.
*/
- private class LoadDetailsThread extends Thread {
-
- final private CancellableHandler handler;
- final private List<Geocache> caches;
-
- public LoadDetailsThread(final CancellableHandler handler, final List<Geocache> caches) {
- this.handler = handler;
- this.caches = caches;
- }
-
- @Override
- public void run() {
- // 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() ?
- ListUtils.union(ListUtils.selectRejected(caches, Geocache.hasStaticMap),
- ListUtils.select(caches, Geocache.hasStaticMap)) :
- caches;
-
- for (final Geocache cache : allCaches) {
- if (!refreshCache(cache)) {
- break;
- }
- }
-
- handler.sendEmptyMessage(MSG_DONE);
- }
-
- /**
- * Refreshes the cache information.
- *
- * @param cache
- * The cache to refresh
- * @return
- * <code>false</code> if the storing was interrupted, <code>true</code> otherwise
- */
- private boolean refreshCache(final Geocache cache) {
- try {
- if (handler.isCancelled()) {
- throw new InterruptedException("Stopped storing process.");
- }
- detailProgress++;
- cache.refreshSynchronous(null);
- handler.sendEmptyMessage(cacheList.indexOf(cache));
- } catch (final InterruptedException e) {
- Log.i(e.getMessage());
- return false;
- } catch (final Exception e) {
- Log.e("CacheListActivity.LoadDetailsThread", e);
- }
-
- return true;
- }
- }
-
- private static class LoadFromWebThread extends Thread {
-
- final private CancellableHandler handler;
- final private int listIdLFW;
-
- public LoadFromWebThread(final CancellableHandler handler, final int listId) {
- this.handler = handler;
- listIdLFW = StoredList.getConcreteList(listId);
- }
-
- @Override
- public void run() {
- long baseTime = System.currentTimeMillis();
-
- final String deviceCode = StringUtils.defaultString(Settings.getWebDeviceCode());
- final Parameters params = new Parameters("code", deviceCode);
- while (!handler.isCancelled() && System.currentTimeMillis() - baseTime < 3 * 60000) { // maximum: 3 minutes
- // Download new code
- final HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params);
-
- if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) {
- final String response = Network.getResponseData(responseFromWeb);
- if (response != null && response.length() > 2) {
- handler.sendMessage(handler.obtainMessage(MSG_LOADING, response));
-
- Geocache.storeCache(null, response, listIdLFW, false, null);
-
- handler.sendMessage(handler.obtainMessage(MSG_LOADED, response));
- baseTime = System.currentTimeMillis();
- } else if ("RG".equals(response)) {
- //Server returned RG (registration) and this device no longer registered.
- Settings.setWebNameCode(null, null);
- handler.sendEmptyMessage(MSG_NO_REGISTRATION);
- handler.cancel();
- break;
- } else {
- try {
- sleep(5000); // Wait for 5s if no cache found
- } catch (final InterruptedException e) {
+ private void loadDetails(final CancellableHandler handler, final List<Geocache> caches) {
+ final Observable<Geocache> allCaches;
+ final Subscription generator;
+ if (Settings.isStoreOfflineMaps()) {
+ // The list of caches will be generated in the background, putting the caches without static maps first.
+ final ReplaySubject<Geocache> withStaticMaps = ReplaySubject.create(caches.size());
+ final ReplaySubject<Geocache> withoutStaticMaps = ReplaySubject.create(caches.size());
+ final Worker worker = Schedulers.io().createWorker();
+ generator = worker.schedule(new Action0() {
+ @Override
+ public void call() {
+ for (final Geocache cache : caches) {
+ if (worker.isUnsubscribed()) {
+ // Do not continue to check for static maps if the user pressed cancel.
+ return;
+ }
+ if (cache.hasStaticMap()) {
+ withStaticMaps.onNext(cache);
+ } else {
+ withoutStaticMaps.onNext(cache);
}
- handler.sendEmptyMessage(MSG_WAITING);
}
- } else {
- handler.sendEmptyMessage(MSG_SERVER_FAIL);
- handler.cancel();
- break;
+ withStaticMaps.onCompleted();
+ withoutStaticMaps.onCompleted();
}
- }
-
- handler.sendEmptyMessage(MSG_DONE);
+ });
+ allCaches = Observable.concat(withoutStaticMaps, withStaticMaps);
+ } else {
+ allCaches = Observable.from(caches);
+ generator = Subscriptions.empty();
}
+ final Observable<Geocache> loaded = allCaches.flatMap(new Func1<Geocache, Observable<Geocache>>() {
+ @Override
+ public Observable<Geocache> call(final Geocache cache) {
+ return Observable.create(new OnSubscribe<Geocache>() {
+ @Override
+ public void call(final Subscriber<? super Geocache> subscriber) {
+ cache.refreshSynchronous(null);
+ detailProgress.incrementAndGet();
+ handler.obtainMessage(DownloadProgress.MSG_LOADED, cache).sendToTarget();
+ subscriber.onCompleted();
+ }
+ }).subscribeOn(RxUtils.refreshScheduler);
+ }
+ }).doOnCompleted(new Action0() {
+ @Override
+ public void call() {
+ handler.sendEmptyMessage(DownloadProgress.MSG_DONE);
+ }
+ });
+ handler.unsubscribeIfCancelled(new CompositeSubscription(generator, loaded.subscribe()));
}
private class DropDetailsTask extends AsyncTaskWithProgress<Geocache, Void> {
+ private final int lastListPosition;
- public DropDetailsTask() {
+ public DropDetailsTask(final int lastListPosition) {
super(CacheListActivity.this, null, res.getString(R.string.caches_remove_progress), true);
+ this.lastListPosition = lastListPosition;
}
@Override
@@ -1303,25 +1271,19 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
adapter.setSelectMode(false);
refreshCurrentList();
replaceCacheListFromSearch();
+ getListView().setSelection(lastListPosition);
}
}
- private class ClearOfflineLogsThread extends Thread {
-
- final private Handler handler;
- final private List<Geocache> selected;
-
- public ClearOfflineLogsThread(final Handler handlerIn) {
- handler = handlerIn;
- selected = adapter.getCheckedOrAllCaches();
- }
-
- @Override
- public void run() {
- DataStore.clearLogsOffline(selected);
- handler.sendEmptyMessage(MSG_DONE);
- }
+ private static void clearOfflineLogs(final Handler handler, final List<Geocache> selectedCaches) {
+ Schedulers.io().createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ DataStore.clearLogsOffline(selectedCaches);
+ handler.sendEmptyMessage(DownloadProgress.MSG_DONE);
+ }
+ });
}
private class MoreCachesListener implements View.OnClickListener {
@@ -1355,13 +1317,13 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
};
}
- public void switchListById(final int id) {
+ private void switchListById(final int id) {
if (id < 0) {
return;
}
if (id == PseudoList.HISTORY_LIST.id) {
- CacheListActivity.startActivityHistory(this);
+ startActivity(CacheListActivity.getHistoryIntent(this));
finish();
return;
}
@@ -1371,9 +1333,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
title = res.getString(R.string.list_all_lists);
} else {
final StoredList list = DataStore.getList(id);
- if (list == null) {
- return;
- }
listId = list.id;
title = list.title;
}
@@ -1437,12 +1396,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
// apply filter settings (if there's a filter)
final SearchResult searchToUse = getFilteredSearch();
- final int count = searchToUse.getCount();
- String mapTitle = title;
- if (count > 0) {
- mapTitle = title + " [" + count + "]";
- }
- CGeoMap.startActivitySearch(this, searchToUse, mapTitle);
+ CGeoMap.startActivitySearch(this, searchToUse, title);
}
private void refreshCurrentList() {
@@ -1452,7 +1406,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
public static void startActivityOffline(final Context context) {
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.OFFLINE);
+ Intents.putListType(cachesIntent, CacheListType.OFFLINE);
context.startActivity(cachesIntent);
}
@@ -1461,7 +1415,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.OWNER);
+ Intents.putListType(cachesIntent, CacheListType.OWNER);
cachesIntent.putExtra(Intents.EXTRA_USERNAME, userName);
context.startActivity(cachesIntent);
}
@@ -1479,7 +1433,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.FINDER);
+ Intents.putListType(cachesIntent, CacheListType.FINDER);
cachesIntent.putExtra(Intents.EXTRA_USERNAME, userName);
context.startActivity(cachesIntent);
}
@@ -1500,37 +1454,39 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
}
- public static void startActivityNearest(final AbstractActivity context, final Geopoint coordsNow) {
- if (!isValidCoords(context, coordsNow)) {
- return;
- }
- final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.NEAREST);
- cachesIntent.putExtra(Intents.EXTRA_COORDS, coordsNow);
- context.startActivity(cachesIntent);
+ public static Intent getNearestIntent(final Activity context) {
+ return Intents.putListType(new Intent(context, CacheListActivity.class), CacheListType.NEAREST);
}
- public static void startActivityHistory(final Context context) {
- final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.HISTORY);
- context.startActivity(cachesIntent);
+ public static Intent getHistoryIntent(final Context context) {
+ return Intents.putListType(new Intent(context, CacheListActivity.class), CacheListType.HISTORY);
}
public static void startActivityAddress(final Context context, final Geopoint coords, final String address) {
final Intent addressIntent = new Intent(context, CacheListActivity.class);
- addressIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.ADDRESS);
+ Intents.putListType(addressIntent, CacheListType.ADDRESS);
addressIntent.putExtra(Intents.EXTRA_COORDS, coords);
addressIntent.putExtra(Intents.EXTRA_ADDRESS, address);
context.startActivity(addressIntent);
}
- public static void startActivityCoordinates(final AbstractActivity context, final Geopoint coords) {
+ /**
+ * start list activity, by searching around the given point.
+ *
+ * @param name
+ * name of coordinates, will lead to a title like "Around ..." instead of directly showing the
+ * coordinates as title
+ */
+ public static void startActivityCoordinates(final AbstractActivity context, final Geopoint coords, @Nullable final String name) {
if (!isValidCoords(context, coords)) {
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.COORDINATE);
+ Intents.putListType(cachesIntent, CacheListType.COORDINATE);
cachesIntent.putExtra(Intents.EXTRA_COORDS, coords);
+ if (StringUtils.isNotEmpty(name)) {
+ cachesIntent.putExtra(Intents.EXTRA_TITLE, context.getString(R.string.around, name));
+ }
context.startActivity(cachesIntent);
}
@@ -1548,15 +1504,15 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.KEYWORD);
+ Intents.putListType(cachesIntent, CacheListType.KEYWORD);
cachesIntent.putExtra(Intents.EXTRA_KEYWORD, keyword);
context.startActivity(cachesIntent);
}
public static void startActivityMap(final Context context, final SearchResult search) {
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.MAP);
cachesIntent.putExtra(Intents.EXTRA_SEARCH, search);
+ Intents.putListType(cachesIntent, CacheListType.MAP);
context.startActivity(cachesIntent);
}
@@ -1567,7 +1523,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return;
}
final Intent cachesIntent = new Intent(context, CacheListActivity.class);
- cachesIntent.putExtra(Intents.EXTRA_LIST_TYPE, CacheListType.POCKET);
+ Intents.putListType(cachesIntent, CacheListType.POCKET);
cachesIntent.putExtra(Intents.EXTRA_NAME, pq.getName());
cachesIntent.putExtra(Intents.EXTRA_POCKET_GUID, guid);
context.startActivity(cachesIntent);
@@ -1592,7 +1548,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
}
if (listId == PseudoList.ALL_LIST.id) {
title = res.getString(R.string.list_all_lists);
- } else if (listId <= StoredList.TEMPORARY_LIST_ID) {
+ } else if (listId <= StoredList.TEMPORARY_LIST.id) {
listId = StoredList.STANDARD_LIST_ID;
title = res.getString(R.string.stored_caches_button);
} else {
@@ -1605,7 +1561,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
title = list.title;
}
- loader = new OfflineGeocacheListLoader(this.getBaseContext(), coords, listId);
+ loader = new OfflineGeocacheListLoader(getBaseContext(), coords, listId);
break;
case HISTORY:
@@ -1623,31 +1579,26 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
break;
case KEYWORD:
final String keyword = extras.getString(Intents.EXTRA_KEYWORD);
- rememberTerm(keyword);
+ title = listNameMemento.rememberTerm(keyword);
loader = new KeywordGeocacheListLoader(app, keyword);
break;
case ADDRESS:
final String address = extras.getString(Intents.EXTRA_ADDRESS);
if (StringUtils.isNotBlank(address)) {
- rememberTerm(address);
+ title = listNameMemento.rememberTerm(address);
} else {
title = coords.toString();
}
- if (coords != null) {
- loader = new CoordsGeocacheListLoader(app, coords);
- }
- else {
- loader = new AddressGeocacheListLoader(app, address);
- }
+ loader = new CoordsGeocacheListLoader(app, coords);
break;
case FINDER:
final String username = extras.getString(Intents.EXTRA_USERNAME);
- rememberTerm(username);
+ title = listNameMemento.rememberTerm(username);
loader = new FinderGeocacheListLoader(app, username);
break;
case OWNER:
final String ownerName = extras.getString(Intents.EXTRA_USERNAME);
- rememberTerm(ownerName);
+ title = listNameMemento.rememberTerm(ownerName);
loader = new OwnerGeocacheListLoader(app, ownerName);
break;
case MAP:
@@ -1657,10 +1608,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
replaceCacheListFromSearch();
loadCachesHandler.sendMessage(Message.obtain());
break;
- case REMOVE_FROM_HISTORY:
- title = res.getString(R.string.caches_history);
- loader = new RemoveFromHistoryLoader(app, extras.getStringArray(Intents.EXTRA_CACHELIST), coords);
- break;
case NEXT_PAGE:
loader = new NextPageGeocacheListLoader(app, search);
break;
@@ -1670,6 +1617,10 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
loader = new PocketGeocacheListLoader(app, guid);
break;
}
+ // if there is a title given in the activity start request, use this one instead of the default
+ if (extras != null && StringUtils.isNotBlank(extras.getString(Intents.EXTRA_TITLE))) {
+ title = extras.getString(Intents.EXTRA_TITLE);
+ }
updateTitle();
showProgress(true);
showFooterLoadingCaches();
@@ -1680,13 +1631,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
return loader;
}
- private void rememberTerm(final String term) {
- // set the title of the activity
- title = term;
- // and remember this term for potential use in list creation
- newListName = term;
- }
-
@Override
public void onLoadFinished(final Loader<SearchResult> arg0, final SearchResult searchIn) {
// The database search was moved into the UI call intentionally. If this is done before the runOnUIThread,
@@ -1716,8 +1660,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
/**
* Allow the title bar spinner to show the same subtitle like the activity itself would show.
*
- * @param list
- * @return
*/
public CharSequence getCacheListSubtitle(@NonNull final AbstractList list) {
// if this is the current list, be aware of filtering
@@ -1735,7 +1677,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA
/**
* Calculate the subtitle of the current list depending on (optional) filters.
*
- * @return
*/
private CharSequence getCurrentSubtitle() {
final ArrayList<String> numbers = new ArrayList<>();
diff --git a/main/src/cgeo/geocaching/CacheMenuHandler.java b/main/src/cgeo/geocaching/CacheMenuHandler.java
index 0dc6444..fbd8771 100644
--- a/main/src/cgeo/geocaching/CacheMenuHandler.java
+++ b/main/src/cgeo/geocaching/CacheMenuHandler.java
@@ -3,8 +3,11 @@ package cgeo.geocaching;
import cgeo.calendar.CalendarAddon;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
import cgeo.geocaching.apps.cache.navi.NavigationSelectionActionProvider;
+import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.AbstractUIFactory;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.app.Activity;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
@@ -18,7 +21,11 @@ import android.view.MenuItem;
* TODO: replace by a fragment
*
*/
-public class CacheMenuHandler extends AbstractUIFactory {
+public final class CacheMenuHandler extends AbstractUIFactory {
+
+ private CacheMenuHandler() {
+ // utility class
+ }
/**
* Methods to be implemented by the activity to react to the cache menu selections.
@@ -33,7 +40,7 @@ public class CacheMenuHandler extends AbstractUIFactory {
}
- public static boolean onMenuItemSelected(final MenuItem item, final CacheMenuHandler.ActivityInterface activityInterface, final Geocache cache) {
+ public static boolean onMenuItemSelected(final MenuItem item, @NonNull final CacheMenuHandler.ActivityInterface activityInterface, final Geocache cache) {
assert activityInterface instanceof Activity || activityInterface instanceof Fragment;
final Activity activity;
if (activityInterface instanceof Activity) {
@@ -85,7 +92,8 @@ public class CacheMenuHandler extends AbstractUIFactory {
menu.findItem(R.id.menu_navigate).setVisible(hasCoords);
menu.findItem(R.id.menu_caches_around).setVisible(hasCoords && cache.supportsCachesAround());
menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar());
- menu.findItem(R.id.menu_show_in_browser).setVisible(cache.canOpenInBrowser());
+ menu.findItem(R.id.menu_log_visit).setVisible(cache.supportsLogging() && !Settings.getLogOffline());
+ menu.findItem(R.id.menu_log_visit_offline).setVisible(cache.supportsLogging() && Settings.getLogOffline());
menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName());
diff --git a/main/src/cgeo/geocaching/CachePopupFragment.java b/main/src/cgeo/geocaching/CachePopupFragment.java
index b2af12c..ff4348a 100644
--- a/main/src/cgeo/geocaching/CachePopupFragment.java
+++ b/main/src/cgeo/geocaching/CachePopupFragment.java
@@ -2,8 +2,8 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.CacheDetailsCreator;
@@ -17,13 +17,12 @@ import rx.functions.Action0;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
-import android.content.Context;
-import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -135,20 +134,25 @@ public class CachePopupFragment extends AbstractDialogFragment {
public void call(final Integer selectedListId) {
storeCache(selectedListId);
}
- }, true, StoredList.TEMPORARY_LIST_ID);
+ }, true, StoredList.TEMPORARY_LIST.id);
} else {
- storeCache(StoredList.TEMPORARY_LIST_ID);
+ storeCache(StoredList.TEMPORARY_LIST.id);
}
}
protected void storeCache(final int listId) {
final StoreCacheHandler storeCacheHandler = new StoreCacheHandler(R.string.cache_dialog_offline_save_message);
- progress.show(getActivity(), res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage());
- Schedulers.io().createWorker().schedule(new Action0() {
+ final FragmentActivity activity = getActivity();
+ progress.show(activity, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true, storeCacheHandler.cancelMessage());
+ RxUtils.andThenOnUi(Schedulers.io(), new Action0() {
@Override
public void call() {
cache.store(listId, storeCacheHandler);
- getActivity().supportInvalidateOptionsMenu();
+ }
+ }, new Action0() {
+ @Override
+ public void call() {
+ activity.supportInvalidateOptionsMenu();
}
});
}
@@ -162,7 +166,7 @@ public class CachePopupFragment extends AbstractDialogFragment {
return;
}
- if (!Network.isNetworkConnected(getActivity())) {
+ if (!Network.isNetworkConnected()) {
showToast(getString(R.string.err_server));
return;
}
@@ -183,7 +187,7 @@ public class CachePopupFragment extends AbstractDialogFragment {
final DropCacheHandler dropCacheHandler = new DropCacheHandler();
progress.show(getActivity(), res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true, null);
- cache.drop(dropCacheHandler, Schedulers.io());
+ cache.drop(dropCacheHandler);
}
}
@@ -212,12 +216,6 @@ public class CachePopupFragment extends AbstractDialogFragment {
getActivity().finish();
}
- public static void startActivity(final Context context, final String geocode) {
- final Intent popupIntent = new Intent(context, CachePopup.class);
- popupIntent.putExtra(Intents.EXTRA_GEOCODE, geocode);
- context.startActivity(popupIntent);
- }
-
@Override
protected Geopoint getCoordinates() {
if (cache == null) {
diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java
index a81319d..d74acea 100644
--- a/main/src/cgeo/geocaching/CgeoApplication.java
+++ b/main/src/cgeo/geocaching/CgeoApplication.java
@@ -1,15 +1,15 @@
package cgeo.geocaching;
-import cgeo.geocaching.sensors.DirectionProvider;
-import cgeo.geocaching.sensors.GeoDataProvider;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.OOMDumpingUncaughtExceptionHandler;
+import cgeo.geocaching.utils.RxUtils;
-import rx.Observable;
-import rx.functions.Action1;
-import rx.observables.ConnectableObservable;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GooglePlayServicesUtil;
+
+import org.eclipse.jdt.annotation.NonNull;
import android.app.Application;
import android.view.ViewConfiguration;
@@ -22,10 +22,7 @@ public class CgeoApplication extends Application {
public boolean showLoginToast = true; //login toast shown just once.
private boolean liveMapHintShownInThisSession = false; // livemap hint has been shown
private static CgeoApplication instance;
- private Observable<IGeoData> geoDataObservable;
- private Observable<Float> directionObservable;
- private volatile IGeoData currentGeo = null;
- private volatile float currentDirection = 0.0f;
+ private boolean isGooglePlayServicesAvailable = false;
public static void dumpOnOutOfMemory(final boolean enable) {
@@ -45,7 +42,7 @@ public class CgeoApplication extends Application {
setInstance(this);
}
- private static void setInstance(final CgeoApplication application) {
+ private static void setInstance(@NonNull final CgeoApplication application) {
instance = application;
}
@@ -60,12 +57,7 @@ public class CgeoApplication extends Application {
final Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
- } catch (final IllegalArgumentException e) {
- // ignore
- } catch (final NoSuchFieldException e) {
- // ignore
- } catch (final IllegalAccessException e) {
- // ignore
+ } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException ignored) {
}
// Set language to English if the user decided so.
@@ -73,55 +65,32 @@ public class CgeoApplication extends Application {
// ensure initialization of lists
DataStore.getLists();
- }
-
- @Override
- public void onLowMemory() {
- Log.i("Cleaning applications cache.");
- DataStore.removeAllFromCache();
- }
- public synchronized Observable<IGeoData> geoDataObservable() {
- if (geoDataObservable == null) {
- final ConnectableObservable<IGeoData> onDemand = GeoDataProvider.create(this).replay(1);
- onDemand.subscribe(new Action1<IGeoData>() {
- @Override
- public void call(final IGeoData geoData) {
- currentGeo = geoData;
- }
- });
- geoDataObservable = onDemand.refCount();
+ // Check if Google Play services is available
+ if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
+ isGooglePlayServicesAvailable = true;
}
- return geoDataObservable;
- }
+ Log.i("Google Play services are " + (isGooglePlayServicesAvailable ? "" : "not ") + "available");
+ final Sensors sensors = Sensors.getInstance();
+ sensors.setupGeoDataObservables(Settings.useGooglePlayServices(), Settings.useLowPowerMode());
+ sensors.setupDirectionObservable(Settings.useLowPowerMode());
- public synchronized Observable<Float> directionObservable() {
- if (directionObservable == null) {
- final ConnectableObservable<Float> onDemand = DirectionProvider.create(this).replay(1);
- onDemand.subscribe(new Action1<Float>() {
- @Override
- public void call(final Float direction) {
- currentDirection = direction;
- }
- });
- directionObservable = onDemand.refCount();
- }
- return directionObservable;
+ // Attempt to acquire an initial location before any real activity happens.
+ sensors.geoDataObservable(true).subscribeOn(RxUtils.looperCallbacksScheduler).first().subscribe();
}
- public IGeoData currentGeo() {
- return currentGeo != null ? currentGeo : geoDataObservable().toBlocking().first();
- }
- public Float distanceNonBlocking(final ICoordinates target) {
- if (currentGeo == null || target.getCoords() == null) {
- return null;
- }
- return currentGeo.getCoords().distanceTo(target);
+ @Override
+ public void onLowMemory() {
+ onTrimMemory(TRIM_MEMORY_COMPLETE);
}
- public float currentDirection() {
- return currentDirection;
+ @Override
+ public void onTrimMemory(final int level) {
+ if (level >= TRIM_MEMORY_MODERATE) {
+ Log.i("Cleaning applications cache to trim memory");
+ DataStore.removeAllFromCache();
+ }
}
public boolean isLiveMapHintShownInThisSession() {
@@ -150,4 +119,8 @@ public class CgeoApplication extends Application {
forceRelog = true;
}
+ public boolean isGooglePlayServicesAvailable() {
+ return isGooglePlayServicesAvailable;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/CompassActivity.java b/main/src/cgeo/geocaching/CompassActivity.java
index 025d938..3f6fe6a 100644
--- a/main/src/cgeo/geocaching/CompassActivity.java
+++ b/main/src/cgeo/geocaching/CompassActivity.java
@@ -4,28 +4,35 @@ import butterknife.ButterKnife;
import butterknife.InjectView;
import cgeo.geocaching.activity.AbstractActionBarActivity;
+import cgeo.geocaching.activity.ShowcaseViewBuilder;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
import cgeo.geocaching.maps.CGeoMap;
-import cgeo.geocaching.sensors.DirectionProvider;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.GpsStatusProvider.Status;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.speech.SpeechService;
import cgeo.geocaching.ui.CompassView;
import cgeo.geocaching.ui.LoggingUI;
+import cgeo.geocaching.utils.AngleUtils;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
+import com.github.amlcurran.showcaseview.targets.ActionItemTarget;
+
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.Menu;
@@ -34,14 +41,10 @@ import android.view.SubMenu;
import android.view.View;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
public class CompassActivity extends AbstractActionBarActivity {
- private static final int COORDINATES_OFFSET = 10;
-
@InjectView(R.id.nav_type) protected TextView navType;
@InjectView(R.id.nav_accuracy) protected TextView navAccuracy;
@InjectView(R.id.nav_satellites) protected TextView navSatellites;
@@ -52,73 +55,70 @@ public class CompassActivity extends AbstractActionBarActivity {
@InjectView(R.id.destination) protected TextView destinationTextView;
@InjectView(R.id.cacheinfo) protected TextView cacheInfoView;
- private static final String EXTRAS_COORDS = "coords";
- private static final String EXTRAS_NAME = "name";
- private static final String EXTRAS_GEOCODE = "geocode";
- private static final String EXTRAS_CACHE_INFO = "cacheinfo";
- private static final List<IWaypoint> coordinates = new ArrayList<>();
-
/**
- * Destination of the compass, or null (if the compass is used for a waypoint only).
+ * Destination cache, may be null
+ */
+ private Geocache cache = null;
+ /**
+ * Destination waypoint, may be null
*/
- private @Nullable Geocache cache = null;
+ private Waypoint waypoint = null;
private Geopoint dstCoords = null;
private float cacheHeading = 0;
- private String title = null;
- private String info = null;
- private boolean hasMagneticFieldSensor;
+ private String description;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.compass_activity);
-
- final SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
- hasMagneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
- if (!hasMagneticFieldSensor) {
- Settings.setUseCompass(false);
- }
+ ButterKnife.inject(this);
// get parameters
final Bundle extras = getIntent().getExtras();
- if (extras != null) {
- final String geocode = extras.getString(EXTRAS_GEOCODE);
- if (StringUtils.isNotEmpty(geocode)) {
- cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
- }
- title = geocode;
- final String name = extras.getString(EXTRAS_NAME);
- dstCoords = extras.getParcelable(EXTRAS_COORDS);
- info = extras.getString(EXTRAS_CACHE_INFO);
-
- if (StringUtils.isNotBlank(name)) {
- if (StringUtils.isNotBlank(title)) {
- title += ": " + name;
- } else {
- title = name;
- }
- }
- } else {
- final Intent pointIntent = new Intent(this, NavigateAnyPointActivity.class);
- startActivity(pointIntent);
-
+ if (extras == null) {
finish();
return;
}
- // set header
- setTitle();
- setDestCoords();
- setCacheInfo();
+ // cache must exist, except for "any point navigation"
+ final String geocode = extras.getString(Intents.EXTRA_GEOCODE);
+ if (geocode != null) {
+ cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+ }
- ButterKnife.inject(this);
+ // find the wanted navigation target
+ if (extras.containsKey(Intents.EXTRA_WAYPOINT_ID)) {
+ final int waypointId = extras.getInt(Intents.EXTRA_WAYPOINT_ID);
+ final Waypoint waypoint = DataStore.loadWaypoint(waypointId);
+ if (waypoint != null) {
+ setTarget(waypoint);
+ }
+ }
+ else if (extras.containsKey(Intents.EXTRA_COORDS)) {
+ setTarget(extras.<Geopoint>getParcelable(Intents.EXTRA_COORDS), extras.getString(Intents.EXTRA_DESCRIPTION));
+ }
+ else {
+ setTarget(cache);
+ }
+
+ // set activity title just once, independent of what target is switched to
+ if (cache != null) {
+ setCacheTitleBar(cache);
+ }
+ else {
+ setTitle(StringUtils.defaultIfBlank(extras.getString(Intents.EXTRA_NAME), res.getString(R.string.navigation)));
+ }
// make sure we can control the TTS volume
setVolumeControlStream(AudioManager.STREAM_MUSIC);
+
+ presentShowcase();
}
@Override
public void onResume() {
- super.onResume(geoDirHandler.start(GeoDirHandler.UPDATE_GEODIR));
+ super.onResume(geoDirHandler.start(GeoDirHandler.UPDATE_GEODIR),
+ Sensors.getInstance().gpsStatusObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(gpsStatusHandler));
+ forceRefresh();
}
@Override
@@ -134,38 +134,43 @@ public class CompassActivity extends AbstractActionBarActivity {
setContentView(R.layout.compass_activity);
ButterKnife.inject(this);
+ setTarget(dstCoords, description);
- setTitle();
- setDestCoords();
- setCacheInfo();
+ forceRefresh();
+ }
+ private void forceRefresh() {
// Force a refresh of location and direction when data is available.
- final CgeoApplication app = CgeoApplication.getInstance();
- final IGeoData geo = app.currentGeo();
- if (geo != null) {
- geoDirHandler.updateGeoDir(geo, app.currentDirection());
- }
+ final Sensors sensors = Sensors.getInstance();
+ geoDirHandler.updateGeoDir(sensors.currentGeo(), sensors.currentDirection());
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.compass_activity_options, menu);
- menu.findItem(R.id.menu_compass_sensor).setVisible(hasMagneticFieldSensor);
- final SubMenu subMenu = menu.findItem(R.id.menu_select_destination).getSubMenu();
- if (coordinates.size() > 1) {
- for (int i = 0; i < coordinates.size(); i++) {
- final IWaypoint coordinate = coordinates.get(i);
- subMenu.add(0, COORDINATES_OFFSET + i, 0, coordinate.getName() + " (" + coordinate.getCoordType() + ")");
- }
- } else {
- menu.findItem(R.id.menu_select_destination).setVisible(false);
- }
+ menu.findItem(R.id.menu_compass_sensor).setVisible(Sensors.getInstance().hasCompassCapabilities());
if (cache != null) {
LoggingUI.addMenuItems(this, menu, cache);
}
+ addWaypointItems(menu);
return true;
}
+ private void addWaypointItems(final Menu menu) {
+ if (cache != null) {
+ final List<Waypoint> waypoints = cache.getWaypoints();
+ boolean visible = false;
+ final SubMenu subMenu = menu.findItem(R.id.menu_select_destination).getSubMenu();
+ for (final Waypoint waypoint : waypoints) {
+ if (waypoint.getCoords() != null) {
+ subMenu.add(0, waypoint.getId(), 0, waypoint.getName());
+ visible = true;
+ }
+ }
+ menu.findItem(R.id.menu_select_destination).setVisible(visible);
+ }
+ }
+
@Override
public boolean onPrepareOptionsMenu(final Menu menu) {
super.onPrepareOptionsMenu(menu);
@@ -177,6 +182,8 @@ public class CompassActivity extends AbstractActionBarActivity {
}
menu.findItem(R.id.menu_tts_start).setVisible(!SpeechService.isRunning());
menu.findItem(R.id.menu_tts_stop).setVisible(SpeechService.isRunning());
+ menu.findItem(R.id.menu_compass_cache).setVisible(cache != null);
+ menu.findItem(R.id.menu_hint).setVisible(cache != null);
return true;
}
@@ -185,7 +192,15 @@ public class CompassActivity extends AbstractActionBarActivity {
final int id = item.getItemId();
switch (id) {
case R.id.menu_map:
- CGeoMap.startActivityCoords(this, dstCoords, null, null);
+ if (waypoint != null) {
+ CGeoMap.startActivityCoords(this, waypoint.getCoords(), waypoint.getWaypointType(), waypoint.getName());
+ }
+ else if (cache != null) {
+ CGeoMap.startActivityGeoCode(this, cache.getGeocode());
+ }
+ else {
+ CGeoMap.startActivityCoords(this, dstCoords, null, null);
+ }
return true;
case R.id.menu_compass_sensor_gps:
Settings.setUseCompass(false);
@@ -203,36 +218,53 @@ public class CompassActivity extends AbstractActionBarActivity {
SpeechService.stopService(this);
invalidateOptionsMenuCompatible();
return true;
+ case R.id.menu_compass_cache:
+ setTarget(cache);
+ return true;
+ case R.id.menu_hint:
+ cache.showHintToast(this);
+ return true;
default:
if (LoggingUI.onMenuItemSelected(item, this, cache)) {
return true;
}
- final int coordinatesIndex = id - COORDINATES_OFFSET;
- if (coordinatesIndex >= 0 && coordinatesIndex < coordinates.size()) {
- final IWaypoint coordinate = coordinates.get(coordinatesIndex);
- title = coordinate.getName();
- dstCoords = coordinate.getCoords();
- setTitle();
- setDestCoords();
- setCacheInfo();
- updateDistanceInfo(app.currentGeo());
-
- Log.d("destination set: " + title + " (" + dstCoords + ")");
- return true;
+ if (cache != null) {
+ final Waypoint waypoint = cache.getWaypointById(id);
+ if (waypoint != null) {
+ setTarget(waypoint);
+ return true;
+ }
}
}
return super.onOptionsItemSelected(item);
}
- private void setTitle() {
- if (StringUtils.isNotBlank(title)) {
- setTitle(title);
- } else {
- setTitle(res.getString(R.string.navigation));
- }
+ @Override
+ public ShowcaseViewBuilder getShowcase() {
+ return new ShowcaseViewBuilder(this)
+ .setTarget(new ActionItemTarget(this, R.id.menu_hint))
+ .setContent(R.string.showcase_compass_hint_title, R.string.showcase_compass_hint_text);
}
- private void setDestCoords() {
+ private void setTarget(@NonNull final Geopoint coords, final String newDescription) {
+ setDestCoords(coords);
+ setTargetDescription(newDescription);
+ updateDistanceInfo(Sensors.getInstance().currentGeo());
+
+ Log.d("destination set: " + newDescription + " (" + dstCoords + ")");
+ }
+
+ private void setTarget(final @NonNull Waypoint waypointIn) {
+ waypoint = waypointIn;
+ setTarget(waypointIn.getCoords(), waypointIn.getName());
+ }
+
+ private void setTarget(final Geocache cache) {
+ setTarget(cache.getCoords(), Formatter.formatCacheInfoShort(cache));
+ }
+
+ private void setDestCoords(final Geopoint coords) {
+ dstCoords = coords;
if (dstCoords == null) {
return;
}
@@ -240,17 +272,18 @@ public class CompassActivity extends AbstractActionBarActivity {
destinationTextView.setText(dstCoords.toString());
}
- private void setCacheInfo() {
- if (info == null) {
+ private void setTargetDescription(final @Nullable String newDescription) {
+ description = newDescription;
+ if (this.description == null) {
cacheInfoView.setVisibility(View.GONE);
return;
}
cacheInfoView.setVisibility(View.VISIBLE);
- cacheInfoView.setText(info);
+ cacheInfoView.setText(this.description);
}
- private void updateDistanceInfo(final IGeoData geo) {
- if (geo.getCoords() == null || dstCoords == null) {
+ private void updateDistanceInfo(final GeoData geo) {
+ if (dstCoords == null) {
return;
}
@@ -259,36 +292,36 @@ public class CompassActivity extends AbstractActionBarActivity {
headingView.setText(Math.round(cacheHeading) + "°");
}
+ private final Action1<Status> gpsStatusHandler = new Action1<Status>() {
+ @Override
+ public void call(final Status gpsStatus) {
+ if (gpsStatus.satellitesVisible >= 0) {
+ navSatellites.setText(res.getString(R.string.loc_sat) + ": " + gpsStatus.satellitesFixed + "/" + gpsStatus.satellitesVisible);
+ } else {
+ navSatellites.setText("");
+ }
+ }
+ };
+
private final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@Override
- public void updateGeoDir(final IGeoData geo, final float dir) {
+ public void updateGeoDir(final GeoData geo, final float dir) {
try {
- if (geo.getCoords() != null) {
- if (geo.getSatellitesVisible() >= 0) {
- navSatellites.setText(res.getString(R.string.loc_sat) + ": " + geo.getSatellitesFixed() + "/" + geo.getSatellitesVisible());
- } else {
- navSatellites.setText("");
- }
- navType.setText(res.getString(geo.getLocationProvider().resourceId));
+ navType.setText(res.getString(geo.getLocationProvider().resourceId));
- if (geo.getAccuracy() >= 0) {
- navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()));
- } else {
- navAccuracy.setText(null);
- }
-
- navLocation.setText(geo.getCoords().toString());
-
- updateDistanceInfo(geo);
+ if (geo.getAccuracy() >= 0) {
+ navAccuracy.setText("±" + Units.getDistanceFromMeters(geo.getAccuracy()));
} else {
- navType.setText(null);
navAccuracy.setText(null);
- navLocation.setText(res.getString(R.string.loc_trying));
}
- updateNorthHeading(DirectionProvider.getDirectionNow(dir));
+ navLocation.setText(geo.getCoords().toString());
+
+ updateDistanceInfo(geo);
+
+ updateNorthHeading(AngleUtils.getDirectionNow(dir));
} catch (final RuntimeException e) {
- Log.w("Failed to LocationUpdater location.");
+ Log.w("Failed to update location", e);
}
}
};
@@ -299,34 +332,24 @@ public class CompassActivity extends AbstractActionBarActivity {
}
}
- public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType,
- final String info) {
- coordinates.clear();
- if (coordinatesWithType != null) {
- for (final IWaypoint coordinate : coordinatesWithType) {
- if (coordinate != null) {
- coordinates.add(coordinate);
- }
- }
- }
-
+ public static void startActivityWaypoint(final Context context, final Waypoint waypoint) {
final Intent navigateIntent = new Intent(context, CompassActivity.class);
- navigateIntent.putExtra(EXTRAS_COORDS, coords);
- navigateIntent.putExtra(EXTRAS_GEOCODE, geocode);
- if (null != displayedName) {
- navigateIntent.putExtra(EXTRAS_NAME, displayedName);
- }
- navigateIntent.putExtra(EXTRAS_CACHE_INFO, info);
+ navigateIntent.putExtra(Intents.EXTRA_GEOCODE, waypoint.getGeocode());
+ navigateIntent.putExtra(Intents.EXTRA_WAYPOINT_ID, waypoint.getId());
context.startActivity(navigateIntent);
}
- public static void startActivity(final Context context, final String geocode, final String displayedName, final Geopoint coords, final Collection<IWaypoint> coordinatesWithType) {
- CompassActivity.startActivity(context, geocode, displayedName, coords, coordinatesWithType, null);
+ public static void startActivityPoint(final Context context, final Geopoint coords, final String displayedName) {
+ final Intent navigateIntent = new Intent(context, CompassActivity.class);
+ navigateIntent.putExtra(Intents.EXTRA_COORDS, coords);
+ navigateIntent.putExtra(Intents.EXTRA_NAME, displayedName);
+ context.startActivity(navigateIntent);
}
- public static void startActivity(final Context context, final Geocache cache) {
- startActivity(context, cache.getGeocode(), cache.getName(), cache.getCoords(), null,
- Formatter.formatCacheInfoShort(cache));
+ public static void startActivityCache(final Context context, final Geocache cache) {
+ final Intent navigateIntent = new Intent(context, CompassActivity.class);
+ navigateIntent.putExtra(Intents.EXTRA_GEOCODE, cache.getGeocode());
+ context.startActivity(navigateIntent);
}
}
diff --git a/main/src/cgeo/geocaching/CreateShortcutActivity.java b/main/src/cgeo/geocaching/CreateShortcutActivity.java
index ffcf81b..ecb7dc4 100644
--- a/main/src/cgeo/geocaching/CreateShortcutActivity.java
+++ b/main/src/cgeo/geocaching/CreateShortcutActivity.java
@@ -3,17 +3,53 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.maps.MapActivity;
+import cgeo.geocaching.ui.dialog.Dialogs;
+import cgeo.geocaching.ui.dialog.Dialogs.ItemWithIcon;
+import cgeo.geocaching.utils.ImageUtils;
import rx.functions.Action1;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
+import java.util.ArrayList;
+import java.util.List;
+
public class CreateShortcutActivity extends AbstractActionBarActivity {
+ private static class Shortcut implements ItemWithIcon {
+
+ private final int titleResourceId;
+ private final int drawableResourceId;
+ private final Intent intent;
+
+ /**
+ * shortcut with a separate icon
+ */
+ public Shortcut(final int titleResourceId, final int drawableResourceId, final Intent intent) {
+ this.titleResourceId = titleResourceId;
+ this.drawableResourceId = drawableResourceId;
+ this.intent = intent;
+ }
+
+ @Override
+ public int getIcon() {
+ return drawableResourceId;
+ }
+
+ @Override
+ public String toString() {
+ return CgeoApplication.getInstance().getString(titleResourceId);
+ }
+ }
+
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// init
@@ -23,35 +59,82 @@ public class CreateShortcutActivity extends AbstractActionBarActivity {
}
private void promptForShortcut() {
+ final List<Shortcut> shortcuts = new ArrayList<>();
+
+ shortcuts.add(new Shortcut(R.string.live_map_button, R.drawable.main_live, new Intent(this, MapActivity.class)));
+ shortcuts.add(new Shortcut(R.string.caches_nearby_button, R.drawable.main_nearby, CacheListActivity.getNearestIntent(this)));
+
+ // TODO: make logging activities ask for cache/trackable when being invoked externally
+ // shortcuts.add(new Shortcut(R.string.cache_menu_visit, new Intent(this, LogCacheActivity.class)));
+ // shortcuts.add(new Shortcut(R.string.trackable_log_touch, new Intent(this, LogTrackableActivity.class)));
+
+ final Shortcut offlineShortcut = new Shortcut(R.string.list_title, R.drawable.main_stored, null);
+ shortcuts.add(offlineShortcut);
+ final Intent allIntent = new Intent(this, CacheListActivity.class);
+ allIntent.putExtra(Intents.EXTRA_LIST_ID, PseudoList.ALL_LIST.id);
+ shortcuts.add(new Shortcut(R.string.list_all_lists, R.drawable.main_stored, allIntent));
+ shortcuts.add(new Shortcut(R.string.advanced_search_button, R.drawable.main_search, new Intent(this, SearchActivity.class)));
+ shortcuts.add(new Shortcut(R.string.any_button, R.drawable.main_any, new Intent(this, NavigateAnyPointActivity.class)));
+ shortcuts.add(new Shortcut(R.string.menu_history, R.drawable.main_stored, CacheListActivity.getHistoryIntent(this)));
+
+ Dialogs.select(this, getString(R.string.create_shortcut), shortcuts, new Action1<Shortcut>() {
+
+ @Override
+ public void call(final Shortcut shortcut) {
+ if (shortcut == offlineShortcut) {
+ promptForListShortcut();
+ }
+ else {
+ createShortcutAndFinish(shortcut.toString(), shortcut.intent, shortcut.drawableResourceId);
+ }
+ }
+ });
+ }
+
+ protected void promptForListShortcut() {
new StoredList.UserInterface(this).promptForListSelection(R.string.create_shortcut, new Action1<Integer>() {
@Override
public void call(final Integer listId) {
- final Intent shortcut = createShortcut(listId);
- setResult(RESULT_OK, shortcut);
-
- // finish activity to return the shortcut
- finish();
+ createOfflineListShortcut(listId);
}
- }, false, PseudoList.HISTORY_LIST.id);
+ }, true, PseudoList.NEW_LIST.id);
}
- protected Intent createShortcut(int listId) {
+ protected void createOfflineListShortcut(final int listId) {
final StoredList list = DataStore.getList(listId);
- if (list == null) {
- return null;
- }
// target to be executed by the shortcut
final Intent targetIntent = new Intent(this, CacheListActivity.class);
targetIntent.putExtra(Intents.EXTRA_LIST_ID, list.id);
- final ShortcutIconResource iconResource = Intent.ShortcutIconResource.fromContext(this, R.drawable.cgeo);
// shortcut to be returned
+ createShortcutAndFinish(list.title, targetIntent, R.drawable.main_stored);
+ }
+
+ private void createShortcutAndFinish(final String title, final Intent targetIntent, final int iconResourceId) {
final Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, targetIntent);
- intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, list.title);
- intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
- return intent;
+ intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
+ if (iconResourceId == R.drawable.cgeo) {
+ final ShortcutIconResource iconResource = Intent.ShortcutIconResource.fromContext(this, iconResourceId);
+ intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
+ }
+ else {
+ intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, createOverlay(iconResourceId));
+ }
+
+ setResult(RESULT_OK, intent);
+
+ // finish activity to return the shortcut
+ finish();
+ }
+
+ private Bitmap createOverlay(final int drawableResourceId) {
+ final LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] {
+ res.getDrawable(drawableResourceId), res.getDrawable(R.drawable.cgeo) });
+ layerDrawable.setLayerInset(0, 0, 0, 10, 10);
+ layerDrawable.setLayerInset(1, 50, 50, 0, 0);
+ return ImageUtils.convertToBitmap(layerDrawable);
}
}
diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java
index e404b22..b7ca577 100644
--- a/main/src/cgeo/geocaching/DataStore.java
+++ b/main/src/cgeo/geocaching/DataStore.java
@@ -11,29 +11,34 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.files.LocalStorage;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.AbstractList;
import cgeo.geocaching.list.PseudoList;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.search.SearchSuggestionCursor;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.FileUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.Version;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
-import rx.android.observables.AndroidObservable;
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Subscriber;
+import rx.android.app.AppObservable;
+import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
-import rx.util.async.Async;
import android.app.Activity;
import android.app.ProgressDialog;
@@ -58,6 +63,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -68,6 +74,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
public class DataStore {
@@ -111,35 +118,32 @@ public class DataStore {
"cg_caches.direction," + // 16
"cg_caches.distance," + // 17
"cg_caches.terrain," + // 18
- "cg_caches.latlon," + // 19
- "cg_caches.location," + // 20
- "cg_caches.personal_note," + // 21
- "cg_caches.shortdesc," + // 22
- "cg_caches.favourite_cnt," + // 23
- "cg_caches.rating," + // 24
- "cg_caches.votes," + // 25
- "cg_caches.myvote," + // 26
- "cg_caches.disabled," + // 27
- "cg_caches.archived," + // 28
- "cg_caches.members," + // 29
- "cg_caches.found," + // 30
- "cg_caches.favourite," + // 31
- "cg_caches.inventoryunknown," + // 32
- "cg_caches.onWatchlist," + // 33
- "cg_caches.reliable_latlon," + // 34
- "cg_caches.coordsChanged," + // 35
- "cg_caches.latitude," + // 36
- "cg_caches.longitude," + // 37
- "cg_caches.finalDefined," + // 38
- "cg_caches._id," + // 39
- "cg_caches.inventorycoins," + // 40
- "cg_caches.inventorytags," + // 41
- "cg_caches.logPasswordRequired"; // 42
-
- //TODO: remove "latlon" field from cache table
+ "cg_caches.location," + // 19
+ "cg_caches.personal_note," + // 20
+ "cg_caches.shortdesc," + // 21
+ "cg_caches.favourite_cnt," + // 22
+ "cg_caches.rating," + // 23
+ "cg_caches.votes," + // 24
+ "cg_caches.myvote," + // 25
+ "cg_caches.disabled," + // 26
+ "cg_caches.archived," + // 27
+ "cg_caches.members," + // 28
+ "cg_caches.found," + // 29
+ "cg_caches.favourite," + // 30
+ "cg_caches.inventoryunknown," + // 31
+ "cg_caches.onWatchlist," + // 32
+ "cg_caches.reliable_latlon," + // 33
+ "cg_caches.coordsChanged," + // 34
+ "cg_caches.latitude," + // 35
+ "cg_caches.longitude," + // 36
+ "cg_caches.finalDefined," + // 37
+ "cg_caches._id," + // 38
+ "cg_caches.inventorycoins," + // 39
+ "cg_caches.inventorytags," + // 40
+ "cg_caches.logPasswordRequired"; // 41
/** The list of fields needed for mapping. */
- private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude", "longitude", "note", "own", "visited" };
+ private static final String[] WAYPOINT_COLUMNS = new String[] { "_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latitude", "longitude", "note", "own", "visited" };
/** Number of days (as ms) after temporarily saved caches are deleted */
private final static long DAYS_AFTER_CACHE_IS_DELETED = 3 * 24 * 60 * 60 * 1000;
@@ -147,7 +151,7 @@ public class DataStore {
/**
* holds the column indexes of the cache table to avoid lookups
*/
- private static CacheCache cacheCache = new CacheCache();
+ private static final CacheCache cacheCache = new CacheCache();
private static SQLiteDatabase database = null;
private static final int dbVersion = 68;
public static final int customListIdOffset = 10;
@@ -162,7 +166,7 @@ public class DataStore {
private static final @NonNull String dbTableLogImages = "cg_logImages";
private static final @NonNull String dbTableLogsOffline = "cg_logs_offline";
private static final @NonNull String dbTableTrackables = "cg_trackables";
- private static final @NonNull String dbTableSearchDestionationHistory = "cg_search_destination_history";
+ private static final @NonNull String dbTableSearchDestinationHistory = "cg_search_destination_history";
private static final @NonNull String dbCreateCaches = ""
+ "create table " + dbTableCaches + " ("
+ "_id integer primary key autoincrement, "
@@ -183,7 +187,6 @@ public class DataStore {
+ "size text, "
+ "difficulty float, "
+ "terrain float, "
- + "latlon text, "
+ "location text, "
+ "direction double, "
+ "distance double, "
@@ -214,9 +217,7 @@ public class DataStore {
+ "create table " + dbTableLists + " ("
+ "_id integer primary key autoincrement, "
+ "title text not null, "
- + "updated long not null, "
- + "latitude double, "
- + "longitude double "
+ + "updated long not null"
+ "); ";
private static final String dbCreateAttributes = ""
+ "create table " + dbTableAttributes + " ("
@@ -235,7 +236,6 @@ public class DataStore {
+ "prefix text, "
+ "lookup text, "
+ "name text, "
- + "latlon text, "
+ "latitude double, "
+ "longitude double, "
+ "note text, "
@@ -303,13 +303,23 @@ public class DataStore {
+ "); ";
private static final String dbCreateSearchDestinationHistory = ""
- + "create table " + dbTableSearchDestionationHistory + " ("
+ + "create table " + dbTableSearchDestinationHistory + " ("
+ "_id integer primary key autoincrement, "
+ "date long not null, "
+ "latitude double, "
+ "longitude double "
+ "); ";
+ private static final Observable<Integer> allCachesCountObservable = Observable.create(new OnSubscribe<Integer>() {
+ @Override
+ public void call(final Subscriber<? super Integer> subscriber) {
+ if (isInitialized()) {
+ subscriber.onNext(getAllCachesCount());
+ subscriber.onCompleted();
+ }
+ }
+ }).timeout(500, TimeUnit.MILLISECONDS).retry(10).subscribeOn(Schedulers.io());
+
private static boolean newlyCreatedDatabase = false;
private static boolean databaseCleaned = false;
@@ -358,11 +368,12 @@ public class DataStore {
}
cacheCache.removeAllFromCache();
- PreparedStatements.clearPreparedStatements();
+ PreparedStatement.clearPreparedStatements();
database.close();
database = null;
}
+ @NonNull
public static File getBackupFileInternal() {
return new File(LocalStorage.getStorage(), "cgeo.sqlite");
}
@@ -391,16 +402,15 @@ public class DataStore {
* Move the database to/from external cgdata in a new thread,
* showing a progress window
*
- * @param fromActivity
*/
public static void moveDatabase(final Activity fromActivity) {
final ProgressDialog dialog = ProgressDialog.show(fromActivity, fromActivity.getString(R.string.init_dbmove_dbmove), fromActivity.getString(R.string.init_dbmove_running), true, false);
- AndroidObservable.bindActivity(fromActivity, Async.fromCallable(new Func0<Boolean>() {
+ AppObservable.bindActivity(fromActivity, Observable.defer(new Func0<Observable<Boolean>>() {
@Override
- public Boolean call() {
+ public Observable<Boolean> call() {
if (!LocalStorage.isExternalStorageAvailable()) {
Log.w("Database was not moved: external memory not available");
- return false;
+ return Observable.just(false);
}
closeDb();
@@ -409,7 +419,7 @@ public class DataStore {
if (!LocalStorage.copy(source, target)) {
Log.e("Database could not be moved to " + target);
init();
- return false;
+ return Observable.just(false);
}
if (!FileUtils.delete(source)) {
Log.e("Original database could not be deleted during move");
@@ -418,7 +428,7 @@ public class DataStore {
Log.i("Database was moved to " + target);
init();
- return true;
+ return Observable.just(true);
}
})).subscribeOn(Schedulers.io()).subscribe(new Action1<Boolean>() {
@Override
@@ -430,14 +440,17 @@ public class DataStore {
});
}
+ @NonNull
private static File databasePath(final boolean internal) {
return new File(internal ? LocalStorage.getInternalDbDirectory() : LocalStorage.getExternalDbDirectory(), dbName);
}
+ @NonNull
private static File databasePath() {
return databasePath(!Settings.isDbOnSDCard());
}
+ @NonNull
private static File databaseAlternatePath() {
return databasePath(Settings.isDbOnSDCard());
}
@@ -552,7 +565,7 @@ public class DataStore {
try {
db.execSQL(dbCreateSearchDestinationHistory);
- Log.i("Added table " + dbTableSearchDestionationHistory + ".");
+ Log.i("Added table " + dbTableSearchDestinationHistory + ".");
} catch (final Exception e) {
Log.e("Failed to upgrade to ver. 52", e);
}
@@ -638,7 +651,6 @@ public class DataStore {
+ "size text, "
+ "difficulty float, "
+ "terrain float, "
- + "latlon text, "
+ "location text, "
+ "direction double, "
+ "distance double, "
@@ -665,7 +677,7 @@ public class DataStore {
db.execSQL(dbCreateCachesTemp);
db.execSQL("insert into " + dbTableCachesTemp + " select _id,updated,detailed,detailedupdate,visiteddate,geocode,reason,cacheid,guid,type,name,own,owner,owner_real," +
- "hidden,hint,size,difficulty,terrain,latlon,location,direction,distance,latitude,longitude, 0," +
+ "hidden,hint,size,difficulty,terrain,location,direction,distance,latitude,longitude, 0," +
"personal_note,shortdesc,description,favourite_cnt,rating,votes,myvote,disabled,archived,members,found,favourite,inventorycoins," +
"inventorytags,inventoryunknown,onWatchlist from " + dbTableCaches);
db.execSQL("drop table " + dbTableCaches);
@@ -681,13 +693,12 @@ public class DataStore {
+ "prefix text, "
+ "lookup text, "
+ "name text, "
- + "latlon text, "
+ "latitude double, "
+ "longitude double, "
+ "note text "
+ "); ";
db.execSQL(dbCreateWaypointsTemp);
- db.execSQL("insert into " + dbTableWaypointsTemp + " select _id, geocode, updated, type, prefix, lookup, name, latlon, latitude, longitude, note from " + dbTableWaypoints);
+ db.execSQL("insert into " + dbTableWaypointsTemp + " select _id, geocode, updated, type, prefix, lookup, name, latitude, longitude, note from " + dbTableWaypoints);
db.execSQL("drop table " + dbTableWaypoints);
db.execSQL("alter table " + dbTableWaypointsTemp + " rename to " + dbTableWaypoints);
@@ -823,7 +834,7 @@ public class DataStore {
private static void sanityChecks(final SQLiteDatabase db) {
// Check that the history of searches is well formed as some dates seem to be missing according
// to NPE traces.
- final int staleHistorySearches = db.delete(dbTableSearchDestionationHistory, "date is null", null);
+ final int staleHistorySearches = db.delete(dbTableSearchDestinationHistory, "date is null", null);
if (staleHistorySearches > 0) {
Log.w(String.format(Locale.getDefault(), "DataStore.dbHelper.onOpen: removed %d bad search history entries", staleHistorySearches));
}
@@ -871,15 +882,17 @@ public class DataStore {
final File[] files = LocalStorage.getStorage().listFiles();
if (ArrayUtils.isNotEmpty(files)) {
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 SQLiteStatement select = PreparedStatement.CHECK_IF_PRESENT.getStatement();
final ArrayList<File> toRemove = new ArrayList<>(files.length);
for (final File file : files) {
if (file.isDirectory()) {
final String geocode = file.getName();
if (oldFilePattern.matcher(geocode).find()) {
- select.bindString(1, geocode);
- if (select.simpleQueryForLong() == 0) {
- toRemove.add(file);
+ synchronized (select) {
+ select.bindString(1, geocode);
+ if (select.simpleQueryForLong() == 0) {
+ toRemove.add(file);
+ }
}
}
}
@@ -887,15 +900,15 @@ public class DataStore {
// Use a background thread for the real removal to avoid keeping the database locked
// if we are called from within a transaction.
- new Thread(new Runnable() {
+ Schedulers.io().createWorker().schedule(new Action0() {
@Override
- public void run() {
+ public void call() {
for (final File dir : toRemove) {
Log.i("Removing obsolete cache directory for " + dir.getName());
- LocalStorage.deleteDirectory(dir);
+ FileUtils.deleteDirectory(dir);
}
}
- }).start();
+ });
}
}
@@ -933,7 +946,7 @@ public class DataStore {
int dataDetailed = 0;
try {
- Cursor cursor;
+ final Cursor cursor;
if (StringUtils.isNotBlank(geocode)) {
cursor = database.query(
@@ -1000,18 +1013,18 @@ public class DataStore {
final SQLiteStatement listId;
final String value;
if (StringUtils.isNotBlank(geocode)) {
- listId = PreparedStatements.getListIdOfGeocode();
+ listId = PreparedStatement.LIST_ID_OF_GEOCODE.getStatement();
value = geocode;
}
else {
- listId = PreparedStatements.getListIdOfGuid();
+ listId = PreparedStatement.LIST_ID_OF_GUID.getStatement();
value = guid;
}
synchronized (listId) {
listId.bindString(1, value);
- return listId.simpleQueryForLong() != StoredList.TEMPORARY_LIST_ID;
+ return listId.simpleQueryForLong() != StoredList.TEMPORARY_LIST.id;
}
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.isOffline", e);
@@ -1020,6 +1033,7 @@ public class DataStore {
return false;
}
+ @Nullable
public static String getGeocodeForGuid(final String guid) {
if (StringUtils.isBlank(guid)) {
return null;
@@ -1027,12 +1041,12 @@ public class DataStore {
init();
try {
- final SQLiteStatement description = PreparedStatements.getGeocodeOfGuid();
+ final SQLiteStatement description = PreparedStatement.GEOCODE_OF_GUID.getStatement();
synchronized (description) {
description.bindString(1, guid);
return description.simpleQueryForString();
}
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.getGeocodeForGuid", e);
@@ -1041,36 +1055,14 @@ public class DataStore {
return null;
}
- public static String getCacheidForGeocode(final String geocode) {
- if (StringUtils.isBlank(geocode)) {
- return null;
- }
- init();
-
- try {
- final SQLiteStatement description = PreparedStatements.getCacheIdOfGeocode();
- synchronized (description) {
- description.bindString(1, geocode);
- return description.simpleQueryForString();
- }
- } catch (final SQLiteDoneException e) {
- // Do nothing, it only means we have no information on the cache
- } catch (final Exception e) {
- Log.e("DataStore.getCacheidForGeocode", e);
- }
-
- return null;
- }
-
/**
* Save/store a cache to the CacheCache
*
* @param cache
* the Cache to save in the CacheCache/DB
- * @param saveFlags
*
*/
- public static void saveCache(final Geocache cache, final EnumSet<LoadFlags.SaveFlag> saveFlags) {
+ public static void saveCache(final Geocache cache, final Set<LoadFlags.SaveFlag> saveFlags) {
saveCaches(Collections.singletonList(cache), saveFlags);
}
@@ -1079,10 +1071,9 @@ public class DataStore {
*
* @param caches
* the caches to save in the CacheCache/DB
- * @param saveFlags
*
*/
- public static void saveCaches(final Collection<Geocache> caches, final EnumSet<LoadFlags.SaveFlag> saveFlags) {
+ public static void saveCaches(final Collection<Geocache> caches, final Set<LoadFlags.SaveFlag> saveFlags) {
if (CollectionUtils.isEmpty(caches)) {
return;
}
@@ -1116,7 +1107,9 @@ public class DataStore {
for (final Geocache cache : caches) {
final String geocode = cache.getGeocode();
final Geocache existingCache = existingCaches.get(geocode);
- final boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null;
+ boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null;
+ // parse the note AFTER merging the local information in
+ dbUpdateRequired |= cache.parseWaypointsFromNote();
cache.addStorageLocation(StorageLocation.CACHE);
cacheCache.putCacheInCache(cache);
@@ -1162,7 +1155,7 @@ public class DataStore {
values.put("hidden", hiddenDate.getTime());
}
values.put("hint", cache.getHint());
- values.put("size", cache.getSize() == null ? "" : cache.getSize().id);
+ values.put("size", cache.getSize().id);
values.put("difficulty", cache.getDifficulty());
values.put("terrain", cache.getTerrain());
values.put("location", cache.getLocation());
@@ -1228,7 +1221,7 @@ public class DataStore {
if (attributes.isEmpty()) {
return;
}
- final SQLiteStatement statement = PreparedStatements.getInsertAttribute();
+ final SQLiteStatement statement = PreparedStatement.INSERT_ATTRIBUTE.getStatement();
final long timestamp = System.currentTimeMillis();
for (final String attribute : attributes) {
statement.bindString(1, geocode);
@@ -1249,9 +1242,12 @@ public class DataStore {
init();
database.beginTransaction();
-
try {
- final SQLiteStatement insertDestination = PreparedStatements.getInsertSearchDestination(destination);
+ final SQLiteStatement insertDestination = PreparedStatement.INSERT_SEARCH_DESTINATION.getStatement();
+ insertDestination.bindLong(1, destination.getDate());
+ final Geopoint coords = destination.getCoords();
+ insertDestination.bindDouble(2, coords.getLatitude());
+ insertDestination.bindDouble(3, coords.getLongitude());
insertDestination.executeInsert();
database.setTransactionSuccessful();
} catch (final Exception e) {
@@ -1264,7 +1260,6 @@ public class DataStore {
public static boolean saveWaypoints(final Geocache cache) {
init();
database.beginTransaction();
-
try {
saveWaypointsWithoutTransaction(cache);
database.setTransactionSuccessful();
@@ -1294,7 +1289,6 @@ public class DataStore {
values.put("prefix", oneWaypoint.getPrefix());
values.put("lookup", oneWaypoint.getLookup());
values.put("name", oneWaypoint.getName());
- values.put("latlon", oneWaypoint.getLatlon());
putCoords(values, oneWaypoint.getCoords());
values.put("note", oneWaypoint.getNote());
values.put("own", oneWaypoint.isUserDefined() ? 1 : 0);
@@ -1315,7 +1309,6 @@ public class DataStore {
/**
* remove all waypoints of the given cache, where the id is not in the given list
*
- * @param cache
* @param remainingWaypointIds
* ids of waypoints which shall not be deleted
*/
@@ -1329,7 +1322,7 @@ public class DataStore {
*
* @param values
* a ContentValues to save coordinates in
- * @param oneWaypoint
+ * @param coords
* coordinates to save, or null to save empty coordinates
*/
private static void putCoords(final ContentValues values, final Geopoint coords) {
@@ -1348,6 +1341,7 @@ public class DataStore {
* index of the longitude column
* @return the coordinates, or null if latitude or longitude is null or the coordinates are invalid
*/
+ @Nullable
private static Geopoint getCoords(final Cursor cursor, final int indexLat, final int indexLon) {
if (cursor.isNull(indexLat) || cursor.isNull(indexLon)) {
return null;
@@ -1373,7 +1367,6 @@ public class DataStore {
values.put("prefix", waypoint.getPrefix());
values.put("lookup", waypoint.getLookup());
values.put("name", waypoint.getName());
- values.put("latlon", waypoint.getLatlon());
putCoords(values, waypoint.getCoords());
values.put("note", waypoint.getNote());
values.put("own", waypoint.isUserDefined() ? 1 : 0);
@@ -1410,7 +1403,7 @@ public class DataStore {
final List<Image> spoilers = cache.getSpoilers();
if (CollectionUtils.isNotEmpty(spoilers)) {
- final SQLiteStatement insertSpoiler = PreparedStatements.getInsertSpoiler();
+ final SQLiteStatement insertSpoiler = PreparedStatement.INSERT_SPOILER.getStatement();
final long timestamp = System.currentTimeMillis();
for (final Image spoiler : spoilers) {
insertSpoiler.bindString(1, geocode);
@@ -1420,8 +1413,7 @@ public class DataStore {
final String description = spoiler.getDescription();
if (description != null) {
insertSpoiler.bindString(5, description);
- }
- else {
+ } else {
insertSpoiler.bindNull(5);
}
insertSpoiler.executeInsert();
@@ -1429,11 +1421,21 @@ public class DataStore {
}
}
- public static void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) {
+ public static void saveLogs(final String geocode, final Iterable<LogEntry> logs) {
+ database.beginTransaction();
+ try {
+ saveLogsWithoutTransaction(geocode, logs);
+ database.setTransactionSuccessful();
+ } finally {
+ database.endTransaction();
+ }
+ }
+
+ private static void saveLogsWithoutTransaction(final String geocode, final Iterable<LogEntry> logs) {
// TODO delete logimages referring these logs
database.delete(dbTableLogs, "geocode = ?", new String[]{geocode});
- final SQLiteStatement insertLog = PreparedStatements.getInsertLog();
+ final SQLiteStatement insertLog = PreparedStatement.INSERT_LOG.getStatement();
final long timestamp = System.currentTimeMillis();
for (final LogEntry log : logs) {
insertLog.bindString(1, geocode);
@@ -1446,7 +1448,7 @@ public class DataStore {
insertLog.bindLong(8, log.friend ? 1 : 0);
final long logId = insertLog.executeInsert();
if (log.hasLogImages()) {
- final SQLiteStatement insertImage = PreparedStatements.getInsertLogImage();
+ final SQLiteStatement insertImage = PreparedStatement.INSERT_LOG_IMAGE.getStatement();
for (final Image img : log.getLogImages()) {
insertImage.bindLong(1, logId);
insertImage.bindString(2, img.getTitle());
@@ -1464,7 +1466,7 @@ public class DataStore {
final Map<LogType, Integer> logCounts = cache.getLogCounts();
if (MapUtils.isNotEmpty(logCounts)) {
final Set<Entry<LogType, Integer>> logCountsItems = logCounts.entrySet();
- final SQLiteStatement insertLogCounts = PreparedStatements.getInsertLogCounts();
+ final SQLiteStatement insertLogCounts = PreparedStatement.INSERT_LOG_COUNTS.getStatement();
final long timestamp = System.currentTimeMillis();
for (final Entry<LogType, Integer> pair : logCountsItems) {
insertLogCounts.bindString(1, geocode);
@@ -1526,6 +1528,7 @@ public class DataStore {
}
}
+ @Nullable
public static Viewport getBounds(final Set<String> geocodes) {
if (CollectionUtils.isEmpty(geocodes)) {
return null;
@@ -1542,6 +1545,7 @@ public class DataStore {
* The Geocode GCXXXX
* @return the loaded cache (if found). Can be null
*/
+ @Nullable
public static Geocache loadCache(final String geocode, final EnumSet<LoadFlag> loadFlags) {
if (StringUtils.isBlank(geocode)) {
throw new IllegalArgumentException("geocode must not be empty");
@@ -1554,15 +1558,15 @@ public class DataStore {
/**
* Load caches.
*
- * @param geocodes
* @return Set of loaded caches. Never null.
*/
+ @NonNull
public static Set<Geocache> loadCaches(final Collection<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
if (CollectionUtils.isEmpty(geocodes)) {
return new HashSet<>();
}
- final Set<Geocache> result = new HashSet<>();
+ final Set<Geocache> result = new HashSet<>(geocodes.size());
final Set<String> remaining = new HashSet<>(geocodes);
if (loadFlags.contains(LoadFlag.CACHE_BEFORE)) {
@@ -1609,10 +1613,9 @@ public class DataStore {
/**
* Load caches.
*
- * @param geocodes
- * @param loadFlags
* @return Set of loaded caches. Never null.
*/
+ @NonNull
private static Set<Geocache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) {
if (CollectionUtils.isEmpty(geocodes)) {
return Collections.emptySet();
@@ -1640,7 +1643,7 @@ public class DataStore {
int logIndex = -1;
while (cursor.moveToNext()) {
- final Geocache cache = DataStore.createCacheFromDatabaseContent(cursor);
+ final Geocache cache = createCacheFromDatabaseContent(cursor);
if (loadFlags.contains(LoadFlag.ATTRIBUTES)) {
cache.setAttributes(loadAttributes(cache.getGeocode()));
@@ -1699,11 +1702,9 @@ public class DataStore {
/**
* Builds a where for a viewport with the size enhanced by 50%.
*
- * @param dbTable
- * @param viewport
- * @return
*/
+ @NonNull
private static StringBuilder buildCoordinateWhere(final String dbTable, final Viewport viewport) {
return viewport.resize(1.5).sqlWhere(dbTable);
}
@@ -1711,9 +1712,9 @@ public class DataStore {
/**
* creates a Cache from the cursor. Doesn't next.
*
- * @param cursor
* @return Cache from DB
*/
+ @NonNull
private static Geocache createCacheFromDatabaseContent(final Cursor cursor) {
final Geocache cache = new Geocache();
@@ -1750,31 +1751,32 @@ public class DataStore {
}
cache.setTerrain(cursor.getFloat(18));
// do not set cache.location
- cache.setCoords(getCoords(cursor, 36, 37));
- cache.setPersonalNote(cursor.getString(21));
+ cache.setPersonalNote(cursor.getString(20));
// do not set cache.shortdesc
// do not set cache.description
- cache.setFavoritePoints(cursor.getInt(23));
- cache.setRating(cursor.getFloat(24));
- cache.setVotes(cursor.getInt(25));
- cache.setMyVote(cursor.getFloat(26));
- cache.setDisabled(cursor.getInt(27) == 1);
- cache.setArchived(cursor.getInt(28) == 1);
- cache.setPremiumMembersOnly(cursor.getInt(29) == 1);
- cache.setFound(cursor.getInt(30) == 1);
- cache.setFavorite(cursor.getInt(31) == 1);
- cache.setInventoryItems(cursor.getInt(32));
- cache.setOnWatchlist(cursor.getInt(33) == 1);
- cache.setReliableLatLon(cursor.getInt(34) > 0);
- cache.setUserModifiedCoords(cursor.getInt(35) > 0);
- cache.setFinalDefined(cursor.getInt(38) > 0);
- cache.setLogPasswordRequired(cursor.getInt(42) > 0);
+ cache.setFavoritePoints(cursor.getInt(22));
+ cache.setRating(cursor.getFloat(23));
+ cache.setVotes(cursor.getInt(24));
+ cache.setMyVote(cursor.getFloat(25));
+ cache.setDisabled(cursor.getInt(26) == 1);
+ cache.setArchived(cursor.getInt(27) == 1);
+ cache.setPremiumMembersOnly(cursor.getInt(28) == 1);
+ cache.setFound(cursor.getInt(29) == 1);
+ cache.setFavorite(cursor.getInt(30) == 1);
+ cache.setInventoryItems(cursor.getInt(31));
+ cache.setOnWatchlist(cursor.getInt(32) == 1);
+ cache.setReliableLatLon(cursor.getInt(33) > 0);
+ cache.setUserModifiedCoords(cursor.getInt(34) > 0);
+ cache.setCoords(getCoords(cursor, 35, 36));
+ cache.setFinalDefined(cursor.getInt(37) > 0);
+ cache.setLogPasswordRequired(cursor.getInt(41) > 0);
Log.d("Loading " + cache.toString() + " (" + cache.getListId() + ") from DB");
return cache;
}
+ @Nullable
public static List<String> loadAttributes(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1792,6 +1794,7 @@ public class DataStore {
GET_STRING_0);
}
+ @Nullable
public static Waypoint loadWaypoint(final int id) {
if (id == 0) {
return null;
@@ -1818,6 +1821,7 @@ public class DataStore {
return waypoint;
}
+ @Nullable
public static List<Waypoint> loadWaypoints(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1840,6 +1844,7 @@ public class DataStore {
});
}
+ @NonNull
private static Waypoint createWaypointFromDatabaseContent(final Cursor cursor) {
final String name = cursor.getString(cursor.getColumnIndex("name"));
final WaypointType type = WaypointType.findById(cursor.getString(cursor.getColumnIndex("type")));
@@ -1850,13 +1855,13 @@ public class DataStore {
waypoint.setGeocode(cursor.getString(cursor.getColumnIndex("geocode")));
waypoint.setPrefix(cursor.getString(cursor.getColumnIndex("prefix")));
waypoint.setLookup(cursor.getString(cursor.getColumnIndex("lookup")));
- waypoint.setLatlon(cursor.getString(cursor.getColumnIndex("latlon")));
waypoint.setCoords(getCoords(cursor, cursor.getColumnIndex("latitude"), cursor.getColumnIndex("longitude")));
waypoint.setNote(cursor.getString(cursor.getColumnIndex("note")));
return waypoint;
}
+ @Nullable
private static List<Image> loadSpoilers(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1885,8 +1890,9 @@ public class DataStore {
*
* @return A list of previously entered destinations or an empty list.
*/
+ @NonNull
public static List<Destination> loadHistoryOfSearchedLocations() {
- return queryToColl(dbTableSearchDestionationHistory,
+ return queryToColl(dbTableSearchDestinationHistory,
new String[]{"_id", "date", "latitude", "longitude"},
"latitude IS NOT NULL AND longitude IS NOT NULL",
null,
@@ -1908,7 +1914,7 @@ public class DataStore {
database.beginTransaction();
try {
- database.delete(dbTableSearchDestionationHistory, null, null);
+ database.delete(dbTableSearchDestinationHistory, null, null);
database.setTransactionSuccessful();
return true;
} catch (final Exception e) {
@@ -1921,7 +1927,6 @@ public class DataStore {
}
/**
- * @param geocode
* @return an immutable, non null list of logs
*/
@NonNull
@@ -1935,7 +1940,7 @@ public class DataStore {
init();
final Cursor cursor = database.rawQuery(
- /* 0 1 2 3 4 5 6 7 8 9 10 */
+ // 0 1 2 3 4 5 6 7 8 9 10
"SELECT cg_logs._id as cg_logs_id, type, author, log, date, found, friend, " + dbTableLogImages + "._id as cg_logImages_id, log_id, title, url"
+ " FROM " + dbTableLogs + " LEFT OUTER JOIN " + dbTableLogImages
+ " ON ( cg_logs._id = log_id ) WHERE geocode = ? ORDER BY date desc, cg_logs._id asc", new String[]{geocode});
@@ -1963,6 +1968,7 @@ public class DataStore {
return Collections.unmodifiableList(logs);
}
+ @Nullable
public static Map<LogType, Integer> loadLogCounts(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -1970,7 +1976,7 @@ public class DataStore {
init();
- final Map<LogType, Integer> logCounts = new HashMap<>();
+ final Map<LogType, Integer> logCounts = new EnumMap<>(LogType.class);
final Cursor cursor = database.query(
dbTableLogCount,
@@ -1991,6 +1997,7 @@ public class DataStore {
return logCounts;
}
+ @Nullable
private static List<Trackable> loadInventory(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2019,6 +2026,7 @@ public class DataStore {
return trackables;
}
+ @Nullable
public static Trackable loadTrackable(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2043,6 +2051,7 @@ public class DataStore {
return trackable;
}
+ @NonNull
private static Trackable createTrackableFromDatabaseContent(final Cursor cursor) {
final Trackable trackable = new Trackable();
trackable.setGeocode(cursor.getString(cursor.getColumnIndex("tbcode")));
@@ -2067,9 +2076,6 @@ public class DataStore {
/**
* Number of caches stored for a given type and/or list
*
- * @param cacheType
- * @param list
- * @return
*/
public static int getAllStoredCachesCount(final CacheType cacheType, final int list) {
if (cacheType == null) {
@@ -2081,37 +2087,29 @@ public class DataStore {
init();
try {
- final StringBuilder sql = new StringBuilder("select count(_id) from " + dbTableCaches + " where detailed = 1");
- String typeKey;
- int reasonIndex;
- if (cacheType != CacheType.ALL) {
- sql.append(" and type = ?");
- typeKey = cacheType.id;
- reasonIndex = 2;
- }
- else {
- typeKey = "all_types";
- reasonIndex = 1;
- }
- String listKey;
- if (list == PseudoList.ALL_LIST.id) {
- sql.append(" and reason > 0");
- listKey = "all_list";
- } else {
- sql.append(" and reason = ?");
- listKey = "list";
- }
-
- final String key = "CountCaches_" + typeKey + "_" + listKey;
+ final SQLiteStatement compiledStmnt;
+ synchronized (PreparedStatement.COUNT_TYPE_LIST) {
+ // All the statements here are used only once and are protected through the current synchronized block
+ if (list == PseudoList.ALL_LIST.id) {
+ if (cacheType == CacheType.ALL) {
+ compiledStmnt = PreparedStatement.COUNT_ALL_TYPES_ALL_LIST.getStatement();
+ } else {
+ compiledStmnt = PreparedStatement.COUNT_TYPE_ALL_LIST.getStatement();
+ compiledStmnt.bindString(1, cacheType.id);
+ }
+ } else {
+ if (cacheType == CacheType.ALL) {
+ compiledStmnt = PreparedStatement.COUNT_ALL_TYPES_LIST.getStatement();
+ compiledStmnt.bindLong(1, list);
+ } else {
+ compiledStmnt = PreparedStatement.COUNT_TYPE_LIST.getStatement();
+ compiledStmnt.bindString(1, cacheType.id);
+ compiledStmnt.bindLong(1, list);
+ }
+ }
- final SQLiteStatement compiledStmnt = PreparedStatements.getStatement(key, sql.toString());
- if (cacheType != CacheType.ALL) {
- compiledStmnt.bindString(1, cacheType.id);
- }
- if (list != PseudoList.ALL_LIST.id) {
- compiledStmnt.bindLong(reasonIndex, list);
+ return (int) compiledStmnt.simpleQueryForLong();
}
- return (int) compiledStmnt.simpleQueryForLong();
} catch (final Exception e) {
Log.e("DataStore.loadAllStoredCachesCount", e);
}
@@ -2123,7 +2121,7 @@ public class DataStore {
init();
try {
- return (int) PreparedStatements.getCountHistoryCaches().simpleQueryForLong();
+ return (int) PreparedStatement.HISTORY_COUNT.simpleQueryForLong();
} catch (final Exception e) {
Log.e("DataStore.getAllHistoricCachesCount", e);
}
@@ -2131,6 +2129,7 @@ public class DataStore {
return 0;
}
+ @NonNull
private static<T, U extends Collection<? super T>> U queryToColl(@NonNull final String table,
final String[] columns,
final String selection,
@@ -2162,10 +2161,9 @@ public class DataStore {
*
* @param coords
* the current coordinates to sort by distance, or null to sort by geocode
- * @param cacheType
- * @param listId
* @return a non-null set of geocodes
*/
+ @NonNull
private static Set<String> loadBatchOfStoredGeocodes(final Geopoint coords, final CacheType cacheType, final int listId) {
if (cacheType == null) {
throw new IllegalArgumentException("cacheType must not be null");
@@ -2212,6 +2210,7 @@ public class DataStore {
}
}
+ @NonNull
private static Set<String> loadBatchOfHistoricGeocodes(final boolean detailedOnly, final CacheType cacheType) {
final StringBuilder selection = new StringBuilder("visiteddate > 0");
@@ -2243,11 +2242,13 @@ public class DataStore {
}
/** Retrieve all stored caches from DB */
+ @NonNull
public static SearchResult loadCachedInViewport(final Viewport viewport, final CacheType cacheType) {
return loadInViewport(false, viewport, cacheType);
}
/** Retrieve stored caches from DB with listId >= 1 */
+ @NonNull
public static SearchResult loadStoredInViewport(final Viewport viewport, final CacheType cacheType) {
return loadInViewport(true, viewport, cacheType);
}
@@ -2255,15 +2256,12 @@ public class DataStore {
/**
* Loads the geocodes of caches in a viewport from CacheCache and/or Database
*
- * @param stored
- * True - query only stored caches, False - query cached ones as well
- * @param centerLat
- * @param centerLon
- * @param spanLat
- * @param spanLon
- * @param cacheType
- * @return Set with geocodes
+ * @param stored {@code true} to query caches stored in the database, {@code false} to also use the CacheCache
+ * @param viewport the viewport defining the area to scan
+ * @param cacheType the cache type
+ * @return the matching caches
*/
+ @NonNull
private static SearchResult loadInViewport(final boolean stored, final Viewport viewport, final CacheType cacheType) {
final Set<String> geocodes = new HashSet<>();
@@ -2306,72 +2304,78 @@ public class DataStore {
}
/**
- * Remove caches with listId = 0
- *
- * @param more
- * true = all caches false = caches stored 3 days or more before
+ * Remove caches with listId = 0 in the background. Once it has been executed once it will not do anything.
+ * This must be called from the UI thread to ensure synchronization of an internal variable.
*/
- public static void clean(final boolean more) {
+ public static void cleanIfNeeded(final Context context) {
if (databaseCleaned) {
return;
}
+ databaseCleaned = true;
- Log.d("Database clean: started");
+ Schedulers.io().createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ Log.d("Database clean: started");
+ try {
+ final int version = Version.getVersionCode(context);
+ final Set<String> geocodes = new HashSet<>();
+ if (version != Settings.getVersion()) {
+ queryToColl(dbTableCaches,
+ new String[]{"geocode"},
+ "reason = 0",
+ null,
+ null,
+ null,
+ null,
+ null,
+ geocodes,
+ GET_STRING_0);
+ } else {
+ final long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
+ final String timestampString = Long.toString(timestamp);
+ queryToColl(dbTableCaches,
+ new String[]{"geocode"},
+ "reason = 0 and detailed < ? and detailedupdate < ? and visiteddate < ?",
+ new String[]{timestampString, timestampString, timestampString},
+ null,
+ null,
+ null,
+ null,
+ geocodes,
+ GET_STRING_0);
+ }
- try {
- Set<String> geocodes = new HashSet<>();
- if (more) {
- queryToColl(dbTableCaches,
- new String[]{"geocode"},
- "reason = 0",
- null,
- null,
- null,
- null,
- null,
- geocodes,
- GET_STRING_0);
- } else {
- final long timestamp = System.currentTimeMillis() - DAYS_AFTER_CACHE_IS_DELETED;
- final String timestampString = Long.toString(timestamp);
- queryToColl(dbTableCaches,
- new String[]{"geocode"},
- "reason = 0 and detailed < ? and detailedupdate < ? and visiteddate < ?",
- new String[]{timestampString, timestampString, timestampString},
- null,
- null,
- null,
- null,
- geocodes,
- GET_STRING_0);
- }
+ final Set<String> withoutOfflineLogs = exceptCachesWithOfflineLog(geocodes);
+ Log.d("Database clean: removing " + withoutOfflineLogs.size() + " geocaches from listId=0");
+ removeCaches(withoutOfflineLogs, LoadFlags.REMOVE_ALL);
- geocodes = exceptCachesWithOfflineLog(geocodes);
+ // This cleanup needs to be kept in place for about one year so that older log images records are
+ // cleaned. TO BE REMOVED AFTER 2015-03-24.
+ Log.d("Database clean: removing obsolete log images records");
+ database.delete(dbTableLogImages, "log_id NOT IN (SELECT _id FROM " + dbTableLogs + ")", null);
- if (!geocodes.isEmpty()) {
- Log.d("Database clean: removing " + geocodes.size() + " geocaches from listId=0");
- removeCaches(geocodes, LoadFlags.REMOVE_ALL);
- }
+ // Remove the obsolete "_others" directory where the user avatar used to be stored.
+ FileUtils.deleteDirectory(LocalStorage.getStorageDir("_others"));
- // This cleanup needs to be kept in place for about one year so that older log images records are
- // cleaned. TO BE REMOVED AFTER 2015-03-24.
- Log.d("Database clean: removing obsolete log images records");
- database.delete(dbTableLogImages, "log_id NOT IN (SELECT _id FROM " + dbTableLogs + ")", null);
- } catch (final Exception e) {
- Log.w("DataStore.clean", e);
- }
+ if (version > -1) {
+ Settings.setVersion(version);
+ }
+ } catch (final Exception e) {
+ Log.w("DataStore.clean", e);
+ }
- Log.d("Database clean: finished");
- databaseCleaned = true;
+ Log.d("Database clean: finished");
+ }
+ });
}
/**
* remove all geocodes from the given list of geocodes where an offline log exists
*
- * @param geocodes
- * @return
*/
- private static Set<String> exceptCachesWithOfflineLog(final Set<String> geocodes) {
+ @NonNull
+ private static Set<String> exceptCachesWithOfflineLog(@NonNull final Set<String> geocodes) {
if (geocodes.isEmpty()) {
return geocodes;
}
@@ -2448,7 +2452,7 @@ public class DataStore {
// Delete cache directories
for (final String geocode : geocodes) {
- LocalStorage.deleteDirectory(LocalStorage.getStorageDir(geocode));
+ FileUtils.deleteDirectory(LocalStorage.getStorageDir(geocode));
}
}
}
@@ -2480,6 +2484,7 @@ public class DataStore {
return id != -1;
}
+ @Nullable
public static LogEntry loadLogOffline(final String geocode) {
if (StringUtils.isBlank(geocode)) {
return null;
@@ -2528,13 +2533,11 @@ public class DataStore {
init();
- final Set<String> geocodes = new HashSet<>(caches.size());
for (final Geocache cache : caches) {
- geocodes.add(cache.getGeocode());
cache.setLogOffline(false);
}
- database.execSQL(String.format("DELETE FROM %s where %s", dbTableLogsOffline, whereGeocodeIn(geocodes)));
+ database.execSQL(String.format("DELETE FROM %s where %s", dbTableLogsOffline, whereGeocodeIn(Geocache.getGeocodes(caches))));
}
public static boolean hasLogOffline(final String geocode) {
@@ -2544,7 +2547,7 @@ public class DataStore {
init();
try {
- final SQLiteStatement logCount = PreparedStatements.getLogCountOfGeocode();
+ final SQLiteStatement logCount = PreparedStatement.LOG_COUNT_OF_GEOCODE.getStatement();
synchronized (logCount) {
logCount.bindString(1, geocode);
return logCount.simpleQueryForLong() > 0;
@@ -2565,8 +2568,7 @@ public class DataStore {
database.beginTransaction();
try {
- final SQLiteStatement setVisit = PreparedStatements.getUpdateVisitDate();
-
+ final SQLiteStatement setVisit = PreparedStatement.UPDATE_VISIT_DATE.getStatement();
for (final String geocode : geocodes) {
setVisit.bindLong(1, visitedDate);
setVisit.bindString(2, geocode);
@@ -2584,7 +2586,7 @@ public class DataStore {
final Resources res = CgeoApplication.getInstance().getResources();
final List<StoredList> lists = new ArrayList<>();
- lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong()));
+ lists.add(new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatement.COUNT_CACHES_ON_STANDARD_LIST.simpleQueryForLong()));
try {
final String query = "SELECT l._id as _id, l.title as title, COUNT(c._id) as count" +
@@ -2600,6 +2602,7 @@ public class DataStore {
return lists;
}
+ @NonNull
private static ArrayList<StoredList> getListsFromCursor(final Cursor cursor) {
final int indexId = cursor.getColumnIndex("_id");
final int indexTitle = cursor.getColumnIndex("title");
@@ -2613,6 +2616,7 @@ public class DataStore {
});
}
+ @NonNull
public static StoredList getList(final int id) {
init();
if (id >= customListIdOffset) {
@@ -2636,15 +2640,20 @@ public class DataStore {
}
// fall back to standard list in case of invalid list id
- if (id == StoredList.STANDARD_LIST_ID || id >= customListIdOffset) {
- return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatements.getCountCachesOnStandardList().simpleQueryForLong());
- }
-
- return null;
+ return new StoredList(StoredList.STANDARD_LIST_ID, res.getString(R.string.list_inbox), (int) PreparedStatement.COUNT_CACHES_ON_STANDARD_LIST.simpleQueryForLong());
}
public static int getAllCachesCount() {
- return (int) PreparedStatements.getCountAllCaches().simpleQueryForLong();
+ return (int) PreparedStatement.COUNT_ALL_CACHES.simpleQueryForLong();
+ }
+
+ /**
+ * Count all caches in the background.
+ *
+ * @return an observable containing a unique element if the caches could be counted, or an error otherwise
+ */
+ public static Observable<Integer> getAllCachesCountObservable() {
+ return allCachesCountObservable;
}
/**
@@ -2710,7 +2719,6 @@ public class DataStore {
/**
* Remove a list. Caches in the list are moved to the standard list.
*
- * @param listId
* @return true if the list got deleted, false else
*/
public static boolean removeList(final int listId) {
@@ -2727,7 +2735,7 @@ public class DataStore {
if (cnt > 0) {
// move caches from deleted list to standard list
- final SQLiteStatement moveToStandard = PreparedStatements.getMoveToStandardList();
+ final SQLiteStatement moveToStandard = PreparedStatement.MOVE_TO_STANDARD_LIST.getStatement();
moveToStandard.bindLong(1, listId);
moveToStandard.execute();
@@ -2759,7 +2767,7 @@ public class DataStore {
}
init();
- final SQLiteStatement move = PreparedStatements.getMoveToList();
+ final SQLiteStatement move = PreparedStatement.MOVE_TO_LIST.getStatement();
database.beginTransaction();
try {
@@ -2787,7 +2795,7 @@ public class DataStore {
database.beginTransaction();
try {
- database.delete(dbTableSearchDestionationHistory, "_id = " + destination.getId(), null);
+ database.delete(dbTableSearchDestinationHistory, "_id = " + destination.getId(), null);
database.setTransactionSuccessful();
return true;
} catch (final Exception e) {
@@ -2802,9 +2810,8 @@ public class DataStore {
/**
* Load the lazily initialized fields of a cache and return them as partial cache (all other fields unset).
*
- * @param geocode
- * @return
*/
+ @NonNull
public static Geocache loadCacheTexts(final String geocode) {
final Geocache partial = new Geocache();
@@ -2835,7 +2842,7 @@ public class DataStore {
}
cursor.close();
- } catch (final SQLiteDoneException e) {
+ } catch (final SQLiteDoneException ignored) {
// Do nothing, it only means we have no information on the cache
} catch (final Exception e) {
Log.e("DataStore.getCacheDescription", e);
@@ -2862,11 +2869,12 @@ public class DataStore {
* Creates the WHERE clause for matching multiple geocodes. This automatically converts all given codes to
* UPPERCASE.
*/
+ @NonNull
private static StringBuilder whereGeocodeIn(final Collection<String> geocodes) {
final StringBuilder whereExpr = new StringBuilder("geocode in (");
final Iterator<String> iterator = geocodes.iterator();
while (true) {
- whereExpr.append(DatabaseUtils.sqlEscapeString(StringUtils.upperCase(iterator.next())));
+ DatabaseUtils.appendEscapedSQLString(whereExpr, StringUtils.upperCase(iterator.next()));
if (!iterator.hasNext()) {
break;
}
@@ -2878,12 +2886,9 @@ public class DataStore {
/**
* Loads all Waypoints in the coordinate rectangle.
*
- * @param excludeDisabled
- * @param excludeMine
- * @param type
- * @return
*/
+ @NonNull
public static Set<Waypoint> loadWaypoints(final Viewport viewport, final boolean excludeMine, final boolean excludeDisabled, final CacheType type) {
final StringBuilder where = buildCoordinateWhere(dbTableWaypoints, viewport);
if (excludeMine) {
@@ -2914,103 +2919,71 @@ public class DataStore {
}
public static void saveChangedCache(final Geocache cache) {
- DataStore.saveCache(cache, cache.getStorageLocation().contains(StorageLocation.DATABASE) ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.CACHE));
+ DataStore.saveCache(cache, cache.inDatabase() ? LoadFlags.SAVE_ALL : EnumSet.of(SaveFlag.CACHE));
}
- private static class PreparedStatements {
-
- private static HashMap<String, SQLiteStatement> statements = new HashMap<>();
-
- public static SQLiteStatement getMoveToStandardList() {
- return getStatement("MoveToStandardList", "UPDATE " + dbTableCaches + " SET reason = " + StoredList.STANDARD_LIST_ID + " WHERE reason = ?");
- }
+ private static enum PreparedStatement {
- public static SQLiteStatement getMoveToList() {
- return getStatement("MoveToList", "UPDATE " + dbTableCaches + " SET reason = ? WHERE geocode = ?");
- }
+ HISTORY_COUNT("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE visiteddate > 0"),
+ MOVE_TO_STANDARD_LIST("UPDATE " + dbTableCaches + " SET reason = " + StoredList.STANDARD_LIST_ID + " WHERE reason = ?"),
+ MOVE_TO_LIST("UPDATE " + dbTableCaches + " SET reason = ? WHERE geocode = ?"),
+ UPDATE_VISIT_DATE("UPDATE " + dbTableCaches + " SET visiteddate = ? WHERE geocode = ?"),
+ INSERT_LOG_IMAGE("INSERT INTO " + dbTableLogImages + " (log_id, title, url) VALUES (?, ?, ?)"),
+ INSERT_LOG_COUNTS("INSERT INTO " + dbTableLogCount + " (geocode, updated, type, count) VALUES (?, ?, ?, ?)"),
+ INSERT_SPOILER("INSERT INTO " + dbTableSpoilers + " (geocode, updated, url, title, description) VALUES (?, ?, ?, ?, ?)"),
+ LOG_COUNT_OF_GEOCODE("SELECT count(_id) FROM " + DataStore.dbTableLogsOffline + " WHERE geocode = ?"),
+ COUNT_CACHES_ON_STANDARD_LIST("SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID),
+ COUNT_ALL_CACHES("SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID),
+ INSERT_LOG("INSERT INTO " + dbTableLogs + " (geocode, updated, type, author, log, date, found, friend) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"),
+ INSERT_ATTRIBUTE("INSERT INTO " + dbTableAttributes + " (geocode, updated, attribute) VALUES (?, ?, ?)"),
+ LIST_ID_OF_GEOCODE("SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?"),
+ LIST_ID_OF_GUID("SELECT reason FROM " + dbTableCaches + " WHERE guid = ?"),
+ GEOCODE_OF_GUID("SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?"),
+ INSERT_SEARCH_DESTINATION("INSERT INTO " + dbTableSearchDestinationHistory + " (date, latitude, longitude) VALUES (?, ?, ?)"),
+ COUNT_TYPE_ALL_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND type = ? AND reason > 0"), // See use of COUNT_TYPE_LIST for synchronization
+ COUNT_ALL_TYPES_ALL_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND reason > 0"), // See use of COUNT_TYPE_LIST for synchronization
+ COUNT_TYPE_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND type = ? AND reason = ?"),
+ COUNT_ALL_TYPES_LIST("SELECT COUNT(_id) FROM " + dbTableCaches + " WHERE detailed = 1 AND reason = ?"), // See use of COUNT_TYPE_LIST for synchronization
+ CHECK_IF_PRESENT("SELECT COUNT(*) FROM " + dbTableCaches + " WHERE geocode = ?");
- public static SQLiteStatement getUpdateVisitDate() {
- return getStatement("UpdateVisitDate", "UPDATE " + dbTableCaches + " SET visiteddate = ? WHERE geocode = ?");
- }
+ private static final List<PreparedStatement> statements = new ArrayList<>();
- public static SQLiteStatement getInsertLogImage() {
- return getStatement("InsertLogImage", "INSERT INTO " + dbTableLogImages + " (log_id, title, url) VALUES (?, ?, ?)");
- }
+ @Nullable
+ private volatile SQLiteStatement statement = null; // initialized lazily
+ final String query;
- public static SQLiteStatement getInsertLogCounts() {
- return getStatement("InsertLogCounts", "INSERT INTO " + dbTableLogCount + " (geocode, updated, type, count) VALUES (?, ?, ?, ?)");
+ PreparedStatement(final String query) {
+ this.query = query;
}
- public static SQLiteStatement getInsertSpoiler() {
- return getStatement("InsertSpoiler", "INSERT INTO " + dbTableSpoilers + " (geocode, updated, url, title, description) VALUES (?, ?, ?, ?, ?)");
+ public long simpleQueryForLong() {
+ return getStatement().simpleQueryForLong();
}
- public static SQLiteStatement getInsertSearchDestination(final Destination destination) {
- final SQLiteStatement statement = getStatement("InsertSearch", "INSERT INTO " + dbTableSearchDestionationHistory + " (date, latitude, longitude) VALUES (?, ?, ?)");
- statement.bindLong(1, destination.getDate());
- final Geopoint coords = destination.getCoords();
- statement.bindDouble(2, coords.getLatitude());
- statement.bindDouble(3, coords.getLongitude());
+ private SQLiteStatement getStatement() {
+ if (statement == null) {
+ synchronized (statements) {
+ if (statement == null) {
+ init();
+ statement = database.compileStatement(query);
+ statements.add(this);
+ }
+ }
+ }
return statement;
}
private static void clearPreparedStatements() {
- for (final SQLiteStatement statement : statements.values()) {
- statement.close();
+ for (final PreparedStatement preparedStatement : statements) {
+ final SQLiteStatement statement = preparedStatement.statement;
+ if (statement != null) {
+ statement.close();
+ preparedStatement.statement = null;
+ }
}
statements.clear();
}
- private static synchronized SQLiteStatement getStatement(final String key, final String query) {
- SQLiteStatement statement = statements.get(key);
- if (statement == null) {
- init();
- statement = database.compileStatement(query);
- statements.put(key, statement);
- }
- return statement;
- }
-
- public static SQLiteStatement getCountHistoryCaches() {
- return getStatement("HistoryCount", "select count(_id) from " + dbTableCaches + " where visiteddate > 0");
- }
-
- private static SQLiteStatement getLogCountOfGeocode() {
- return getStatement("LogCountFromGeocode", "SELECT count(_id) FROM " + DataStore.dbTableLogsOffline + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getCountCachesOnStandardList() {
- return getStatement("CountStandardList", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason = " + StoredList.STANDARD_LIST_ID);
- }
-
- private static SQLiteStatement getCountAllCaches() {
- return getStatement("CountAllLists", "SELECT count(_id) FROM " + dbTableCaches + " WHERE reason >= " + StoredList.STANDARD_LIST_ID);
- }
-
- private static SQLiteStatement getInsertLog() {
- return getStatement("InsertLog", "INSERT INTO " + dbTableLogs + " (geocode, updated, type, author, log, date, found, friend) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
- }
-
- private static SQLiteStatement getInsertAttribute() {
- return getStatement("InsertAttribute", "INSERT INTO " + dbTableAttributes + " (geocode, updated, attribute) VALUES (?, ?, ?)");
- }
-
- private static SQLiteStatement getListIdOfGeocode() {
- return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getListIdOfGuid() {
- return getStatement("listFromGeocode", "SELECT reason FROM " + dbTableCaches + " WHERE guid = ?");
- }
-
- private static SQLiteStatement getCacheIdOfGeocode() {
- return getStatement("cacheIdFromGeocode", "SELECT cacheid FROM " + dbTableCaches + " WHERE geocode = ?");
- }
-
- private static SQLiteStatement getGeocodeOfGuid() {
- return getStatement("geocodeFromGuid", "SELECT geocode FROM " + dbTableCaches + " WHERE guid = ?");
- }
-
}
public static void saveVisitDate(final String geocode) {
@@ -3018,9 +2991,10 @@ public class DataStore {
}
public static void markDropped(final List<Geocache> caches) {
- moveToList(caches, StoredList.TEMPORARY_LIST_ID);
+ moveToList(caches, StoredList.TEMPORARY_LIST.id);
}
+ @Nullable
public static Viewport getBounds(final String geocode) {
if (geocode == null) {
return null;
@@ -3033,11 +3007,13 @@ public class DataStore {
setVisitDate(Arrays.asList(selected), 0);
}
+ @NonNull
public static SearchResult getBatchOfStoredCaches(final Geopoint coords, final CacheType cacheType, final int listId) {
final Set<String> geocodes = DataStore.loadBatchOfStoredGeocodes(coords, cacheType, listId);
return new SearchResult(geocodes, DataStore.getAllStoredCachesCount(cacheType, listId));
}
+ @NonNull
public static SearchResult getHistoryOfCaches(final boolean detailedOnly, final CacheType cacheType) {
final Set<String> geocodes = DataStore.loadBatchOfHistoricGeocodes(detailedOnly, cacheType);
return new SearchResult(geocodes, DataStore.getAllHistoryCachesCount());
@@ -3051,6 +3027,7 @@ public class DataStore {
return false;
}
+ @NonNull
public static Set<String> getCachedMissingFromSearch(final SearchResult searchResult, final Set<Tile> tiles, final IConnector connector, final int maxZoom) {
// get cached CacheListActivity
@@ -3081,6 +3058,7 @@ public class DataStore {
return missingFromSearch;
}
+ @Nullable
public static Cursor findSuggestions(final String searchTerm) {
// require 3 characters, otherwise there are to many results
if (StringUtils.length(searchTerm) < 3) {
@@ -3116,6 +3094,7 @@ public class DataStore {
cursor.close();
}
+ @NonNull
private static String getSuggestionArgument(final String input) {
return "%" + StringUtils.trim(input) + "%";
}
@@ -3143,6 +3122,7 @@ public class DataStore {
cursor.close();
}
+ @NonNull
public static String[] getSuggestions(final String table, final String column, final String input) {
try {
final Cursor cursor = database.rawQuery("SELECT DISTINCT " + column
@@ -3152,26 +3132,31 @@ public class DataStore {
return cursorToColl(cursor, new LinkedList<String>(), GET_STRING_0).toArray(new String[cursor.getCount()]);
} catch (final RuntimeException e) {
Log.e("cannot get suggestions from " + table + "->" + column + " for input '" + input + "'", e);
- return new String[0];
+ return ArrayUtils.EMPTY_STRING_ARRAY;
}
}
+ @NonNull
public static String[] getSuggestionsOwnerName(final String input) {
return getSuggestions(dbTableCaches, "owner_real", input);
}
+ @NonNull
public static String[] getSuggestionsTrackableCode(final String input) {
return getSuggestions(dbTableTrackables, "tbcode", input);
}
+ @NonNull
public static String[] getSuggestionsFinderName(final String input) {
return getSuggestions(dbTableLogs, "author", input);
}
+ @NonNull
public static String[] getSuggestionsGeocode(final String input) {
return getSuggestions(dbTableCaches, "geocode", input);
}
+ @NonNull
public static String[] getSuggestionsKeyword(final String input) {
return getSuggestions(dbTableCaches, "name", input);
}
@@ -3180,6 +3165,7 @@ public class DataStore {
*
* @return list of last caches opened in the details view, ordered by most recent first
*/
+ @NonNull
public static ArrayList<Geocache> getLastOpenedCaches() {
final List<String> geocodes = Settings.getLastOpenedCaches();
final Set<Geocache> cachesSet = DataStore.loadCaches(geocodes, LoadFlags.LOAD_CACHE_OR_DB);
diff --git a/main/src/cgeo/geocaching/Destination.java b/main/src/cgeo/geocaching/Destination.java
index 10d51be..1990d5d 100644
--- a/main/src/cgeo/geocaching/Destination.java
+++ b/main/src/cgeo/geocaching/Destination.java
@@ -1,6 +1,6 @@
package cgeo.geocaching;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
public final class Destination implements ICoordinates {
diff --git a/main/src/cgeo/geocaching/EditWaypointActivity.java b/main/src/cgeo/geocaching/EditWaypointActivity.java
index d49308e..ce279bf 100644
--- a/main/src/cgeo/geocaching/EditWaypointActivity.java
+++ b/main/src/cgeo/geocaching/EditWaypointActivity.java
@@ -7,11 +7,12 @@ import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.DistanceParser;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.location.DistanceParser;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
@@ -66,11 +67,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
@ViewById(R.id.modify_cache_coordinates_local) protected RadioButton modifyLocal;
@Extra(Intents.EXTRA_GEOCODE) protected String geocode = null;
- @Extra(Intents.EXTRA_WAYPOINT_ID) protected int id = -1;
- /**
- * number of waypoints that the corresponding cache has until now
- */
- @Extra(Intents.EXTRA_COUNT) protected int wpCount = 0;
+ @Extra(Intents.EXTRA_WAYPOINT_ID) protected int waypointId = -1;
@InstanceState protected int waypointTypeSelectorPosition = -1;
@@ -89,14 +86,14 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
*/
private Geocache cache;
- private Handler loadWaypointHandler = new Handler() {
+ private final Handler loadWaypointHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
try {
if (waypoint == null) {
- Log.d("No waypoint loaded to edit. id= " + id);
- id = -1;
+ Log.d("No waypoint loaded to edit. id= " + waypointId);
+ waypointId = -1;
} else {
geocode = waypoint.getGeocode();
prefix = waypoint.getPrefix();
@@ -119,14 +116,23 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
}
Dialogs.moveCursorToEnd(note);
}
- final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
- setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
+ new AsyncTask<Void, Void, Geocache>() {
+ @Override
+ protected Geocache doInBackground(final Void... params) {
+ return DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_ONLY);
+ }
+
+ @Override
+ protected void onPostExecute(final Geocache cache) {
+ setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
+ }
+ }.execute();
}
if (own) {
initializeWaypointTypeSelector();
}
- } catch (RuntimeException e) {
+ } catch (final RuntimeException e) {
Log.e("EditWaypointActivity.loadWaypointHandler", e);
} finally {
if (waitDialog != null) {
@@ -138,17 +144,17 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
};
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.editwaypoint_activity);
- if (StringUtils.isBlank(geocode) && id <= 0) {
+ if (StringUtils.isBlank(geocode) && waypointId <= 0) {
showToast(res.getString(R.string.err_waypoint_cache_unknown));
finish();
return;
}
- if (id <= 0) {
+ if (waypointId <= 0) {
setTitle(res.getString(R.string.waypoint_add_title));
} else {
setTitle(res.getString(R.string.waypoint_edit_title));
@@ -159,11 +165,11 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
addWaypoint.setOnClickListener(new SaveWaypointListener());
- List<String> wayPointNames = new ArrayList<>();
- for (WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
+ final List<String> wayPointNames = new ArrayList<>();
+ for (final WaypointType wpt : WaypointType.ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL) {
wayPointNames.add(wpt.getL10n());
}
- ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames);
+ final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames);
waypointName.setAdapter(adapter);
if (savedInstanceState != null) {
@@ -174,7 +180,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
setCoordsModificationVisibility(ConnectorFactory.getConnector(geocode), cache);
}
- if (id > 0) { // existing waypoint
+ if (waypointId > 0) { // existing waypoint
waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
waitDialog.setCancelable(true);
@@ -189,7 +195,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
disableSuggestions(distanceView);
}
- private void setCoordsModificationVisibility(IConnector con, Geocache cache) {
+ private void setCoordsModificationVisibility(final IConnector con, final Geocache cache) {
if (cache != null && (cache.getType() == CacheType.MYSTERY || cache.getType() == CacheType.MULTI)) {
coordinatesGroup.setVisibility(View.VISIBLE);
modifyBoth.setVisibility(con.supportsOwnCoordinates() ? View.VISIBLE : View.GONE);
@@ -205,18 +211,23 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
}
private void initializeWaypointTypeSelector() {
- ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, POSSIBLE_WAYPOINT_TYPES.toArray(new WaypointType[POSSIBLE_WAYPOINT_TYPES.size()]));
+ final ArrayAdapter<WaypointType> wpAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, POSSIBLE_WAYPOINT_TYPES.toArray(new WaypointType[POSSIBLE_WAYPOINT_TYPES.size()]));
wpAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
waypointTypeSelector.setAdapter(wpAdapter);
waypointTypeSelector.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
- public void onItemSelected(AdapterView<?> parent, View v, int pos, long id) {
+ public void onItemSelected(final AdapterView<?> parent, final View v, final int pos, final long id) {
+ final String oldDefaultName = waypointTypeSelectorPosition >= 0 ? getDefaultWaypointName(POSSIBLE_WAYPOINT_TYPES.get(waypointTypeSelectorPosition)) : StringUtils.EMPTY;
waypointTypeSelectorPosition = pos;
+ final String currentName = waypointName.getText().toString().trim();
+ if (StringUtils.isBlank(currentName) || oldDefaultName.equals(currentName)) {
+ waypointName.setText(getDefaultWaypointName(getSelectedWaypointType()));
+ }
}
@Override
- public void onNothingSelected(AdapterView<?> parent) {
+ public void onNothingSelected(final AdapterView<?> parent) {
}
});
@@ -249,17 +260,13 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
private void initializeDistanceUnitSelector() {
distanceUnits = new ArrayList<>(Arrays.asList(res.getStringArray(R.array.distance_units)));
if (initViews) {
- distanceUnitSelector.setSelection(Settings.isUseImperialUnits() ? 2 : 0); //0:m, 2:ft
+ distanceUnitSelector.setSelection(Settings.useImperialUnits() ? 2 : 0); //0:m, 2:ft
}
}
final private GeoDirHandler geoDirHandler = new GeoDirHandler() {
@Override
- public void updateGeoData(final IGeoData geo) {
- if (geo.getCoords() == null) {
- return;
- }
-
+ public void updateGeoData(final GeoData geo) {
try {
buttonLat.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW));
buttonLon.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW));
@@ -274,10 +281,10 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
@Override
public void run() {
try {
- waypoint = DataStore.loadWaypoint(id);
+ waypoint = DataStore.loadWaypoint(waypointId);
loadWaypointHandler.sendMessage(Message.obtain());
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("EditWaypointActivity.loadWaypoint.run", e);
}
}
@@ -286,28 +293,71 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
private class CoordDialogListener implements View.OnClickListener {
@Override
- public void onClick(View arg0) {
+ public void onClick(final View arg0) {
Geopoint gp = null;
try {
gp = new Geopoint(buttonLat.getText().toString(), buttonLon.getText().toString());
- } catch (Geopoint.ParseException e) {
+ } catch (final Geopoint.ParseException ignored) {
// button text is blank when creating new waypoint
}
- Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
- CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(cache, gp, app.currentGeo());
- coordsDialog.setCancelable(true);
- coordsDialog.show(getSupportFragmentManager(),"wpeditdialog");
+ final Geopoint geopoint = gp;
+ new AsyncTask<Void, Void, Geocache>() {
+ @Override
+ protected Geocache doInBackground(final Void... params) {
+ return DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ }
+
+ @Override
+ protected void onPostExecute(final Geocache cache) {
+ final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(cache, geopoint, Sensors.getInstance().currentGeo());
+ coordsDialog.setCancelable(true);
+ coordsDialog.show(getSupportFragmentManager(), "wpeditdialog");
+ }
+ }.execute();
}
}
@Override
- public void updateCoordinates(Geopoint gp) {
+ public void updateCoordinates(final Geopoint gp) {
buttonLat.setText(gp.format(GeopointFormatter.Format.LAT_DECMINUTE));
buttonLon.setText(gp.format(GeopointFormatter.Format.LON_DECMINUTE));
}
+ /**
+ * Suffix the waypoint type with a running number to get a default name.
+ *
+ * @param type
+ * type to create a new default name for
+ *
+ */
+ private String getDefaultWaypointName(final WaypointType type) {
+ final ArrayList<String> wpNames = new ArrayList<>();
+ for (final Waypoint waypoint : cache.getWaypoints()) {
+ wpNames.add(waypoint.getName());
+ }
+ // try final and trailhead without index
+ if (type == WaypointType.FINAL || type == WaypointType.TRAILHEAD) {
+ if (!wpNames.contains(type.getL10n())) {
+ return type.getL10n();
+ }
+ }
+ // for other types add an index by default, which is highest found index + 1
+ int max = 0;
+ for (int i = 0; i < 30; i++) {
+ if (wpNames.contains(type.getL10n() + " " + i)) {
+ max = i;
+ }
+ }
+ return type.getL10n() + " " + (max + 1);
+ }
+
+ private WaypointType getSelectedWaypointType() {
+ final int selectedTypeIndex = waypointTypeSelector.getSelectedItemPosition();
+ return selectedTypeIndex >= 0 ? POSSIBLE_WAYPOINT_TYPES.get(selectedTypeIndex) : waypoint.getWaypointType();
+ }
+
public static final int SUCCESS = 0;
public static final int UPLOAD_START = 1;
public static final int UPLOAD_ERROR = 2;
@@ -318,7 +368,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
private class SaveWaypointListener implements View.OnClickListener {
@Override
- public void onClick(View arg0) {
+ public void onClick(final View arg0) {
final String bearingText = bearing.getText().toString();
// combine distance from EditText and distanceUnit saved from Spinner
final String distanceText = distanceView.getText().toString() + distanceUnits.get(distanceUnitSelector.getSelectedItemPosition());
@@ -336,17 +386,12 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
if (StringUtils.isNotBlank(latText) && StringUtils.isNotBlank(lonText)) {
try {
coords = new Geopoint(latText, lonText);
- } catch (Geopoint.ParseException e) {
+ } catch (final Geopoint.ParseException e) {
showToast(res.getString(e.resource));
return;
}
} else {
- final IGeoData geo = app.currentGeo();
- if (geo.getCoords() == null) {
- showToast(res.getString(R.string.err_point_curr_position_unavailable));
- return;
- }
- coords = geo.getCoords();
+ coords = Sensors.getInstance().currentGeo().getCoords();
}
if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) {
@@ -354,7 +399,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
double bearing;
try {
bearing = Double.parseDouble(bearingText);
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
Dialogs.message(EditWaypointActivity.this, R.string.err_point_bear_and_dist_title, R.string.err_point_bear_and_dist);
return;
}
@@ -362,8 +407,8 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
double distance;
try {
distance = DistanceParser.parseDistance(distanceText,
- !Settings.isUseImperialUnits());
- } catch (NumberFormatException e) {
+ !Settings.useImperialUnits());
+ } catch (final NumberFormatException ignored) {
showToast(res.getString(R.string.err_parse_dist));
return;
}
@@ -371,25 +416,22 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
coords = coords.project(bearing, distance);
}
- // if no name is given, just give the waypoint its number as name
final String givenName = waypointName.getText().toString().trim();
- final String name = StringUtils.isNotEmpty(givenName) ? givenName : res.getString(R.string.waypoint) + " " + (wpCount + 1);
+ final String name = StringUtils.defaultIfBlank(givenName, getDefaultWaypointName(getSelectedWaypointType()));
final String noteText = note.getText().toString().trim();
final Geopoint coordsToSave = coords;
- final int selectedTypeIndex = waypointTypeSelector.getSelectedItemPosition();
- final WaypointType type = selectedTypeIndex >= 0 ? POSSIBLE_WAYPOINT_TYPES.get(selectedTypeIndex) : waypoint.getWaypointType();
+ final WaypointType type = getSelectedWaypointType();
final boolean visited = visitedCheckBox.isChecked();
final ProgressDialog progress = ProgressDialog.show(EditWaypointActivity.this, getString(R.string.waypoint), getString(R.string.waypoint_being_saved), true);
final Handler finishHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
- // TODO: The order of showToast, progress.dismiss and finish is different in these cases. Why?
+ public void handleMessage(final Message msg) {
switch (msg.what) {
case UPLOAD_SUCCESS:
- showToast(getString(R.string.waypoint_coordinates_has_been_modified_on_website, coordsToSave));
progress.dismiss();
finish();
+ showToast(getString(R.string.waypoint_coordinates_has_been_modified_on_website, coordsToSave));
break;
case SUCCESS:
progress.dismiss();
@@ -422,7 +464,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
class SaveWptTask extends AsyncTask<Void, Void, Void> {
@Override
- protected Void doInBackground(Void... params) {
+ protected Void doInBackground(final Void... params) {
final Waypoint waypoint = new Waypoint(name, type, own);
waypoint.setGeocode(geocode);
waypoint.setPrefix(prefix);
@@ -430,14 +472,14 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
waypoint.setCoords(coordsToSave);
waypoint.setNote(noteText);
waypoint.setVisited(visited);
- waypoint.setId(id);
+ waypoint.setId(waypointId);
- Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
if (cache == null) {
finishHandler.sendEmptyMessage(SAVE_ERROR);
return null;
}
- Waypoint oldWaypoint = cache.getWaypointById(id);
+ final Waypoint oldWaypoint = cache.getWaypointById(waypointId);
if (cache.addOrChangeWaypoint(waypoint, true)) {
DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
if (!StaticMapsProvider.hasAllStaticMapsForWaypoint(geocode, waypoint)) {
@@ -460,7 +502,7 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
finishHandler.sendEmptyMessage(UPLOAD_START);
if (cache.supportsOwnCoordinates()) {
- boolean result = uploadModifiedCoords(cache, waypoint.getCoords());
+ final boolean result = uploadModifiedCoords(cache, waypoint.getCoords());
finishHandler.sendEmptyMessage(result ? SUCCESS : UPLOAD_ERROR);
} else {
showToast(getString(R.string.waypoint_coordinates_couldnt_be_modified_on_website));
@@ -485,10 +527,10 @@ public class EditWaypointActivity extends AbstractActionBarActivity implements C
}
public static void startActivityEditWaypoint(final Context context, final Geocache cache, final int waypointId) {
- EditWaypointActivity_.intent(context).geocode(cache.getGeocode()).id(waypointId).start();
+ EditWaypointActivity_.intent(context).geocode(cache.getGeocode()).waypointId(waypointId).start();
}
public static void startActivityAddWaypoint(final Context context, final Geocache cache) {
- EditWaypointActivity_.intent(context).geocode(cache.getGeocode()).wpCount(cache.getWaypoints().size()).start();
+ EditWaypointActivity_.intent(context).geocode(cache.getGeocode()).start();
}
}
diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java
index d9b2856..033196c 100644
--- a/main/src/cgeo/geocaching/Geocache.java
+++ b/main/src/cgeo/geocaching/Geocache.java
@@ -12,22 +12,20 @@ import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.connector.gc.UncertainProperty;
-import cgeo.geocaching.enumerations.CacheAttribute;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.enumerations.LoadFlags.LoadFlag;
import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.files.GPXParser;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.CalendarUtils;
import cgeo.geocaching.utils.CancellableHandler;
-import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.LazyInitializedList;
import cgeo.geocaching.utils.Log;
@@ -40,7 +38,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
-import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@@ -50,18 +47,17 @@ import org.eclipse.jdt.annotation.Nullable;
import rx.Scheduler;
import rx.Subscription;
import rx.functions.Action0;
+import rx.schedulers.Schedulers;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.text.Html;
-import android.text.Html.ImageGetter;
import java.io.File;
import java.util.ArrayList;
@@ -69,10 +65,9 @@ import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
+import java.util.EnumMap;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -80,16 +75,18 @@ import java.util.Set;
import java.util.regex.Pattern;
/**
- * Internal c:geo representation of a "cache"
+ * Internal representation of a "cache"
*/
-public class Geocache implements ICache, IWaypoint {
+public class Geocache implements IWaypoint {
private static final int OWN_WP_PREFIX_OFFSET = 17;
private long updated = 0;
private long detailedUpdate = 0;
private long visitedDate = 0;
- private int listId = StoredList.TEMPORARY_LIST_ID;
+ private int listId = StoredList.TEMPORARY_LIST.id;
private boolean detailed = false;
+
+ @NonNull
private String geocode = "";
private String cacheId = "";
private String guid = "";
@@ -102,7 +99,7 @@ public class Geocache implements ICache, IWaypoint {
* lazy initialized
*/
private String hint = null;
- private CacheSize size = CacheSize.UNKNOWN;
+ @NonNull private CacheSize size = CacheSize.UNKNOWN;
private float difficulty = 0;
private float terrain = 0;
private Float direction = null;
@@ -137,19 +134,19 @@ public class Geocache implements ICache, IWaypoint {
private final LazyInitializedList<String> attributes = new LazyInitializedList<String>() {
@Override
public List<String> call() {
- return DataStore.loadAttributes(geocode);
+ return inDatabase() ? DataStore.loadAttributes(geocode) : new LinkedList<String>();
}
};
private final LazyInitializedList<Waypoint> waypoints = new LazyInitializedList<Waypoint>() {
@Override
public List<Waypoint> call() {
- return DataStore.loadWaypoints(geocode);
+ return inDatabase() ? DataStore.loadWaypoints(geocode) : new LinkedList<Waypoint>();
}
};
private List<Image> spoilers = null;
private List<Trackable> inventory = null;
- private Map<LogType, Integer> logCounts = new HashMap<>();
+ private Map<LogType, Integer> logCounts = new EnumMap<>(LogType.class);
private boolean userModifiedCoords = false;
// temporary values
private boolean statusChecked = false;
@@ -163,10 +160,6 @@ public class Geocache implements ICache, IWaypoint {
private Handler changeNotificationHandler = null;
- // Images whose URL contains one of those patterns will not be available on the Images tab
- // for opening into an external application.
- private final String[] NO_EXTERNAL = new String[]{"geocheck.org"};
-
/**
* Create a new cache. To be used everywhere except for the GPX parser
*/
@@ -178,7 +171,7 @@ public class Geocache implements ICache, IWaypoint {
* Cache constructor to be used by the GPX parser only. This constructor explicitly sets several members to empty
* lists.
*
- * @param gpxParser
+ * @param gpxParser ignored parameter allowing to select this constructor
*/
public Geocache(final GPXParser gpxParser) {
setReliableLatLon(true);
@@ -220,7 +213,7 @@ public class Geocache implements ICache, IWaypoint {
// if parsed cache is not yet detailed and stored is, the information of
// the parsed cache will be overwritten
if (!detailed && other.detailed) {
- detailed = other.detailed;
+ detailed = true;
detailedUpdate = other.detailedUpdate;
// boolean values must be enumerated here. Other types are assigned outside this if-statement
reliableLatLon = other.reliableLatLon;
@@ -251,7 +244,7 @@ public class Geocache implements ICache, IWaypoint {
if (visitedDate == 0) {
visitedDate = other.visitedDate;
}
- if (listId == StoredList.TEMPORARY_LIST_ID) {
+ if (listId == StoredList.TEMPORARY_LIST.id) {
listId = other.listId;
}
if (StringUtils.isBlank(geocode)) {
@@ -279,7 +272,7 @@ public class Geocache implements ICache, IWaypoint {
if (!detailed && StringUtils.isBlank(getHint())) {
hint = other.getHint();
}
- if (size == null || CacheSize.UNKNOWN == size) {
+ if (size == CacheSize.UNKNOWN) {
size = other.size;
}
if (difficulty == 0) {
@@ -455,11 +448,7 @@ public class Geocache implements ICache, IWaypoint {
ActivityMixin.showToast(fromActivity, fromActivity.getResources().getString(R.string.err_cannot_log_visit));
return;
}
- final Intent logVisitIntent = new Intent(fromActivity, LogCacheActivity.class);
- logVisitIntent.putExtra(LogCacheActivity.EXTRAS_ID, cacheId);
- logVisitIntent.putExtra(LogCacheActivity.EXTRAS_GEOCODE, geocode);
-
- fromActivity.startActivity(logVisitIntent);
+ fromActivity.startActivity(LogCacheActivity.getLogCacheIntent(fromActivity, cacheId, geocode));
}
public void logOffline(final Activity fromActivity, final LogType logType) {
@@ -491,11 +480,15 @@ public class Geocache implements ICache, IWaypoint {
notifyChange();
}
+ @NonNull
public List<LogType> getPossibleLogTypes() {
return getConnector().getPossibleLogTypes(this);
}
public void openInBrowser(final Activity fromActivity) {
+ if (getUrl() == null) {
+ return;
+ }
final Intent viewIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getLongUrl()));
// Check if cgeo is the default, show the chooser to let the user choose a browser
@@ -514,19 +507,11 @@ public class Geocache implements ICache, IWaypoint {
}
}
-
- private String getCacheUrl() {
- return getConnector().getCacheUrl(this);
- }
-
+ @NonNull
private IConnector getConnector() {
return ConnectorFactory.getConnector(this);
}
- public boolean canOpenInBrowser() {
- return getCacheUrl() != null;
- }
-
public boolean supportsRefresh() {
return getConnector() instanceof ISearchByGeocode;
}
@@ -551,11 +536,11 @@ public class Geocache implements ICache, IWaypoint {
return getConnector().supportsOwnCoordinates();
}
+ @NonNull
public ILoggingManager getLoggingManager(final LogCacheActivity activity) {
return getConnector().getLoggingManager(activity, this);
}
- @Override
public float getDifficulty() {
return difficulty;
}
@@ -565,35 +550,30 @@ public class Geocache implements ICache, IWaypoint {
return geocode;
}
- @Override
+ /**
+ * @return displayed owner, might differ from the real owner
+ */
public String getOwnerDisplayName() {
return ownerDisplayName;
}
- @Override
+ @NonNull
public CacheSize getSize() {
- if (size == null) {
- return CacheSize.UNKNOWN;
- }
return size;
}
- @Override
public float getTerrain() {
return terrain;
}
- @Override
public boolean isArchived() {
return BooleanUtils.isTrue(archived);
}
- @Override
public boolean isDisabled() {
return BooleanUtils.isTrue(disabled);
}
- @Override
public boolean isPremiumMembersOnly() {
return BooleanUtils.isTrue(premiumMembersOnly);
}
@@ -602,20 +582,27 @@ public class Geocache implements ICache, IWaypoint {
this.premiumMembersOnly = members;
}
- @Override
+ /**
+ *
+ * @return {@code true} if the user is the owner of the cache, {@code false} otherwise
+ */
public boolean isOwner() {
return getConnector().isOwner(this);
}
- @Override
+ /**
+ * @return GC username of the (actual) owner, might differ from the owner. Never empty.
+ */
+ @NonNull
public String getOwnerUserId() {
return ownerUserId;
}
/**
* Attention, calling this method may trigger a database access for the cache!
+ *
+ * @return the decrypted hint
*/
- @Override
public String getHint() {
initializeCacheTexts();
assertTextNotNull(hint, "Hint");
@@ -635,7 +622,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getDescription() {
initializeCacheTexts();
assertTextNotNull(description, "Description");
@@ -647,18 +633,25 @@ public class Geocache implements ICache, IWaypoint {
*/
private void initializeCacheTexts() {
if (description == null || shortdesc == null || hint == null || location == null) {
- final Geocache partial = DataStore.loadCacheTexts(this.getGeocode());
- if (description == null) {
- setDescription(partial.getDescription());
- }
- if (shortdesc == null) {
- setShortDescription(partial.getShortDescription());
- }
- if (hint == null) {
- setHint(partial.getHint());
- }
- if (location == null) {
- setLocation(partial.getLocation());
+ if (inDatabase()) {
+ final Geocache partial = DataStore.loadCacheTexts(this.getGeocode());
+ if (description == null) {
+ setDescription(partial.getDescription());
+ }
+ if (shortdesc == null) {
+ setShortDescription(partial.getShortDescription());
+ }
+ if (hint == null) {
+ setHint(partial.getHint());
+ }
+ if (location == null) {
+ setLocation(partial.getLocation());
+ }
+ } else {
+ description = StringUtils.defaultString(description);
+ shortdesc = StringUtils.defaultString(shortdesc);
+ hint = StringUtils.defaultString(hint);
+ location = StringUtils.defaultString(location);
}
}
}
@@ -666,7 +659,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getShortDescription() {
initializeCacheTexts();
assertTextNotNull(shortdesc, "Short description");
@@ -678,7 +670,6 @@ public class Geocache implements ICache, IWaypoint {
return name;
}
- @Override
public String getCacheId() {
if (StringUtils.isBlank(cacheId) && getConnector().equals(GCConnector.getInstance())) {
return String.valueOf(GCConstants.gccodeToGCId(geocode));
@@ -687,7 +678,6 @@ public class Geocache implements ICache, IWaypoint {
return cacheId;
}
- @Override
public String getGuid() {
return guid;
}
@@ -695,14 +685,12 @@ public class Geocache implements ICache, IWaypoint {
/**
* Attention, calling this method may trigger a database access for the cache!
*/
- @Override
public String getLocation() {
initializeCacheTexts();
assertTextNotNull(location, "Location");
return location;
}
- @Override
public String getPersonalNote() {
// non premium members have no personal notes, premium members have an empty string by default.
// map both to null, so other code doesn't need to differentiate
@@ -713,15 +701,13 @@ public class Geocache implements ICache, IWaypoint {
return getConnector() instanceof ISearchByCenter;
}
- public void shareCache(final Activity fromActivity, final Resources res) {
- if (geocode == null) {
- return;
- }
-
+ public void shareCache(@NonNull final Activity fromActivity, final Resources res) {
final Intent intent = getShareIntent();
fromActivity.startActivity(Intent.createChooser(intent, res.getText(R.string.cache_menu_share)));
}
+
+ @NonNull
public Intent getShareIntent() {
final StringBuilder subject = new StringBuilder("Geocache ");
subject.append(geocode);
@@ -732,20 +718,25 @@ public class Geocache implements ICache, IWaypoint {
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject.toString());
- intent.putExtra(Intent.EXTRA_TEXT, getUrl());
+ intent.putExtra(Intent.EXTRA_TEXT, StringUtils.defaultString(getUrl()));
return intent;
}
+ @Nullable
public String getUrl() {
return getConnector().getCacheUrl(this);
}
+ @Nullable
public String getLongUrl() {
return getConnector().getLongCacheUrl(this);
}
- public String getCgeoUrl() { return getConnector().getCacheUrl(this); }
+ @Nullable
+ public String getCgeoUrl() {
+ return getConnector().getCacheUrl(this);
+ }
public boolean supportsGCVote() {
return StringUtils.startsWithIgnoreCase(geocode, "GC");
@@ -755,12 +746,14 @@ public class Geocache implements ICache, IWaypoint {
this.description = description;
}
- @Override
public boolean isFound() {
return BooleanUtils.isTrue(found);
}
- @Override
+ /**
+ *
+ * @return {@code true} if the user has put a favorite point onto this cache
+ */
public boolean isFavorite() {
return BooleanUtils.isTrue(favorite);
}
@@ -769,18 +762,16 @@ public class Geocache implements ICache, IWaypoint {
this.favorite = favorite;
}
- @Override
@Nullable
public Date getHiddenDate() {
return hidden;
}
- @Override
+ @NonNull
public List<String> getAttributes() {
return attributes.getUnderlyingList();
}
- @Override
public List<Trackable> getInventory() {
return inventory;
}
@@ -792,22 +783,25 @@ public class Geocache implements ICache, IWaypoint {
spoilers.add(spoiler);
}
- @Override
+ @NonNull
public List<Image> getSpoilers() {
return ListUtils.unmodifiableList(ListUtils.emptyIfNull(spoilers));
}
- @Override
+ /**
+ * @return a statistic how often the caches has been found, disabled, archived etc.
+ */
public Map<LogType, Integer> getLogCounts() {
return logCounts;
}
- @Override
public int getFavoritePoints() {
return favoritePoints;
}
- @Override
+ /**
+ * @return the normalized cached name to be used for sorting, taking into account the numerical parts in the name
+ */
public String getNameForSorting() {
if (null == nameForSorting) {
nameForSorting = name;
@@ -908,8 +902,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Set reliable coordinates
- *
- * @param coords
*/
public void setCoords(final Geopoint coords) {
this.coords = new UncertainProperty<>(coords);
@@ -917,9 +909,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* Set unreliable coordinates from a certain map zoom level
- *
- * @param coords
- * @param zoomlevel
*/
public void setCoords(final Geopoint coords, final int zoomlevel) {
this.coords = new UncertainProperty<>(coords, zoomlevel);
@@ -976,7 +965,9 @@ public class Geocache implements ICache, IWaypoint {
this.inventoryItems = inventoryItems;
}
- @Override
+ /**
+ * @return {@code true} if the cache is on the user's watchlist, {@code false} otherwise
+ */
public boolean isOnWatchlist() {
return BooleanUtils.isTrue(onWatchlist);
}
@@ -990,6 +981,7 @@ public class Geocache implements ICache, IWaypoint {
*
* @return always non <code>null</code>
*/
+ @NonNull
public List<Waypoint> getWaypoints() {
return waypoints.getUnderlyingList();
}
@@ -1028,7 +1020,7 @@ public class Geocache implements ICache, IWaypoint {
*/
@NonNull
public List<LogEntry> getLogs() {
- return DataStore.loadLogs(geocode);
+ return inDatabase() ? DataStore.loadLogs(geocode) : Collections.<LogEntry>emptyList();
}
/**
@@ -1069,7 +1061,7 @@ public class Geocache implements ICache, IWaypoint {
this.directionImg = directionImg;
}
- public void setGeocode(final String geocode) {
+ public void setGeocode(@NonNull final String geocode) {
this.geocode = StringUtils.upperCase(geocode);
}
@@ -1097,13 +1089,8 @@ public class Geocache implements ICache, IWaypoint {
this.hint = hint;
}
- public void setSize(final CacheSize size) {
- if (size == null) {
- this.size = CacheSize.UNKNOWN;
- }
- else {
- this.size = size;
- }
+ public void setSize(@NonNull final CacheSize size) {
+ this.size = size;
}
public void setDifficulty(final float difficulty) {
@@ -1160,7 +1147,6 @@ public class Geocache implements ICache, IWaypoint {
*
* @returns Never null
*/
- @Override
public CacheType getType() {
return cacheType.getValue();
}
@@ -1203,6 +1189,13 @@ public class Geocache implements ICache, IWaypoint {
}
/**
+ * Check if this cache instance comes from or has been stored into the database.
+ */
+ public boolean inDatabase() {
+ return storageLocation.contains(StorageLocation.DATABASE);
+ }
+
+ /**
* @param waypoint
* Waypoint to add to the cache
* @param saveToDatabase
@@ -1214,7 +1207,9 @@ public class Geocache implements ICache, IWaypoint {
waypoint.setGeocode(geocode);
if (waypoint.getId() < 0) { // this is a new waypoint
- assignUniquePrefix(waypoint);
+ if (StringUtils.isBlank(waypoint.getPrefix())) {
+ assignUniquePrefix(waypoint);
+ }
waypoints.add(waypoint);
if (waypoint.isFinalWithCoords()) {
finalDefined = true;
@@ -1249,13 +1244,14 @@ public class Geocache implements ICache, IWaypoint {
}
for (int i = OWN_WP_PREFIX_OFFSET; i < 100; i++) {
- final String prefixCandidate = StringUtils.leftPad(String.valueOf(i), 2, '0');
+ final String prefixCandidate = String.valueOf(i);
if (!assignedPrefixes.contains(prefixCandidate)) {
waypoint.setPrefix(prefixCandidate);
- break;
+ return;
}
}
+ throw new IllegalStateException("too many waypoints, unable to assign unique prefix");
}
public boolean hasWaypoints() {
@@ -1341,8 +1337,6 @@ public class Geocache implements ICache, IWaypoint {
/**
* deletes any waypoint
- *
- * @param waypoint
*/
public void deleteWaypointForce(final Waypoint waypoint) {
@@ -1389,12 +1383,15 @@ public class Geocache implements ICache, IWaypoint {
/**
* Detect coordinates in the personal note and convert them to user defined waypoints. Works by rule of thumb.
*/
- public void parseWaypointsFromNote() {
+ public boolean parseWaypointsFromNote() {
+ boolean changed = false;
for (final Waypoint waypoint : Waypoint.parseWaypointsFromNote(StringUtils.defaultString(getPersonalNote()))) {
if (!hasIdenticalWaypoint(waypoint.getCoords())) {
addOrChangeWaypoint(waypoint, false);
+ changed = true;
}
}
+ return changed;
}
private boolean hasIdenticalWaypoint(final Geopoint point) {
@@ -1432,7 +1429,7 @@ public class Geocache implements ICache, IWaypoint {
}
public void store(final CancellableHandler handler) {
- store(StoredList.TEMPORARY_LIST_ID, handler);
+ store(StoredList.TEMPORARY_LIST.id, handler);
}
public void store(final int listId, final CancellableHandler handler) {
@@ -1457,8 +1454,8 @@ public class Geocache implements ICache, IWaypoint {
return "cache";
}
- public Subscription drop(final Handler handler, final Scheduler scheduler) {
- return scheduler.createWorker().schedule(new Action0() {
+ public Subscription drop(final Handler handler) {
+ return Schedulers.io().createWorker().schedule(new Action0() {
@Override
public void call() {
try {
@@ -1476,54 +1473,37 @@ public class Geocache implements ICache, IWaypoint {
DataStore.removeCache(getGeocode(), EnumSet.of(RemoveFlag.CACHE));
}
- public void checkFields() {
- if (StringUtils.isBlank(getGeocode())) {
- Log.w("geo code not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getName())) {
- Log.w("name not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getGuid())) {
- Log.w("guid not parsed correctly for " + geocode);
- }
- if (getTerrain() == 0.0) {
- Log.w("terrain not parsed correctly for " + geocode);
- }
- if (getDifficulty() == 0.0) {
- Log.w("difficulty not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getOwnerDisplayName())) {
- Log.w("owner display name not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getOwnerUserId())) {
- Log.w("owner user id real not parsed correctly for " + geocode);
- }
- if (getHiddenDate() == null) {
- Log.w("hidden not parsed correctly for " + geocode);
- }
- if (getFavoritePoints() < 0) {
- Log.w("favoriteCount not parsed correctly for " + geocode);
- }
- if (getSize() == null) {
- Log.w("size not parsed correctly for " + geocode);
- }
- if (getType() == null || getType() == CacheType.UNKNOWN) {
- Log.w("type not parsed correctly for " + geocode);
- }
- if (getCoords() == null) {
- Log.w("coordinates not parsed correctly for " + geocode);
- }
- if (StringUtils.isBlank(getLocation())) {
- Log.w("location not parsed correctly for " + geocode);
+ private void warnIncorrectParsingIf(final boolean incorrect, final String field) {
+ if (incorrect) {
+ Log.w(field + " not parsed correctly for " + geocode);
}
}
+ private void warnIncorrectParsingIfBlank(final String str, final String field) {
+ warnIncorrectParsingIf(StringUtils.isBlank(str), field);
+ }
+
+ public void checkFields() {
+ warnIncorrectParsingIfBlank(getGeocode(), "geo");
+ warnIncorrectParsingIfBlank(getName(), "name");
+ warnIncorrectParsingIfBlank(getGuid(), "guid");
+ warnIncorrectParsingIf(getTerrain() == 0.0, "terrain");
+ warnIncorrectParsingIf(getDifficulty() == 0.0, "difficulty");
+ warnIncorrectParsingIfBlank(getOwnerDisplayName(), "owner");
+ warnIncorrectParsingIfBlank(getOwnerUserId(), "owner");
+ warnIncorrectParsingIf(getHiddenDate() == null, "hidden");
+ warnIncorrectParsingIf(getFavoritePoints() < 0, "favoriteCount");
+ warnIncorrectParsingIf(getSize() == CacheSize.UNKNOWN, "size");
+ warnIncorrectParsingIf(getType() == null || getType() == CacheType.UNKNOWN, "type");
+ warnIncorrectParsingIf(getCoords() == null, "coordinates");
+ warnIncorrectParsingIfBlank(getLocation(), "location");
+ }
+
public Subscription refresh(final CancellableHandler handler, final Scheduler scheduler) {
return scheduler.createWorker().schedule(new Action0() {
@Override
public void call() {
refreshSynchronous(handler);
- handler.sendEmptyMessage(CancellableHandler.DONE);
}
});
}
@@ -1614,7 +1594,7 @@ public class Geocache implements ICache, IWaypoint {
RxUtils.waitForCompletion(StaticMapsProvider.downloadMaps(cache), imgGetter.waitForEndObservable(handler));
if (handler != null) {
- handler.sendMessage(Message.obtain());
+ handler.sendEmptyMessage(CancellableHandler.DONE);
}
} catch (final Exception e) {
Log.e("Geocache.storeCache", e);
@@ -1627,7 +1607,7 @@ public class Geocache implements ICache, IWaypoint {
return null;
}
- if (!forceReload && listId == StoredList.TEMPORARY_LIST_ID && (DataStore.isOffline(geocode, guid) || DataStore.isThere(geocode, guid, true, true))) {
+ if (!forceReload && listId == StoredList.TEMPORARY_LIST.id && (DataStore.isOffline(geocode, guid) || DataStore.isThere(geocode, guid, true, true))) {
final SearchResult search = new SearchResult();
final String realGeocode = StringUtils.isNotBlank(geocode) ? geocode : DataStore.getGeocodeForGuid(guid);
search.addGeocode(realGeocode);
@@ -1635,7 +1615,7 @@ public class Geocache implements ICache, IWaypoint {
}
// if we have no geocode, we can't dynamically select the handler, but must explicitly use GC
- if (geocode == null && guid != null) {
+ if (geocode == null) {
return GCConnector.getInstance().searchByGeocode(null, guid, handler);
}
@@ -1655,9 +1635,9 @@ public class Geocache implements ICache, IWaypoint {
*
* @return start time in minutes after midnight
*/
- public String guessEventTimeMinutes() {
+ public int guessEventTimeMinutes() {
if (!isEventCache()) {
- return null;
+ return -1;
}
final String hourLocalized = CgeoApplication.getInstance().getString(R.string.cache_time_full_hours);
@@ -1669,7 +1649,7 @@ public class Geocache implements ICache, IWaypoint {
// 17 - 20 o'clock
patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?" + "\\s*(?:-|[a-z]+)\\s*" + "(?:\\d{1,2})(?:\\.00)?" + "\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
// 12 o'clock, 12.00 o'clock
- patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.00)?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
+ patterns.add(Pattern.compile("\\b(\\d{1,2})(?:\\.(00|15|30|45))?\\s+" + Pattern.quote(hourLocalized), Pattern.CASE_INSENSITIVE));
}
final String searchText = getShortDescription() + ' ' + getDescription();
@@ -1679,64 +1659,25 @@ public class Geocache implements ICache, IWaypoint {
try {
final int hours = Integer.parseInt(matcher.group(1));
int minutes = 0;
- if (matcher.groupCount() >= 2) {
+ if (matcher.groupCount() >= 2 && !StringUtils.isEmpty(matcher.group(2))) {
minutes = Integer.parseInt(matcher.group(2));
}
if (hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60) {
- return String.valueOf(hours * 60 + minutes);
+ return hours * 60 + minutes;
}
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// cannot happen, but static code analysis doesn't know
}
}
}
- return null;
- }
-
- /**
- * check whether the cache has a given attribute
- *
- * @param attribute
- * @param yes
- * true if we are looking for the attribute_yes version, false for the attribute_no version
- * @return
- */
- public boolean hasAttribute(final CacheAttribute attribute, final boolean yes) {
- Geocache fullCache = DataStore.loadCache(getGeocode(), EnumSet.of(LoadFlag.ATTRIBUTES));
- if (fullCache == null) {
- fullCache = this;
- }
- return fullCache.getAttributes().contains(attribute.getAttributeName(yes));
+ return -1;
}
public boolean hasStaticMap() {
return StaticMapsProvider.hasStaticMap(this);
}
- public static final Predicate<Geocache> hasStaticMap = new Predicate<Geocache>() {
- @Override
- public boolean evaluate(final Geocache cache) {
- return cache.hasStaticMap();
- }
- };
-
- private void addDescriptionImagesUrls(final Collection<Image> images) {
- final Set<String> urls = new LinkedHashSet<>();
- for (final Image image : images) {
- urls.add(image.getUrl());
- }
- Html.fromHtml(getDescription(), new ImageGetter() {
- @Override
- public Drawable getDrawable(final String source) {
- if (!urls.contains(source) && !ImageUtils.containsPattern(source, NO_EXTERNAL)) {
- images.add(new Image(source, geocode));
- urls.add(source);
- }
- return null;
- }
- }, null);
- }
-
+ @NonNull
public Collection<Image> getImages() {
final LinkedList<Image> result = new LinkedList<>();
result.addAll(getSpoilers());
@@ -1744,22 +1685,23 @@ public class Geocache implements ICache, IWaypoint {
for (final LogEntry log : getLogs()) {
result.addAll(log.getLogImages());
}
- final Set<String> urls = new HashSet<>(result.size());
- for (final Image image : result) {
- urls.add(image.getUrl());
- }
- addDescriptionImagesUrls(result);
+ ImageUtils.addImagesFromHtml(result, geocode, getShortDescription(), getDescription());
return result;
}
- // Add spoilers stored locally in /sdcard/GeocachePhotos
+ /**
+ * Add spoilers stored locally in <tt>/sdcard/GeocachePhotos</tt>. If a cache is named GC123ABC, the
+ * directory will be <tt>/sdcard/GeocachePhotos/C/B/GC123ABC/</tt>.
+ *
+ * @param spoilers the list to add to
+ */
private void addLocalSpoilersTo(final List<Image> spoilers) {
if (StringUtils.length(geocode) >= 2) {
final String suffix = StringUtils.right(geocode, 2);
- final File baseDir = new File(Environment.getExternalStorageDirectory().toString(), "GeocachePhotos");
+ final File baseDir = new File(Environment.getExternalStorageDirectory(), "GeocachePhotos");
final File lastCharDir = new File(baseDir, suffix.substring(1));
final File secondToLastCharDir = new File(lastCharDir, suffix.substring(0, 1));
- final File finalDir = new File(secondToLastCharDir, getGeocode());
+ final File finalDir = new File(secondToLastCharDir, geocode);
final File[] files = finalDir.listFiles();
if (files != null) {
for (final File image : files) {
@@ -1805,18 +1747,17 @@ public class Geocache implements ICache, IWaypoint {
return getConnector().getWaypointGpxId(prefix, geocode);
}
+ @NonNull
public String getWaypointPrefix(final String name) {
return getConnector().getWaypointPrefix(name);
}
/**
* Get number of overall finds for a cache, or 0 if the number of finds is not known.
- *
- * @return
*/
public int getFindsCount() {
if (getLogCounts().isEmpty()) {
- setLogCounts(DataStore.loadLogCounts(getGeocode()));
+ setLogCounts(inDatabase() ? DataStore.loadLogCounts(getGeocode()) : Collections.<LogType, Integer>emptyMap());
}
final Integer logged = getLogCounts().get(LogType.FOUND_IT);
if (logged != null) {
@@ -1829,12 +1770,13 @@ public class Geocache implements ICache, IWaypoint {
return (getType().applyDistanceRule() || hasUserModifiedCoords()) && getConnector() == GCConnector.getInstance();
}
+ @NonNull
public LogType getDefaultLogType() {
if (isEventCache()) {
final Date eventDate = getHiddenDate();
- final boolean expired = DateUtils.isPastEvent(this);
+ final boolean expired = CalendarUtils.isPastEvent(this);
- if (hasOwnLog(LogType.WILL_ATTEND) || expired || (eventDate != null && DateUtils.daysSince(eventDate.getTime()) == 0)) {
+ if (hasOwnLog(LogType.WILL_ATTEND) || expired || (eventDate != null && CalendarUtils.daysSince(eventDate.getTime()) == 0)) {
return hasOwnLog(LogType.ATTENDED) ? LogType.NOTE : LogType.ATTENDED;
}
return LogType.WILL_ATTEND;
@@ -1848,4 +1790,30 @@ public class Geocache implements ICache, IWaypoint {
return LogType.FOUND_IT;
}
+ /**
+ * Get the geocodes of a collection of caches.
+ *
+ * @param caches a collection of caches
+ * @return the non-blank geocodes of the caches
+ */
+ @NonNull
+ public static Set<String> getGeocodes(@NonNull final Collection<Geocache> caches) {
+ final Set<String> geocodes = new HashSet<>(caches.size());
+ for (final Geocache cache : caches) {
+ final String geocode = cache.getGeocode();
+ if (StringUtils.isNotBlank(geocode)) {
+ geocodes.add(geocode);
+ }
+ }
+ return geocodes;
+ }
+
+ /**
+ * Show the hint as toast message. If no hint is available, a default "no hint available" will be shown instead.
+ */
+ public void showHintToast(final Activity activity) {
+ final String hint = getHint();
+ ActivityMixin.showToast(activity, StringUtils.defaultIfBlank(hint, activity.getString(R.string.cache_hint_not_available)));
+ }
+
}
diff --git a/main/src/cgeo/geocaching/GpxFileListActivity.java b/main/src/cgeo/geocaching/GpxFileListActivity.java
index dae52c4..352dbab 100644
--- a/main/src/cgeo/geocaching/GpxFileListActivity.java
+++ b/main/src/cgeo/geocaching/GpxFileListActivity.java
@@ -1,63 +1,64 @@
-package cgeo.geocaching;
-
-import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.connector.IConnector;
-import cgeo.geocaching.files.AbstractFileListActivity;
-import cgeo.geocaching.files.GPXImporter;
-import cgeo.geocaching.list.StoredList;
-import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.ui.GPXListAdapter;
-
-import org.apache.commons.lang3.StringUtils;
-
-import android.app.Activity;
-import android.content.Intent;
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
-public class GpxFileListActivity extends AbstractFileListActivity<GPXListAdapter> {
-
- public GpxFileListActivity() {
- super(new String[] { "gpx", "loc", "zip" });
- }
-
- @Override
- protected GPXListAdapter getAdapter(List<File> files) {
- return new GPXListAdapter(this, files);
- }
-
- @Override
- protected List<File> getBaseFolders() {
- return Collections.singletonList(new File(Settings.getGpxImportDir()));
- }
-
- public static void startSubActivity(Activity fromActivity, int listId) {
- final Intent intent = new Intent(fromActivity, GpxFileListActivity.class);
- intent.putExtra(Intents.EXTRA_LIST_ID, StoredList.getConcreteList(listId));
- fromActivity.startActivityForResult(intent, 0);
- }
-
- @Override
- protected boolean filenameBelongsToList(final String filename) {
- if (super.filenameBelongsToList(filename)) {
- if (StringUtils.endsWithIgnoreCase(filename, GPXImporter.ZIP_FILE_EXTENSION)) {
- for (IConnector connector : ConnectorFactory.getConnectors()) {
- if (connector.isZippedGPXFile(filename)) {
- return true;
- }
- }
- return false;
- }
- // filter out waypoint files
- return !StringUtils.containsIgnoreCase(filename, GPXImporter.WAYPOINTS_FILE_SUFFIX);
- }
- return false;
- }
-
- public int getListId() {
- return listId;
- }
-
-}
+package cgeo.geocaching;
+
+import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.files.AbstractFileListActivity;
+import cgeo.geocaching.files.GPXImporter;
+import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.ui.GPXListAdapter;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.app.Activity;
+import android.content.Intent;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+public class GpxFileListActivity extends AbstractFileListActivity<GPXListAdapter> {
+
+ public GpxFileListActivity() {
+ super(new String[] { "gpx", "loc", "zip" });
+ }
+
+ @Override
+ protected GPXListAdapter getAdapter(final List<File> files) {
+ return new GPXListAdapter(this, files);
+ }
+
+ @Override
+ protected List<File> getBaseFolders() {
+ return Collections.singletonList(new File(Settings.getGpxImportDir()));
+ }
+
+ public static void startSubActivity(final Activity fromActivity, final int listId) {
+ final Intent intent = new Intent(fromActivity, GpxFileListActivity.class);
+ intent.putExtra(Intents.EXTRA_LIST_ID, StoredList.getConcreteList(listId));
+ fromActivity.startActivityForResult(intent, 0);
+ }
+
+ @Override
+ protected boolean filenameBelongsToList(@NonNull final String filename) {
+ if (super.filenameBelongsToList(filename)) {
+ if (StringUtils.endsWithIgnoreCase(filename, GPXImporter.ZIP_FILE_EXTENSION)) {
+ for (final IConnector connector : ConnectorFactory.getConnectors()) {
+ if (connector.isZippedGPXFile(filename)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // filter out waypoint files
+ return !StringUtils.containsIgnoreCase(filename, GPXImporter.WAYPOINTS_FILE_SUFFIX);
+ }
+ return false;
+ }
+
+ public int getListId() {
+ return listId;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ICache.java b/main/src/cgeo/geocaching/ICache.java
deleted file mode 100644
index b99d877..0000000
--- a/main/src/cgeo/geocaching/ICache.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- *
- */
-package cgeo.geocaching;
-
-import cgeo.geocaching.enumerations.CacheSize;
-import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LogType;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Basic interface for caches
- */
-public interface ICache extends ILogable, ICoordinates {
-
- /**
- * @return Displayed owner, might differ from the real owner
- */
- public String getOwnerDisplayName();
-
- /**
- * @return GC username of the (actual) owner, might differ from the owner. Never empty.
- */
- public String getOwnerUserId();
-
- /**
- * @return true if the user is the owner of the cache, false else
- */
- public boolean isOwner();
-
- /**
- * @return true is the cache is archived, false else
- */
- public boolean isArchived();
-
- /**
- * @return true is the cache is a Premium Member cache only, false else
- */
- public boolean isPremiumMembersOnly();
-
- /**
- * @return Decrypted hint
- */
- public String getHint();
-
- /**
- * @return Description
- */
- public String getDescription();
-
- /**
- * @return Short Description
- */
- public String getShortDescription();
-
-
- /**
- * @return Id
- */
- public String getCacheId();
-
- /**
- * @return Guid
- */
- public String getGuid();
-
- /**
- * @return Location
- */
- public String getLocation();
-
- /**
- * @return Personal note
- */
- public String getPersonalNote();
-
-
- /**
- * @return true if the user gave a favorite point to the cache
- *
- */
- public boolean isFavorite();
-
- /**
- * @return number of favorite points
- *
- */
- public int getFavoritePoints();
-
- /**
- * @return true if the cache is on the watchlist of the user
- *
- */
- public boolean isOnWatchlist();
-
- /**
- * @return The date the cache has been hidden
- *
- */
- public Date getHiddenDate();
-
- /**
- * null safe list of attributes
- *
- * @return the list of attributes for this cache
- */
- public List<String> getAttributes();
-
- /**
- * @return the list of trackables in this cache
- */
- public List<Trackable> getInventory();
-
- /**
- * @return the list of spoiler images
- */
- public List<Image> getSpoilers();
-
- /**
- * @return a statistic how often the caches has been found, disabled, archived etc.
- */
- public Map<LogType, Integer> getLogCounts();
-
- /**
- * get the name for lexicographical sorting.
- *
- * @return normalized, cached name which sort also correct for numerical parts in the name
- */
- public String getNameForSorting();
-
- /**
- * @return Tradi, multi etc.
- */
- CacheType getType();
-
- /**
- * @return Micro, small etc.
- */
- CacheSize getSize();
-
- /**
- * @return true if the user already found the cache
- *
- */
- boolean isFound();
-
- /**
- * @return true if the cache is disabled, false else
- */
- boolean isDisabled();
-
- /**
- * @return Difficulty assessment
- */
- float getDifficulty();
-
- /**
- * @return Terrain assessment
- */
- float getTerrain();
-}
diff --git a/main/src/cgeo/geocaching/ICoordinates.java b/main/src/cgeo/geocaching/ICoordinates.java
index b70e4ac..8f78e00 100644
--- a/main/src/cgeo/geocaching/ICoordinates.java
+++ b/main/src/cgeo/geocaching/ICoordinates.java
@@ -1,6 +1,6 @@
package cgeo.geocaching;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
public interface ICoordinates {
diff --git a/main/src/cgeo/geocaching/Image.java b/main/src/cgeo/geocaching/Image.java
index f592fc1..5c0e4f0 100644
--- a/main/src/cgeo/geocaching/Image.java
+++ b/main/src/cgeo/geocaching/Image.java
@@ -31,7 +31,7 @@ public class Image implements Parcelable {
}
public Image(final File file) {
- this("file://" + file.getAbsolutePath(), file.getName(), null);
+ this(FileUtils.fileToUrl(file), file.getName(), null);
}
public Image(final Parcel in) {
@@ -46,7 +46,7 @@ public class Image implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(final Parcel dest, final int flags) {
dest.writeString(url);
dest.writeString(title);
dest.writeString(description);
@@ -54,12 +54,12 @@ public class Image implements Parcelable {
public static final Parcelable.Creator<Image> CREATOR = new Parcelable.Creator<Image>() {
@Override
- public Image createFromParcel(Parcel in) {
+ public Image createFromParcel(final Parcel in) {
return new Image(in);
}
@Override
- public Image[] newArray(int size) {
+ public Image[] newArray(final int size) {
return new Image[size];
}
};
diff --git a/main/src/cgeo/geocaching/ImageSelectActivity.java b/main/src/cgeo/geocaching/ImageSelectActivity.java
index a64b4cf..9d1c1e0 100644
--- a/main/src/cgeo/geocaching/ImageSelectActivity.java
+++ b/main/src/cgeo/geocaching/ImageSelectActivity.java
@@ -18,6 +18,7 @@ import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -48,11 +49,6 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
@InjectView(R.id.cancel) protected Button clearButton;
@InjectView(R.id.image_preview) protected ImageView imagePreview;
- static final String EXTRAS_CAPTION = "caption";
- static final String EXTRAS_DESCRIPTION = "description";
- static final String EXTRAS_URI_AS_STRING = "uri";
- static final String EXTRAS_SCALE = "scale";
-
private static final String SAVED_STATE_IMAGE_CAPTION = "cgeo.geocaching.saved_state_image_caption";
private static final String SAVED_STATE_IMAGE_DESCRIPTION = "cgeo.geocaching.saved_state_image_description";
private static final String SAVED_STATE_IMAGE_URI = "cgeo.geocaching.saved_state_image_uri";
@@ -80,10 +76,10 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
// Get parameters from intent and basic cache information from database
final Bundle extras = getIntent().getExtras();
if (extras != null) {
- imageCaption = extras.getString(EXTRAS_CAPTION);
- imageDescription = extras.getString(EXTRAS_DESCRIPTION);
- imageUri = Uri.parse(extras.getString(EXTRAS_URI_AS_STRING));
- scaleChoiceIndex = extras.getInt(EXTRAS_SCALE, scaleChoiceIndex);
+ imageCaption = extras.getString(Intents.EXTRA_CAPTION);
+ imageDescription = extras.getString(Intents.EXTRA_DESCRIPTION);
+ imageUri = Uri.parse(extras.getString(Intents.EXTRA_URI_AS_STRING));
+ scaleChoiceIndex = extras.getInt(Intents.EXTRA_SCALE, scaleChoiceIndex);
}
// Restore previous state
@@ -97,7 +93,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
cameraButton.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View view) {
+ public void onClick(final View view) {
selectImageFromCamera();
}
});
@@ -105,7 +101,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
storedButton.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View view) {
+ public void onClick(final View view) {
selectImageFromStorage();
}
});
@@ -123,20 +119,20 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
scaleView.setSelection(scaleChoiceIndex);
scaleView.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
- public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
+ public void onItemSelected(final AdapterView<?> arg0, final View arg1, final int arg2, final long arg3) {
scaleChoiceIndex = scaleView.getSelectedItemPosition();
Settings.setLogImageScale(scaleChoiceIndex);
}
@Override
- public void onNothingSelected(AdapterView<?> arg0) {
+ public void onNothingSelected(final AdapterView<?> arg0) {
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View v) {
+ public void onClick(final View v) {
saveImageInfo(true);
}
});
@@ -144,7 +140,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View v) {
+ public void onClick(final View v) {
saveImageInfo(false);
}
});
@@ -162,27 +158,36 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
outState.putInt(SAVED_STATE_IMAGE_SCALE, scaleChoiceIndex);
}
- public void saveImageInfo(boolean saveInfo) {
+ public void saveImageInfo(final boolean saveInfo) {
if (saveInfo) {
- final String filename = writeScaledImage(imageUri.getPath());
- if (filename != null) {
- imageUri = Uri.parse(filename);
- final Intent intent = new Intent();
- syncEditTexts();
- intent.putExtra(EXTRAS_CAPTION, imageCaption);
- intent.putExtra(EXTRAS_DESCRIPTION, imageDescription);
- intent.putExtra(EXTRAS_URI_AS_STRING, imageUri.toString());
- intent.putExtra(EXTRAS_SCALE, scaleChoiceIndex);
- setResult(RESULT_OK, intent);
- } else {
- showToast(res.getString(R.string.err_select_logimage_failed));
- setResult(RESULT_CANCELED);
- }
+ new AsyncTask<Void, Void, String>() {
+ @Override
+ protected String doInBackground(final Void... params) {
+ return writeScaledImage(imageUri.getPath());
+ }
+
+ @Override
+ protected void onPostExecute(final String filename) {
+ if (filename != null) {
+ imageUri = Uri.parse(filename);
+ final Intent intent = new Intent();
+ syncEditTexts();
+ intent.putExtra(Intents.EXTRA_CAPTION, imageCaption);
+ intent.putExtra(Intents.EXTRA_DESCRIPTION, imageDescription);
+ intent.putExtra(Intents.EXTRA_URI_AS_STRING, imageUri.toString());
+ intent.putExtra(Intents.EXTRA_SCALE, scaleChoiceIndex);
+ setResult(RESULT_OK, intent);
+ } else {
+ showToast(res.getString(R.string.err_select_logimage_failed));
+ setResult(RESULT_CANCELED);
+ }
+ finish();
+ }
+ }.execute();
} else {
setResult(RESULT_CANCELED);
+ finish();
}
-
- finish();
}
private void syncEditTexts() {
@@ -193,7 +198,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
private void selectImageFromCamera() {
// create Intent to take a picture and return control to the calling application
- Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
imageUri = ImageUtils.getOutputImageFileUri(); // create a file to save the image
if (imageUri == null) {
@@ -207,14 +212,14 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
}
private void selectImageFromStorage() {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/jpeg");
startActivityForResult(Intent.createChooser(intent, "Select Image"), SELECT_STORED_IMAGE);
}
@Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
showToast(getResources().getString(R.string.info_select_logimage_cancelled));
@@ -232,7 +237,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
if (data != null) {
final Uri selectedImage = data.getData();
if (Build.VERSION.SDK_INT < VERSION_CODES.KITKAT) {
- String[] filePathColumn = { MediaColumns.DATA };
+ final String[] filePathColumn = { MediaColumns.DATA };
Cursor cursor = null;
try {
@@ -243,14 +248,14 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
}
cursor.moveToFirst();
- int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
- String filePath = cursor.getString(columnIndex);
+ final int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
+ final String filePath = cursor.getString(columnIndex);
if (StringUtils.isBlank(filePath)) {
showFailure();
return;
}
imageUri = Uri.parse(filePath);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("ImageSelectActivity.onActivityResult", e);
showFailure();
} finally {
@@ -269,7 +274,7 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
output = new FileOutputStream(outputFile);
LocalStorage.copy(input, output);
imageUri = Uri.fromFile(outputFile);
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException e) {
Log.e("ImageSelectActivity.onStartResult", e);
} finally {
IOUtils.closeQuietly(input);
@@ -288,7 +293,6 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
/**
* Scales and writes the scaled image.
*
- * @param filePath
* @return the scaled image path, or <tt>null</tt> if the image cannot be decoded
*/
@Nullable
@@ -314,8 +318,17 @@ public class ImageSelectActivity extends AbstractActionBarActivity {
return;
}
- final Bitmap bitmap = ImageUtils.readAndScaleImageToFitDisplay(imageUri.getPath());
- imagePreview.setImageBitmap(bitmap);
- imagePreview.setVisibility(View.VISIBLE);
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(final Void... params) {
+ return ImageUtils.readAndScaleImageToFitDisplay(imageUri.getPath());
+ }
+
+ @Override
+ protected void onPostExecute(final Bitmap bitmap) {
+ imagePreview.setImageBitmap(bitmap);
+ imagePreview.setVisibility(View.VISIBLE);
+ }
+ }.execute();
}
}
diff --git a/main/src/cgeo/geocaching/ImagesActivity.java b/main/src/cgeo/geocaching/ImagesActivity.java
index b75e5eb..975a720 100644
--- a/main/src/cgeo/geocaching/ImagesActivity.java
+++ b/main/src/cgeo/geocaching/ImagesActivity.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.ui.ImagesList;
import cgeo.geocaching.ui.ImagesList.ImageType;
import org.apache.commons.collections4.CollectionUtils;
+
import rx.Subscription;
import android.content.Context;
@@ -28,7 +29,7 @@ public class ImagesActivity extends AbstractActionBarActivity {
private Subscription subscription;
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get parameters
@@ -78,11 +79,12 @@ public class ImagesActivity extends AbstractActionBarActivity {
super.onStop();
}
- public static void startActivityLogImages(final Context fromActivity, final String geocode, List<Image> logImages) {
+ public static void startActivityLogImages(final Context fromActivity, final String geocode, final List<Image> logImages) {
startActivity(fromActivity, geocode, logImages, ImageType.LogImages);
}
- private static void startActivity(final Context fromActivity, final String geocode, List<Image> logImages, ImageType imageType) {
+ @SuppressWarnings("deprecation")
+ private static void startActivity(final Context fromActivity, final String geocode, final List<Image> logImages, final ImageType imageType) {
final Intent logImgIntent = new Intent(fromActivity, ImagesActivity.class);
// if resuming our app within this activity, finish it and return to the cache activity
logImgIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
@@ -95,18 +97,18 @@ public class ImagesActivity extends AbstractActionBarActivity {
fromActivity.startActivity(logImgIntent);
}
- public static void startActivitySpoilerImages(final Context fromActivity, String geocode, List<Image> spoilers) {
+ public static void startActivitySpoilerImages(final Context fromActivity, final String geocode, final List<Image> spoilers) {
startActivity(fromActivity, geocode, spoilers, ImageType.SpoilerImages);
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
imagesList.onCreateContextMenu(menu, v);
}
@Override
- public boolean onContextItemSelected(MenuItem item) {
+ public boolean onContextItemSelected(final MenuItem item) {
if (imagesList.onContextItemSelected(item)) {
return true;
}
diff --git a/main/src/cgeo/geocaching/Intents.java b/main/src/cgeo/geocaching/Intents.java
index a55c22a..cbf2346 100644
--- a/main/src/cgeo/geocaching/Intents.java
+++ b/main/src/cgeo/geocaching/Intents.java
@@ -1,5 +1,13 @@
package cgeo.geocaching;
+import cgeo.geocaching.enumerations.CacheListType;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.Intent;
+import android.os.Bundle;
+
public class Intents {
private Intents() {
@@ -10,6 +18,8 @@ public class Intents {
public static final String EXTRA_ADDRESS = PREFIX + "address";
public static final String EXTRA_COORDS = PREFIX + "coords";
+ public static final String EXTRA_LATITUDE = PREFIX + "latitude";
+ public static final String EXTRA_LONGITUDE = PREFIX + "longitude";
public static final String EXTRA_COUNT = PREFIX + "count";
public static final String EXTRA_GEOCODE = PREFIX + "geocode";
public static final String EXTRA_GUID = PREFIX + "guid";
@@ -18,7 +28,24 @@ public class Intents {
public static final String EXTRA_KEYWORD = PREFIX + "keyword";
public static final String EXTRA_KEYWORD_SEARCH = PREFIX + "keyword_search";
public static final String EXTRA_LIST_ID = PREFIX + "list_id";
- public static final String EXTRA_LIST_TYPE = PREFIX + "list_type";
+ public static final String EXTRA_CAPTION = PREFIX + "caption";
+ public static final String EXTRA_DESCRIPTION = PREFIX + "description";
+ public static final String EXTRA_URI_AS_STRING = PREFIX + "uri";
+ public static final String EXTRA_SCALE = PREFIX + "scale";
+
+ public static final String EXTRA_WPTTYPE = PREFIX + "wpttype";
+ public static final String EXTRA_MAPSTATE = PREFIX + "mapstate";
+ public static final String EXTRA_TITLE = PREFIX + "title";
+ public static final String EXTRA_MAP_MODE = PREFIX + "mapMode";
+ public static final String EXTRA_LIVE_ENABLED = PREFIX + "liveEnabled";
+
+ public static final String EXTRA_DOWNLOAD = PREFIX + "download";
+
+ /**
+ * list type to be used with the cache list activity. Be aware to use the String representation of the corresponding
+ * enum.
+ */
+ private static final String EXTRA_LIST_TYPE = PREFIX + "list_type";
public static final String EXTRA_MAP_FILE = PREFIX + "map_file";
public static final String EXTRA_NAME = PREFIX + "name";
public static final String EXTRA_SEARCH = PREFIX + "search";
@@ -49,4 +76,25 @@ public class Intents {
public static final String EXTRA_OAUTH_TEMP_TOKEN_SECRET_PREF = PREFIX_OAUTH + "tempSecretPref";
public static final String EXTRA_OAUTH_TOKEN_PUBLIC_KEY = PREFIX_OAUTH + "publicTokenPref";
public static final String EXTRA_OAUTH_TOKEN_SECRET_KEY = PREFIX_OAUTH + "secretTokenPref";
+
+ public static Intent putListType(final Intent intent, final @NonNull CacheListType listType) {
+ intent.putExtra(Intents.EXTRA_LIST_TYPE, listType.name());
+ return intent;
+ }
+
+ public static @NonNull CacheListType getListType(final Intent intent) {
+ final Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return CacheListType.OFFLINE;
+ }
+ final String typeName = extras.getString(Intents.EXTRA_LIST_TYPE);
+ if (StringUtils.isBlank(typeName)) {
+ return CacheListType.OFFLINE;
+ }
+ try {
+ return CacheListType.valueOf(typeName);
+ } catch (final IllegalArgumentException ignored) {
+ return CacheListType.OFFLINE;
+ }
+ }
}
diff --git a/main/src/cgeo/geocaching/LogCacheActivity.java b/main/src/cgeo/geocaching/LogCacheActivity.java
index bc87525..6fbd7bf 100644
--- a/main/src/cgeo/geocaching/LogCacheActivity.java
+++ b/main/src/cgeo/geocaching/LogCacheActivity.java
@@ -1,6 +1,7 @@
package cgeo.geocaching;
import butterknife.ButterKnife;
+import butterknife.InjectView;
import cgeo.geocaching.activity.ShowcaseViewBuilder;
import cgeo.geocaching.connector.ILoggingManager;
@@ -11,12 +12,14 @@ import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.LogTypeTrackable;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.gcvote.GCVote;
+import cgeo.geocaching.gcvote.GCVoteRatingBarUtil;
+import cgeo.geocaching.gcvote.GCVoteRatingBarUtil.OnRatingChangeListener;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.twitter.Twitter;
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.CalendarUtils;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.LogTemplateProvider;
@@ -44,8 +47,6 @@ import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
-import android.widget.RatingBar;
-import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.TextView;
import java.util.ArrayList;
@@ -54,8 +55,6 @@ import java.util.Date;
import java.util.List;
public class LogCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent {
- static final String EXTRAS_GEOCODE = "geocode";
- static final String EXTRAS_ID = "id";
private static final String SAVED_STATE_RATING = "cgeo.geocaching.saved_state_rating";
private static final String SAVED_STATE_TYPE = "cgeo.geocaching.saved_state_type";
@@ -72,9 +71,9 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
private String text = null;
private List<LogType> possibleLogTypes = new ArrayList<>();
private List<TrackableLog> trackables = null;
- private CheckBox tweetCheck = null;
- private LinearLayout tweetBox = null;
- private LinearLayout logPasswordBox = null;
+ protected @InjectView(R.id.tweet) CheckBox tweetCheck;
+ protected @InjectView(R.id.tweet_box) LinearLayout tweetBox;
+ protected @InjectView(R.id.log_password_box) LinearLayout logPasswordBox;
private SparseArray<TrackableLog> actionButtons;
private ILoggingManager loggingManager;
@@ -88,9 +87,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
private Uri imageUri;
private boolean sendButtonEnabled;
-
public void onLoadFinished() {
-
if (loggingManager.hasLoaderError()) {
showErrorLoadingData();
return;
@@ -111,6 +108,8 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
showToast(res.getString(R.string.info_log_type_changed));
}
+ initializeRatingBar();
+
enablePostButton(true);
initializeTrackablesAction();
@@ -141,7 +140,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
}
actionButtons = new SparseArray<>();
- final LinearLayout inventoryView = (LinearLayout) findViewById(R.id.inventory);
+ final LinearLayout inventoryView = ButterKnife.findById(this, R.id.inventory);
inventoryView.removeAllViews();
for (final TrackableLog tb : trackables) {
@@ -165,7 +164,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final String tbCode = tb.trackCode;
inventoryItem.setClickable(true);
- inventoryItem.findViewById(R.id.info).setOnClickListener(new View.OnClickListener() {
+ ButterKnife.findById(inventoryItem, R.id.info).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
@@ -179,10 +178,10 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
}
if (inventoryView.getChildCount() > 0) {
- findViewById(R.id.inventory_box).setVisibility(View.VISIBLE);
+ ButterKnife.findById(this, R.id.inventory_box).setVisibility(View.VISIBLE);
}
if (inventoryView.getChildCount() > 1) {
- final LinearLayout inventoryChangeAllView = (LinearLayout) findViewById(R.id.inventory_changeall);
+ final LinearLayout inventoryChangeAllView = ButterKnife.findById(this, R.id.inventory_changeall);
final Button changeButton = ButterKnife.findById(inventoryChangeAllView, R.id.changebutton);
changeButton.setOnClickListener(new View.OnClickListener() {
@@ -208,9 +207,9 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
// Get parameters from intent and basic cache information from database
final Bundle extras = getIntent().getExtras();
if (extras != null) {
- geocode = extras.getString(EXTRAS_GEOCODE);
+ geocode = extras.getString(Intents.EXTRA_GEOCODE);
if (StringUtils.isBlank(geocode)) {
- final String cacheid = extras.getString(EXTRAS_ID);
+ final String cacheid = extras.getString(Intents.EXTRA_ID);
if (StringUtils.isNotBlank(cacheid)) {
geocode = DataStore.getGeocodeForGuid(cacheid);
}
@@ -227,13 +226,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
setTitle(res.getString(R.string.log_new_log) + ": " + cache.getGeocode());
}
- // Get ids for later use
- tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
- tweetCheck = (CheckBox) findViewById(R.id.tweet);
- logPasswordBox = (LinearLayout) findViewById(R.id.log_password_box);
-
- final RatingBar ratingBar = (RatingBar) findViewById(R.id.gcvoteRating);
- initializeRatingBar(ratingBar);
+ initializeRatingBar();
// initialize with default values
setDefaultValues();
@@ -261,7 +254,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
}
enablePostButton(false);
- final Button typeButton = (Button) findViewById(R.id.type);
+ final Button typeButton = ButterKnife.findById(this, R.id.type);
typeButton.setText(typeSelected.getL10n());
typeButton.setOnClickListener(new View.OnClickListener() {
@@ -271,11 +264,11 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
}
});
- final Button dateButton = (Button) findViewById(R.id.date);
+ final Button dateButton = ButterKnife.findById(this, R.id.date);
setDate(date);
dateButton.setOnClickListener(new DateListener());
- final EditText logView = (EditText) findViewById(R.id.log);
+ final EditText logView = ButterKnife.findById(this, R.id.log);
if (StringUtils.isBlank(currentLogText()) && StringUtils.isNotBlank(text)) {
logView.setText(text);
Dialogs.moveCursorToEnd(logView);
@@ -288,27 +281,19 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
loggingManager = cache.getLoggingManager(this);
loggingManager.init();
+ requestKeyboardForLogging();
}
- private void initializeRatingBar(final RatingBar ratingBar) {
- final TextView label = (TextView) findViewById(R.id.gcvoteLabel);
+ private void initializeRatingBar() {
if (GCVote.isVotingPossible(cache)) {
- ratingBar.setVisibility(View.VISIBLE);
- label.setVisibility(View.VISIBLE);
- }
- ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
+ GCVoteRatingBarUtil.initializeRatingBar(cache, getWindow().getDecorView().getRootView(), new OnRatingChangeListener() {
- @Override
- public void onRatingChanged(final RatingBar ratingBar, final float stars, final boolean fromUser) {
- // 0.5 is not a valid rating, therefore we must limit
- rating = GCVote.isValidRating(stars) ? stars : 0;
- if (rating < stars) {
- ratingBar.setRating(rating);
+ @Override
+ public void onRatingChanged(final float stars) {
+ rating = stars;
}
- label.setText(GCVote.getDescription(rating));
- }
- });
- ratingBar.setRating(cache.getMyVote());
+ });
+ }
}
private void setDefaultValues() {
@@ -316,7 +301,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
rating = GCVote.NO_RATING;
typeSelected = cache.getDefaultLogType();
// it this is an attended event log, use the event date by default instead of the current date
- if (cache.isEventCache() && DateUtils.isPastEvent(cache) && typeSelected == LogType.ATTENDED) {
+ if (cache.isEventCache() && CalendarUtils.isPastEvent(cache) && typeSelected == LogType.ATTENDED) {
date.setTime(cache.getHiddenDate());
}
text = null;
@@ -333,9 +318,9 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
setType(typeSelected);
setDate(date);
- final EditText logView = (EditText) findViewById(R.id.log);
+ final EditText logView = ButterKnife.findById(this, R.id.log);
logView.setText(StringUtils.EMPTY);
- final EditText logPasswordView = (EditText) findViewById(R.id.log_password);
+ final EditText logPasswordView = ButterKnife.findById(this, R.id.log_password);
logPasswordView.setText(StringUtils.EMPTY);
showToast(res.getString(R.string.info_log_cleared));
@@ -368,12 +353,12 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
public void setDate(final Calendar dateIn) {
date = dateIn;
- final Button dateButton = (Button) findViewById(R.id.date);
+ final Button dateButton = ButterKnife.findById(this, R.id.date);
dateButton.setText(Formatter.formatShortDateVerbally(date.getTime().getTime()));
}
public void setType(final LogType type) {
- final Button typeButton = (Button) findViewById(R.id.type);
+ final Button typeButton = ButterKnife.findById(this, R.id.type);
typeSelected = type;
typeButton.setText(typeSelected.getL10n());
@@ -419,13 +404,13 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final String log = logTexts[0];
final String logPwd = logTexts.length > 1 ? logTexts[1] : null;
try {
- final LogResult logResult = loggingManager.postLog(cache, typeSelected, date, log, logPwd, trackables);
+ final LogResult logResult = loggingManager.postLog(typeSelected, date, log, logPwd, trackables);
if (logResult.getPostLogResult() == StatusCode.NO_ERROR) {
// update geocache in DB
- if (typeSelected == LogType.FOUND_IT || typeSelected == LogType.ATTENDED || typeSelected == LogType.WEBCAM_PHOTO_TAKEN) {
+ if (typeSelected.isFoundLog()) {
cache.setFound(true);
- cache.setVisitedDate(new Date().getTime());
+ cache.setVisitedDate(date.getTimeInMillis());
}
DataStore.saveChangedCache(cache);
@@ -434,7 +419,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final LogEntry logNow = new LogEntry(date.getTimeInMillis(), typeSelected, log);
logNow.friend = true;
newLogs.add(0, logNow);
- DataStore.saveLogsWithoutTransaction(cache.getGeocode(), newLogs);
+ DataStore.saveLogs(cache.getGeocode(), newLogs);
// update offline log in DB
cache.clearOfflineLog();
@@ -444,8 +429,13 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
Twitter.postTweetCache(geocode, logNow);
}
}
- if (GCVote.isValidRating(rating)) {
- GCVote.setRating(cache, rating);
+ if (GCVote.isValidRating(rating) && GCVote.isVotingPossible(cache)) {
+ if (GCVote.setRating(cache, rating)) {
+ cache.setMyVote(rating);
+ DataStore.saveChangedCache(cache);
+ } else {
+ showToast(res.getString(R.string.err_gcvote_send_rating));
+ }
}
if (StringUtils.isNotBlank(imageUri.getPath())) {
@@ -453,7 +443,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
final String uploadedImageUrl = imageResult.getImageUri();
if (StringUtils.isNotEmpty(uploadedImageUrl)) {
logNow.addLogImage(new Image(uploadedImageUrl, imageCaption, imageDescription));
- DataStore.saveLogsWithoutTransaction(cache.getGeocode(), newLogs);
+ DataStore.saveLogs(cache.getGeocode(), newLogs);
}
return imageResult.getPostResult();
}
@@ -461,7 +451,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
return logResult.getPostLogResult();
} catch (final RuntimeException e) {
- Log.e("VisitCacheActivity.Poster.doInBackgroundInternal", e);
+ Log.e("LogCacheActivity.Poster.doInBackgroundInternal", e);
}
return StatusCode.LOG_POST_ERROR;
@@ -491,16 +481,17 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
// again will be easy using "Clear" while retyping the text may not be.
if (force || (StringUtils.isNotEmpty(log) && !StringUtils.equals(log, text))) {
cache.logOffline(this, log, date, typeSelected);
+ Settings.setLastCacheLog(log);
}
text = log;
}
private String currentLogText() {
- return ((EditText) findViewById(R.id.log)).getText().toString();
+ return ButterKnife.<EditText>findById(this, R.id.log).getText().toString();
}
private String currentLogPassword() {
- return ((EditText) findViewById(R.id.log_password)).getText().toString();
+ return ButterKnife.<EditText>findById(this, R.id.log_password).getText().toString();
}
@Override
@@ -578,9 +569,9 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
private void selectImage() {
final Intent selectImageIntent = new Intent(this, ImageSelectActivity.class);
- selectImageIntent.putExtra(ImageSelectActivity.EXTRAS_CAPTION, imageCaption);
- selectImageIntent.putExtra(ImageSelectActivity.EXTRAS_DESCRIPTION, imageDescription);
- selectImageIntent.putExtra(ImageSelectActivity.EXTRAS_URI_AS_STRING, imageUri.toString());
+ selectImageIntent.putExtra(Intents.EXTRA_CAPTION, imageCaption);
+ selectImageIntent.putExtra(Intents.EXTRA_DESCRIPTION, imageDescription);
+ selectImageIntent.putExtra(Intents.EXTRA_URI_AS_STRING, imageUri.toString());
startActivityForResult(selectImageIntent, SELECT_IMAGE);
}
@@ -589,9 +580,9 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == SELECT_IMAGE) {
if (resultCode == RESULT_OK) {
- imageCaption = data.getStringExtra(ImageSelectActivity.EXTRAS_CAPTION);
- imageDescription = data.getStringExtra(ImageSelectActivity.EXTRAS_DESCRIPTION);
- imageUri = Uri.parse(data.getStringExtra(ImageSelectActivity.EXTRAS_URI_AS_STRING));
+ imageCaption = data.getStringExtra(Intents.EXTRA_CAPTION);
+ imageDescription = data.getStringExtra(Intents.EXTRA_DESCRIPTION);
+ imageUri = Uri.parse(data.getStringExtra(Intents.EXTRA_URI_AS_STRING));
} else if (resultCode != RESULT_CANCELED) {
// Image capture failed, advise user
showToast(getResources().getString(R.string.err_select_logimage_failed));
@@ -603,7 +594,7 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_send:
- sendLog();
+ sendLogAndConfirm();
return true;
case R.id.menu_image:
selectImage();
@@ -622,18 +613,37 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
return super.onOptionsItemSelected(item);
}
- private void sendLog() {
+ private void sendLogAndConfirm() {
if (!sendButtonEnabled) {
Dialogs.message(this, R.string.log_post_not_possible);
+ return;
+ }
+ if (CalendarUtils.isFuture(date)) {
+ Dialogs.message(this, R.string.log_date_future_not_allowed);
+ return;
+ }
+ if (typeSelected.mustConfirmLog()) {
+ Dialogs.confirm(this, R.string.confirm_log_title, res.getString(R.string.confirm_log_message, typeSelected.getL10n()), new OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ sendLogInternal();
+ }
+ });
}
else {
- final String message = res.getString(StringUtils.isBlank(imageUri.getPath()) ?
- R.string.log_saving :
- R.string.log_saving_and_uploading);
- new Poster(this, message).execute(currentLogText(), currentLogPassword());
+ sendLogInternal();
}
}
+ private void sendLogInternal() {
+ final String message = res.getString(StringUtils.isBlank(imageUri.getPath()) ?
+ R.string.log_saving :
+ R.string.log_saving_and_uploading);
+ new Poster(this, message).execute(currentLogText(), currentLogPassword());
+ Settings.setLastCacheLog(currentLogText());
+ }
+
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
super.onCreateOptionsMenu(menu);
@@ -650,4 +660,16 @@ public class LogCacheActivity extends AbstractLoggingActivity implements DateDia
.setTarget(new ActionItemTarget(this, R.id.menu_send))
.setContent(R.string.showcase_logcache_title, R.string.showcase_logcache_text);
}
+
+ public static Intent getLogCacheIntent(final Activity context, final String cacheId, final String geocode) {
+ final Intent logVisitIntent = new Intent(context, LogCacheActivity.class);
+ logVisitIntent.putExtra(Intents.EXTRA_ID, cacheId);
+ logVisitIntent.putExtra(Intents.EXTRA_GEOCODE, geocode);
+ return logVisitIntent;
+ }
+
+ @Override
+ protected String getLastLog() {
+ return Settings.getLastCacheLog();
+ }
}
diff --git a/main/src/cgeo/geocaching/LogEntry.java b/main/src/cgeo/geocaching/LogEntry.java
index b4b346c..41c222b 100644
--- a/main/src/cgeo/geocaching/LogEntry.java
+++ b/main/src/cgeo/geocaching/LogEntry.java
@@ -2,7 +2,6 @@ package cgeo.geocaching;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.utils.DateUtils;
import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.MatcherWrapper;
@@ -89,7 +88,7 @@ public final class LogEntry {
public CharSequence getImageTitles() {
final List<String> titles = new ArrayList<>(5);
- for (Image image : getLogImages()) {
+ for (final Image image : getLogImages()) {
if (StringUtils.isNotBlank(image.getTitle())) {
titles.add(HtmlUtils.extractText(image.getTitle()));
}
@@ -100,16 +99,12 @@ public final class LogEntry {
return StringUtils.join(titles, ", ");
}
- public int daysSinceLog() {
- return DateUtils.daysSince(date);
- }
-
/**
* Get the log text to be displayed. Depending on the settings, color tags might be removed.
*/
public String getDisplayText() {
if (Settings.getPlainLogs()) {
- MatcherWrapper matcher = new MatcherWrapper(PATTERN_REMOVE_COLORS, log);
+ final MatcherWrapper matcher = new MatcherWrapper(PATTERN_REMOVE_COLORS, log);
return matcher.replaceAll(StringUtils.EMPTY);
}
return log;
diff --git a/main/src/cgeo/geocaching/LogTrackableActivity.java b/main/src/cgeo/geocaching/LogTrackableActivity.java
index 26f7c84..fa77458 100644
--- a/main/src/cgeo/geocaching/LogTrackableActivity.java
+++ b/main/src/cgeo/geocaching/LogTrackableActivity.java
@@ -3,6 +3,7 @@ package cgeo.geocaching;
import butterknife.ButterKnife;
import butterknife.InjectView;
+import cgeo.geocaching.activity.Keyboard;
import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.enumerations.LogType;
@@ -15,7 +16,9 @@ import cgeo.geocaching.ui.dialog.DateDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.LogTemplateProvider;
import cgeo.geocaching.utils.LogTemplateProvider.LogContext;
+import cgeo.geocaching.utils.LogTemplateProvider.LogTemplate;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -28,6 +31,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.ContextMenu;
+import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
@@ -61,6 +65,8 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
private int attempts = 0;
private Trackable trackable;
+ final public static int LOG_TRACKABLE = 1;
+
private final Handler showProgressHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
@@ -106,6 +112,7 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
final StatusCode error = (StatusCode) msg.obj;
if (error == StatusCode.NO_ERROR) {
showToast(res.getString(R.string.info_log_posted));
+ setResult(RESULT_OK);
finish();
} else {
showToast(error.getErrorString(res));
@@ -132,20 +139,31 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
trackable = DataStore.loadTrackable(geocode);
+ if (trackable == null) {
+ Log.e("LogTrackableActivity.onCreate: cannot load trackable " + geocode);
+ setResult(RESULT_CANCELED);
+ finish();
+ return;
+ }
+
if (StringUtils.isNotBlank(trackable.getName())) {
setTitle(res.getString(R.string.trackable_touch) + ": " + trackable.getName());
} else {
setTitle(res.getString(R.string.trackable_touch) + ": " + trackable.getGeocode());
}
- if (guid == null) {
- showToast(res.getString(R.string.err_tb_forgot_saw));
+ init();
+ requestKeyboardForLogging();
+ }
- finish();
- return;
+ @Override
+ protected void requestKeyboardForLogging() {
+ if (StringUtils.isBlank(trackingEditText.getText())) {
+ new Keyboard(this).show(trackingEditText);
+ }
+ else {
+ super.requestKeyboardForLogging();
}
-
- init();
}
@Override
@@ -241,11 +259,6 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
public LoadDataThread() {
super("Load data for logging trackable");
- if (guid == null) {
- showToast(res.getString(R.string.err_tb_forgot_saw));
-
- finish();
- }
}
@Override
@@ -309,6 +322,9 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
tweetCheck.isChecked() && tweetBox.getVisibility() == View.VISIBLE) {
Twitter.postTweetTrackable(geocode, new LogEntry(0, typeSelected, log));
}
+ if (status == StatusCode.NO_ERROR) {
+ addLocalTrackableLog(log);
+ }
return status;
} catch (final Exception e) {
@@ -318,12 +334,25 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
return StatusCode.LOG_POST_ERROR;
}
- public static void startActivity(final Context context, final Trackable trackable) {
+ /**
+ * Adds the new log to the list of log entries for this trackable to be able to show it in the trackable activity.
+ *
+ *
+ */
+ private void addLocalTrackableLog(final String logText) {
+ final LogEntry logEntry = new LogEntry(date.getTimeInMillis(), typeSelected, logText);
+ final ArrayList<LogEntry> modifiedLogs = new ArrayList<>(trackable.getLogs());
+ modifiedLogs.add(0, logEntry);
+ trackable.setLogs(modifiedLogs);
+ DataStore.saveTrackable(trackable);
+ }
+
+ public static Intent getIntent(final Context context, final Trackable trackable) {
final Intent logTouchIntent = new Intent(context, LogTrackableActivity.class);
logTouchIntent.putExtra(Intents.EXTRA_GEOCODE, trackable.getGeocode());
logTouchIntent.putExtra(Intents.EXTRA_GUID, trackable.getGuid());
logTouchIntent.putExtra(Intents.EXTRA_TRACKING_CODE, trackable.getTrackingcode());
- context.startActivity(logTouchIntent);
+ return logTouchIntent;
}
@Override
@@ -355,9 +384,26 @@ public class LogTrackableActivity extends AbstractLoggingActivity implements Dat
final String tracking = trackingEditText.getText().toString();
final String log = logEditText.getText().toString();
new PostLogThread(postLogHandler, tracking, log).start();
+ Settings.setLastTrackableLog(log);
} else {
showToast(res.getString(R.string.err_log_load_data_still));
}
}
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ final boolean result = super.onCreateOptionsMenu(menu);
+ for (final LogTemplate template : LogTemplateProvider.getTemplatesWithoutSignature()) {
+ if (template.getTemplateString().equals("NUMBER")) {
+ menu.findItem(R.id.menu_templates).getSubMenu().removeItem(template.getItemId());
+ }
+ }
+ return result;
+ }
+
+ @Override
+ protected String getLastLog() {
+ return Settings.getLastTrackableLog();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java
index c0c6712..45ce698 100644
--- a/main/src/cgeo/geocaching/MainActivity.java
+++ b/main/src/cgeo/geocaching/MainActivity.java
@@ -7,17 +7,21 @@ import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.activity.ShowcaseViewBuilder;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.capability.ILogin;
-import cgeo.geocaching.connector.gc.GCConnector;
-import cgeo.geocaching.connector.gc.GCLogin;
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.location.AndroidGeocoder;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.MapQuestGeocoder;
+import cgeo.geocaching.location.Units;
import cgeo.geocaching.maps.CGeoMap;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.GpsStatusProvider;
+import cgeo.geocaching.sensors.GpsStatusProvider.Status;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.ui.dialog.Dialogs;
@@ -35,21 +39,23 @@ import com.google.zxing.integration.android.IntentResult;
import org.apache.commons.lang3.StringUtils;
import rx.Observable;
-import rx.Observable.OnSubscribe;
-import rx.Subscriber;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action0;
import rx.functions.Action1;
-import rx.subscriptions.Subscriptions;
+import rx.functions.Func1;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.SearchManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.location.Address;
-import android.location.Geocoder;
+import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -64,12 +70,12 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-import java.util.Locale;
public class MainActivity extends AbstractActionBarActivity {
@InjectView(R.id.nav_satellites) protected TextView navSatellites;
@@ -88,11 +94,9 @@ public class MainActivity extends AbstractActionBarActivity {
public static final int SEARCH_REQUEST_CODE = 2;
- private int version = 0;
- private boolean cleanupRunning = false;
- private int countBubbleCnt = 0;
private Geopoint addCoords = null;
private boolean initialized = false;
+ private ConnectivityChangeReceiver connectivityChangeReceiver;
private final UpdateLocation locationUpdater = new UpdateLocation();
@@ -110,7 +114,7 @@ public class MainActivity extends AbstractActionBarActivity {
for (final ILogin conn : loginConns) {
- final TextView connectorInfo = (TextView) inflater.inflate(R.layout.main_activity_connectorstatus, null);
+ final TextView connectorInfo = (TextView) inflater.inflate(R.layout.main_activity_connectorstatus, infoArea, false);
infoArea.addView(connectorInfo);
final StringBuilder userInfo = new StringBuilder(conn.getName()).append(Formatter.SEPARATOR);
@@ -128,6 +132,19 @@ public class MainActivity extends AbstractActionBarActivity {
}
};
+ private final class ConnectivityChangeReceiver extends BroadcastReceiver {
+ private boolean isConnected = Network.isNetworkConnected();
+
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ final boolean wasConnected = isConnected;
+ isConnected = Network.isNetworkConnected();
+ if (isConnected && !wasConnected) {
+ startBackgroundLogin();
+ }
+ }
+ }
+
private static String formatAddress(final Address address) {
final ArrayList<String> addressParts = new ArrayList<>();
@@ -147,37 +164,16 @@ public class MainActivity extends AbstractActionBarActivity {
return StringUtils.join(addressParts, ", ");
}
- private class SatellitesHandler extends GeoDirHandler {
-
- private boolean gpsEnabled = false;
- private int satellitesFixed = 0;
- private int satellitesVisible = 0;
-
+ private final Action1<GpsStatusProvider.Status> satellitesHandler = new Action1<Status>() {
@Override
- public void updateGeoData(final IGeoData data) {
- if (data.getGpsEnabled() == gpsEnabled &&
- data.getSatellitesFixed() == satellitesFixed &&
- data.getSatellitesVisible() == satellitesVisible) {
- return;
- }
- gpsEnabled = data.getGpsEnabled();
- satellitesFixed = data.getSatellitesFixed();
- satellitesVisible = data.getSatellitesVisible();
-
- if (gpsEnabled) {
- if (satellitesFixed > 0) {
- navSatellites.setText(res.getString(R.string.loc_sat) + ": " + satellitesFixed + '/' + satellitesVisible);
- } else if (satellitesVisible >= 0) {
- navSatellites.setText(res.getString(R.string.loc_sat) + ": 0/" + satellitesVisible);
- }
+ public void call(final Status gpsStatus) {
+ if (gpsStatus.gpsEnabled) {
+ navSatellites.setText(res.getString(R.string.loc_sat) + ": " + gpsStatus.satellitesFixed + '/' + gpsStatus.satellitesVisible);
} else {
navSatellites.setText(res.getString(R.string.loc_gps_disabled));
}
}
-
- }
-
- private final SatellitesHandler satellitesHandler = new SatellitesHandler();
+ };
private final Handler firstLoginHandler = new Handler() {
@@ -214,8 +210,7 @@ public class MainActivity extends AbstractActionBarActivity {
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search
- version = Version.getVersionCode(this);
- Log.i("Starting " + getPackageName() + ' ' + version + " a.k.a " + Version.getVersionName(this));
+ Log.i("Starting " + getPackageName() + ' ' + Version.getVersionCode(this) + " a.k.a " + Version.getVersionName(this));
init();
@@ -231,30 +226,34 @@ public class MainActivity extends AbstractActionBarActivity {
@Override
public void onResume() {
- super.onResume(Subscriptions.from(locationUpdater.start(GeoDirHandler.UPDATE_GEODATA), satellitesHandler.start(GeoDirHandler.UPDATE_GEODATA)));
+ super.onResume(locationUpdater.start(GeoDirHandler.UPDATE_GEODATA | GeoDirHandler.LOW_POWER),
+ Sensors.getInstance().gpsStatusObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(satellitesHandler));
updateUserInfoHandler.sendEmptyMessage(-1);
startBackgroundLogin();
init();
+
+ connectivityChangeReceiver = new ConnectivityChangeReceiver();
+ registerReceiver(connectivityChangeReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
private void startBackgroundLogin() {
- assert(app != null);
+ assert app != null;
final boolean mustLogin = app.mustRelog();
for (final ILogin conn : ConnectorFactory.getActiveLiveConnectors()) {
if (mustLogin || !conn.isLoggedIn()) {
- new Thread() {
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
@Override
- public void run() {
- if (mustLogin && conn == GCConnector.getInstance()) {
+ public void call() {
+ if (mustLogin) {
// Properly log out from geocaching.com
- GCLogin.getInstance().logout();
+ conn.logout();
}
conn.login(firstLoginHandler, MainActivity.this);
updateUserInfoHandler.sendEmptyMessage(-1);
}
- }.start();
+ });
}
}
}
@@ -276,6 +275,7 @@ public class MainActivity extends AbstractActionBarActivity {
@Override
public void onPause() {
initialized = false;
+ unregisterReceiver(connectivityChangeReceiver);
super.onPause();
}
@@ -315,7 +315,7 @@ public class MainActivity extends AbstractActionBarActivity {
startActivity(new Intent(this, SettingsActivity.class));
return true;
case R.id.menu_history:
- CacheListActivity.startActivityHistory(this);
+ startActivity(CacheListActivity.getHistoryIntent(this));
return true;
case R.id.menu_scan:
startScannerApplication();
@@ -447,7 +447,7 @@ public class MainActivity extends AbstractActionBarActivity {
setFilterTitle();
checkRestore();
- (new CleanDatabaseThread()).start();
+ DataStore.cleanIfNeeded(this);
}
protected void selectGlobalTypeFilter() {
@@ -464,11 +464,11 @@ public class MainActivity extends AbstractActionBarActivity {
sorted.addAll(Arrays.asList(CacheType.values()));
sorted.removeAll(cacheTypes);
+ final Collator collator = TextUtils.getCollator();
Collections.sort(sorted, new Comparator<CacheType>() {
-
@Override
public int compare(final CacheType left, final CacheType right) {
- return left.getL10n().compareToIgnoreCase(right.getL10n());
+ return collator.compare(left.getL10n(), right.getL10n());
}
});
@@ -501,7 +501,23 @@ public class MainActivity extends AbstractActionBarActivity {
}
public void updateCacheCounter() {
- (new CountBubbleUpdateThread()).start();
+ AppObservable.bindActivity(this, DataStore.getAllCachesCountObservable()).subscribe(new Action1<Integer>() {
+ @Override
+ public void call(final Integer countBubbleCnt1) {
+ if (countBubbleCnt1 == 0) {
+ countBubble.setVisibility(View.GONE);
+ } else {
+ countBubble.setText(Integer.toString(countBubbleCnt1));
+ countBubble.bringToFront();
+ countBubble.setVisibility(View.VISIBLE);
+ }
+ }
+ }, new Action1<Throwable>() {
+ @Override
+ public void call(final Throwable throwable) {
+ Log.e("Unable to add bubble count", throwable);
+ }
+ });
}
private void checkRestore() {
@@ -534,7 +550,7 @@ public class MainActivity extends AbstractActionBarActivity {
private class UpdateLocation extends GeoDirHandler {
@Override
- public void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final GeoData geo) {
if (!nearestView.isClickable()) {
nearestView.setFocusable(true);
nearestView.setClickable(true);
@@ -556,29 +572,21 @@ public class MainActivity extends AbstractActionBarActivity {
navAccuracy.setText(null);
}
+ final Geopoint currentCoords = geo.getCoords();
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 OnSubscribe<String>() {
+ if (addCoords == null || (currentCoords.distanceTo(addCoords) > 0.5)) {
+ addCoords = currentCoords;
+ final Observable<String> address = (new AndroidGeocoder(MainActivity.this).getFromLocation(currentCoords)
+ .onErrorResumeNext(MapQuestGeocoder.getFromLocation(currentCoords))).map(new Func1<Address, String>() {
@Override
- public void call(final Subscriber<? super String> subscriber) {
- 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()) {
- subscriber.onNext(formatAddress(addresses.get(0)));
- }
- subscriber.onCompleted();
- } catch (final Exception e) {
- subscriber.onError(e);
- }
+ public String call(final Address address) {
+ return formatAddress(address);
}
- });
- AndroidObservable.bindActivity(MainActivity.this, address.onErrorResumeNext(Observable.from(geo.getCoords().toString())))
+ }).onErrorResumeNext(Observable.just(currentCoords.toString()));
+ AppObservable.bindActivity(MainActivity.this, address)
.subscribeOn(RxUtils.networkScheduler)
.subscribe(new Action1<String>() {
@Override
@@ -588,7 +596,7 @@ public class MainActivity extends AbstractActionBarActivity {
});
}
} else {
- navLocation.setText(geo.getCoords().toString());
+ navLocation.setText(currentCoords.toString());
}
}
}
@@ -599,7 +607,7 @@ public class MainActivity extends AbstractActionBarActivity {
*/
public void cgeoFindOnMap(final View v) {
findOnMap.setPressed(true);
- CGeoMap.startActivityLiveMap(this);
+ startActivity(CGeoMap.getLiveMapIntent(this));
}
/**
@@ -607,12 +615,8 @@ public class MainActivity extends AbstractActionBarActivity {
* unused here but needed since this method is referenced from XML layout
*/
public void cgeoFindNearest(final View v) {
- if (app.currentGeo().getCoords() == null) {
- return;
- }
-
nearestView.setPressed(true);
- CacheListActivity.startActivityNearest(this, app.currentGeo().getCoords());
+ startActivity(CacheListActivity.getNearestIntent(this));
}
/**
@@ -659,86 +663,19 @@ public class MainActivity extends AbstractActionBarActivity {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
- private class CountBubbleUpdateThread extends Thread {
- private final Handler countBubbleHandler = new Handler() {
-
- @Override
- public void handleMessage(final Message msg) {
- try {
- if (countBubbleCnt == 0) {
- countBubble.setVisibility(View.GONE);
- } else {
- countBubble.setText(Integer.toString(countBubbleCnt));
- countBubble.bringToFront();
- countBubble.setVisibility(View.VISIBLE);
- }
- } catch (final Exception e) {
- Log.w("MainActivity.countBubbleHander", e);
- }
- }
- };
-
- @Override
- public void run() {
- if (app == null) {
- return;
- }
-
- int checks = 0;
- while (!DataStore.isInitialized()) {
- try {
- sleep(500);
- checks++;
- } catch (final Exception e) {
- Log.e("MainActivity.CountBubbleUpdateThread.run", e);
- }
-
- if (checks > 10) {
- return;
- }
- }
-
- countBubbleCnt = DataStore.getAllCachesCount();
-
- countBubbleHandler.sendEmptyMessage(0);
- }
- }
-
- private class CleanDatabaseThread extends Thread {
-
- @Override
- public void run() {
- if (app == null) {
- return;
- }
- if (cleanupRunning) {
- return;
- }
-
- boolean more = false;
- if (version != Settings.getVersion()) {
- Log.i("Initializing hard cleanup - version changed from " + Settings.getVersion() + " to " + version + ".");
-
- more = true;
- }
-
- cleanupRunning = true;
- DataStore.clean(more);
- cleanupRunning = false;
-
- if (version > 0) {
- Settings.setVersion(version);
- }
- }
- }
-
private void checkShowChangelog() {
- final long lastChecksum = Settings.getLastChangelogChecksum();
- final long checksum = TextUtils.checksum(getString(R.string.changelog_master) + getString(R.string.changelog_release));
- Settings.setLastChangelogChecksum(checksum);
- // don't show change log after new install...
- if (lastChecksum > 0 && lastChecksum != checksum) {
- AboutActivity.showChangeLog(this);
+ // temporary workaround for #4143
+ //TODO: understand and avoid if possible
+ try {
+ final long lastChecksum = Settings.getLastChangelogChecksum();
+ final long checksum = TextUtils.checksum(getString(R.string.changelog_master) + getString(R.string.changelog_release));
+ Settings.setLastChangelogChecksum(checksum);
+ // don't show change log after new install...
+ if (lastChecksum > 0 && lastChecksum != checksum) {
+ AboutActivity.showChangeLog(this);
+ }
+ } catch (final Exception ex) {
+ Log.e("Error checking/showing changelog!", ex);
}
}
diff --git a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
index 2591987..b0d413d 100644
--- a/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
+++ b/main/src/cgeo/geocaching/NavigateAnyPointActivity.java
@@ -7,11 +7,12 @@ import butterknife.Optional;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.activity.INavigationSource;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.geopoint.DistanceParser;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.location.DistanceParser;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.AbstractViewHolder;
import cgeo.geocaching.ui.NavigationActionProvider;
@@ -19,8 +20,13 @@ import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
+
+import rx.functions.Action0;
+import rx.schedulers.Schedulers;
import android.app.Activity;
import android.content.Context;
@@ -94,7 +100,7 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
public View getView(final int position, final View convertView, final ViewGroup parent) {
View rowView = convertView;
- ViewHolder viewHolder;
+ final ViewHolder viewHolder;
if (rowView == null) {
rowView = getInflater().inflate(R.layout.simple_way_point, parent, false);
viewHolder = new ViewHolder(rowView);
@@ -261,7 +267,7 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
private void initializeDistanceUnitSelector() {
if (StringUtils.isBlank(distanceUnit)) {
- if (Settings.isUseImperialUnits()) {
+ if (Settings.useImperialUnits()) {
distanceUnitSelector.setSelection(2); // ft
distanceUnit = res.getStringArray(R.array.distance_units)[2];
} else {
@@ -281,7 +287,7 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
if (latButton.getText().length() > 0 && lonButton.getText().length() > 0) {
gp = new Geopoint(latButton.getText().toString() + " " + lonButton.getText().toString());
}
- final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(null, gp, app.currentGeo());
+ final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(null, gp, Sensors.getInstance().currentGeo());
coordsDialog.setCancelable(true);
coordsDialog.show(getSupportFragmentManager(),"wpedit_dialog");
}
@@ -336,7 +342,7 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
menu.findItem(R.id.menu_caches_around).setVisible(visible);
menu.findItem(R.id.menu_clear_history).setVisible(!getHistoryOfSearchedLocations().isEmpty());
- } catch (final RuntimeException e) {
+ } catch (final RuntimeException ignored) {
// nothing
}
@@ -346,20 +352,14 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int menuItem = item.getItemId();
-
- final Geopoint coords = getDestination();
-
- if (coords != null) {
- addToHistory(coords);
- }
-
+ final Geopoint coords = getDestinationAndAddToHistory();
switch (menuItem) {
case R.id.menu_default_navigation:
- navigateTo();
+ navigateTo(coords);
return true;
case R.id.menu_caches_around:
- cachesAround();
+ cachesAround(coords);
return true;
case R.id.menu_clear_history:
@@ -373,22 +373,33 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
return super.onOptionsItemSelected(item);
}
- private void addToHistory(final Geopoint coords) {
+ private Geopoint getDestinationAndAddToHistory() {
+ final Geopoint coords = getDestination();
+ addToHistory(coords);
+ return coords;
+ }
+
+ private void addToHistory(@Nullable final Geopoint coords) {
+ if (coords == null) {
+ return;
+ }
+
// Add locations to history
final Destination loc = new Destination(coords);
if (!getHistoryOfSearchedLocations().contains(loc)) {
getHistoryOfSearchedLocations().add(0, loc);
-
- // Save location
- DataStore.saveSearchedDestination(loc);
-
- // Ensure to remove the footer
- historyListView.removeFooterView(getEmptyHistoryFooter());
-
- runOnUiThread(new Runnable() {
+ RxUtils.andThenOnUi(Schedulers.io(), new Action0() {
@Override
- public void run() {
+ public void call() {
+ // Save location
+ DataStore.saveSearchedDestination(loc);
+ }
+ }, new Action0() {
+ @Override
+ public void call() {
+ // Ensure to remove the footer
+ historyListView.removeFooterView(getEmptyHistoryFooter());
destinationHistoryAdapter.notifyDataSetChanged();
}
});
@@ -431,35 +442,34 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
}
}
- private void navigateTo() {
- navigateTo(getDestination());
- }
+ private void navigateTo(final Geopoint coords) {
+ if (coords == null) {
+ showToast(res.getString(R.string.err_location_unknown));
+ return;
+ }
- private void navigateTo(final Geopoint geopoint) {
- NavigationAppFactory.startDefaultNavigationApplication(1, this, geopoint);
+ NavigationAppFactory.startDefaultNavigationApplication(1, this, coords);
}
- private void cachesAround() {
- final Geopoint coords = getDestination();
-
+ private void cachesAround(final Geopoint coords) {
if (coords == null) {
showToast(res.getString(R.string.err_location_unknown));
return;
}
- CacheListActivity.startActivityCoordinates(this, coords);
+ CacheListActivity.startActivityCoordinates(this, coords, null);
finish();
}
private final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@Override
- public void updateGeoData(final IGeoData geo) {
+ public void updateGeoData(final GeoData geo) {
try {
latButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE_RAW));
lonButton.setHint(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE_RAW));
} catch (final RuntimeException e) {
- Log.w("Failed to update location.");
+ Log.w("Failed to update location", e);
}
}
};
@@ -468,15 +478,9 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
@Override
public void onClick(final View arg0) {
- final Geopoint coords = app.currentGeo().getCoords();
- if (coords == null) {
- showToast(res.getString(R.string.err_point_unknown_position));
- return;
- }
-
+ final Geopoint coords = Sensors.getInstance().currentGeo().getCoords();
latButton.setText(coords.format(GeopointFormatter.Format.LAT_DECMINUTE));
lonButton.setText(coords.format(GeopointFormatter.Format.LON_DECMINUTE));
-
changed = false;
}
}
@@ -504,30 +508,25 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
return null;
}
} else {
- if (app.currentGeo().getCoords() == null) {
- showToast(res.getString(R.string.err_point_curr_position_unavailable));
- return null;
- }
-
- coords = app.currentGeo().getCoords();
+ coords = Sensors.getInstance().currentGeo().getCoords();
}
// apply projection
- if (coords != null && StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) {
+ if (StringUtils.isNotBlank(bearingText) && StringUtils.isNotBlank(distanceText)) {
// bearing & distance
- double bearing;
+ final double bearing;
try {
bearing = Double.parseDouble(bearingText);
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
Dialogs.message(this, R.string.err_point_bear_and_dist_title, R.string.err_point_bear_and_dist);
return null;
}
- double distance;
+ final double distance;
try {
distance = DistanceParser.parseDistance(distanceText,
- !Settings.isUseImperialUnits());
- } catch (final NumberFormatException e) {
+ !Settings.useImperialUnits());
+ } catch (final NumberFormatException ignored) {
showToast(res.getString(R.string.err_parse_dist));
return null;
}
@@ -535,9 +534,7 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
coords = coords.project(bearing, distance);
}
- if (coords != null) {
- saveCoords(coords);
- }
+ saveCoords(coords);
return coords;
}
@@ -551,11 +548,11 @@ public class NavigateAnyPointActivity extends AbstractActionBarActivity implemen
@Override
public void startDefaultNavigation() {
- navigateTo();
+ navigateTo(getDestinationAndAddToHistory());
}
@Override
public void startDefaultNavigation2() {
- NavigationAppFactory.startDefaultNavigationApplication(2, this, getDestination());
+ NavigationAppFactory.startDefaultNavigationApplication(2, this, getDestinationAndAddToHistory());
}
}
diff --git a/main/src/cgeo/geocaching/PocketQueryList.java b/main/src/cgeo/geocaching/PocketQueryList.java
index 21f306e..27edffd 100644
--- a/main/src/cgeo/geocaching/PocketQueryList.java
+++ b/main/src/cgeo/geocaching/PocketQueryList.java
@@ -2,14 +2,10 @@ package cgeo.geocaching;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.utils.RxUtils;
import org.apache.commons.collections4.CollectionUtils;
-import rx.Observable;
-import rx.Observable.OnSubscribe;
-import rx.Subscriber;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
import android.app.Activity;
@@ -47,13 +43,7 @@ public final class PocketQueryList {
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);
- AndroidObservable.bindActivity(activity, Observable.create(new OnSubscribe<List<PocketQueryList>>() {
- @Override
- public void call(final Subscriber<? super List<PocketQueryList>> subscriber) {
- subscriber.onNext(GCParser.searchPocketQueryList());
- subscriber.onCompleted();
- }
- })).subscribeOn(RxUtils.networkScheduler).subscribe(new Action1<List<PocketQueryList>>() {
+ AppObservable.bindActivity(activity, GCParser.searchPocketQueryListObservable).subscribe(new Action1<List<PocketQueryList>>() {
@Override
public void call(final List<PocketQueryList> pocketQueryLists) {
waitDialog.dismiss();
@@ -61,6 +51,7 @@ public final class PocketQueryList {
}
});
}
+
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));
diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java
index edd611a..ea91857 100644
--- a/main/src/cgeo/geocaching/SearchActivity.java
+++ b/main/src/cgeo/geocaching/SearchActivity.java
@@ -9,10 +9,11 @@ import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
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.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
import cgeo.geocaching.search.AutoCompleteAdapter;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.GeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.CoordinatesInputDialog;
import cgeo.geocaching.ui.dialog.Dialogs;
@@ -62,6 +63,8 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
@InjectView(R.id.trackable) protected AutoCompleteTextView trackableEditText;
@InjectView(R.id.display_trackable) protected Button buttonSearchTrackable;
+ private static final String GOOGLE_NOW_SEARCH_ACTION = "com.google.android.gms.actions.SEARCH_ACTION";
+
@Override
public final void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -81,8 +84,8 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
return;
}
- // search query
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ // search query, from search toolbar or from google now
+ if (Intent.ACTION_SEARCH.equals(intent.getAction()) || GOOGLE_NOW_SEARCH_ACTION.equals(intent.getAction())) {
hideKeyboard();
final String query = intent.getStringExtra(SearchManager.QUERY);
final boolean keywordSearch = intent.getBooleanExtra(Intents.EXTRA_KEYWORD_SEARCH, true);
@@ -124,7 +127,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
/**
* Performs a search for query either as geocode, trackable code or keyword
*
- * @param query
+ * @param nonTrimmedQuery
* String to search for
* @param keywordSearch
* Set to true if keyword search should be performed if query isn't GC or TB
@@ -142,7 +145,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
}
final IConnector connector = ConnectorFactory.getConnector(geocode);
- if (connector instanceof ISearchByGeocode) {
+ if (connector instanceof ISearchByGeocode && geocode != null) {
CacheDetailActivity.startActivity(this, geocode.toUpperCase(Locale.US));
return true;
}
@@ -159,7 +162,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
}
}
- if (trackableConnector != ConnectorFactory.UNKNOWN_TRACKABLE_CONNECTOR) {
+ if (trackableConnector != ConnectorFactory.UNKNOWN_TRACKABLE_CONNECTOR && geocode != null) {
final Intent trackablesIntent = new Intent(this, TrackableActivity.class);
trackablesIntent.putExtra(Intents.EXTRA_GEOCODE, geocode.toUpperCase(Locale.US));
startActivity(trackablesIntent);
@@ -291,7 +294,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
}
private void updateCoordinates() {
- final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(null, null, app.currentGeo());
+ final CoordinatesInputDialog coordsDialog = CoordinatesInputDialog.getInstance(null, null, Sensors.getInstance().currentGeo());
coordsDialog.setCancelable(true);
coordsDialog.show(getSupportFragmentManager(), "wpedit_dialog");
}
@@ -307,14 +310,12 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
final String lonText = StringUtils.trim(buttonLongitude.getText().toString());
if (StringUtils.isEmpty(latText) || StringUtils.isEmpty(lonText)) {
- final IGeoData geo = app.currentGeo();
- if (geo.getCoords() != null) {
- buttonLatitude.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
- buttonLongitude.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
- }
+ final GeoData geo = Sensors.getInstance().currentGeo();
+ buttonLatitude.setText(geo.getCoords().format(GeopointFormatter.Format.LAT_DECMINUTE));
+ buttonLongitude.setText(geo.getCoords().format(GeopointFormatter.Format.LON_DECMINUTE));
} else {
try {
- CacheListActivity.startActivityCoordinates(this, new Geopoint(latText, lonText));
+ CacheListActivity.startActivityCoordinates(this, new Geopoint(latText, lonText), null);
} catch (final Geopoint.ParseException e) {
showToast(res.getString(e.resource));
}
@@ -373,7 +374,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
}
private void findByGeocodeFn() {
- final String geocodeText = StringUtils.trim(geocodeEditText.getText().toString());
+ final String geocodeText = StringUtils.trimToEmpty(geocodeEditText.getText().toString());
if (StringUtils.isBlank(geocodeText) || geocodeText.equalsIgnoreCase("GC")) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_gccode);
@@ -384,7 +385,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin
}
private void findTrackableFn() {
- final String trackableText = StringUtils.trim(trackableEditText.getText().toString());
+ final String trackableText = StringUtils.trimToEmpty(trackableEditText.getText().toString());
if (StringUtils.isBlank(trackableText) || trackableText.equalsIgnoreCase("TB")) {
Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_tb);
diff --git a/main/src/cgeo/geocaching/SearchResult.java b/main/src/cgeo/geocaching/SearchResult.java
index 74cc59d..5de1298 100644
--- a/main/src/cgeo/geocaching/SearchResult.java
+++ b/main/src/cgeo/geocaching/SearchResult.java
@@ -16,6 +16,7 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import rx.Observable;
+import rx.functions.Func0;
import rx.functions.Func1;
import rx.functions.Func2;
@@ -215,10 +216,6 @@ public class SearchResult implements Parcelable {
}
/**
- * @param excludeDisabled
- * @param excludeMine
- * @param cacheType
- * @return
*/
public SearchResult filterSearchResults(final boolean excludeDisabled, final boolean excludeMine, final CacheType cacheType) {
@@ -314,17 +311,17 @@ public class SearchResult implements Parcelable {
public static <C extends IConnector> SearchResult parallelCombineActive(final Collection<C> connectors,
final Func1<C, SearchResult> func) {
- return Observable.from(connectors).parallel(new Func1<Observable<C>, Observable<SearchResult>>() {
+ return Observable.from(connectors).flatMap(new Func1<C, Observable<SearchResult>>() {
@Override
- public Observable<SearchResult> call(final Observable<C> cObservable) {
- return cObservable.flatMap(new Func1<C, Observable<? extends SearchResult>>() {
+ public Observable<SearchResult> call(final C connector) {
+ return connector.isActive() ? Observable.defer(new Func0<Observable<SearchResult>>() {
@Override
- public Observable<? extends SearchResult> call(final C c) {
- return c.isActive() ? Observable.from(func.call(c)) : Observable.<SearchResult>empty();
+ public Observable<SearchResult> call() {
+ return Observable.just(func.call(connector));
}
- });
+ }).subscribeOn(RxUtils.networkScheduler) : Observable.<SearchResult>empty();
}
- }, RxUtils.networkScheduler).reduce(new SearchResult(), new Func2<SearchResult, SearchResult, SearchResult>() {
+ }).reduce(new SearchResult(), new Func2<SearchResult, SearchResult, SearchResult>() {
@Override
public SearchResult call(final SearchResult searchResult, final SearchResult searchResult2) {
searchResult.addSearchResult(searchResult2);
diff --git a/main/src/cgeo/geocaching/SelectMapfileActivity.java b/main/src/cgeo/geocaching/SelectMapfileActivity.java
index dc898d7..a506f16 100644
--- a/main/src/cgeo/geocaching/SelectMapfileActivity.java
+++ b/main/src/cgeo/geocaching/SelectMapfileActivity.java
@@ -33,7 +33,7 @@ public class SelectMapfileActivity extends AbstractFileListActivity<FileSelectio
private String mapFile;
- private static int REQUEST_DIRECTORY = 1;
+ private final static int REQUEST_DIRECTORY = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -53,7 +53,7 @@ public class SelectMapfileActivity extends AbstractFileListActivity<FileSelectio
dirChooser.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT,
getString(android.R.string.ok));
startActivityForResult(dirChooser, REQUEST_DIRECTORY);
- } catch (android.content.ActivityNotFoundException ex) {
+ } catch (android.content.ActivityNotFoundException ignored) {
// OI file manager not available
final Intent dirChooser = new Intent(SelectMapfileActivity.this, SimpleDirChooser.class);
dirChooser.putExtra(Intents.EXTRA_START_DIR, LocalStorage.getStorage().getAbsolutePath());
@@ -87,7 +87,7 @@ public class SelectMapfileActivity extends AbstractFileListActivity<FileSelectio
for (File dir : LocalStorage.getStorages()) {
folders.add(new File(dir, "mfmaps"));
folders.add(new File(new File(dir, "Locus"), "mapsVector"));
- folders.add(new File(dir, LocalStorage.cache));
+ folders.add(new File(dir, LocalStorage.CACHE_DIRNAME));
}
return folders;
}
@@ -98,8 +98,8 @@ public class SelectMapfileActivity extends AbstractFileListActivity<FileSelectio
}
@Override
- public void setCurrentFile(String newFile) {
- mapFile = newFile;
+ public void setCurrentFile(String name) {
+ mapFile = name;
}
@Override
diff --git a/main/src/cgeo/geocaching/StaticMapsActivity.java b/main/src/cgeo/geocaching/StaticMapsActivity.java
index ceceab9..be363f0 100644
--- a/main/src/cgeo/geocaching/StaticMapsActivity.java
+++ b/main/src/cgeo/geocaching/StaticMapsActivity.java
@@ -27,14 +27,11 @@ import java.util.List;
@OptionsMenu(R.menu.static_maps_activity_options)
public class StaticMapsActivity extends AbstractActionBarActivity {
- private static final String EXTRAS_WAYPOINT = "waypoint";
- private static final String EXTRAS_DOWNLOAD = "download";
- private static final String EXTRAS_GEOCODE = "geocode";
-
- @Extra(EXTRAS_DOWNLOAD) boolean download = false;
- @Extra(EXTRAS_WAYPOINT) Integer waypointId = null;
- @Extra(EXTRAS_GEOCODE) String geocode = null;
+ @Extra(Intents.EXTRA_DOWNLOAD) boolean download = false;
+ @Extra(Intents.EXTRA_WAYPOINT_ID) Integer waypointId = null;
+ @Extra(Intents.EXTRA_GEOCODE) String geocode = null;
+ private Geocache cache;
private final List<Bitmap> maps = new ArrayList<>();
private LayoutInflater inflater = null;
private ProgressDialog waitDialog = null;
@@ -94,12 +91,16 @@ public class StaticMapsActivity extends AbstractActionBarActivity {
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.staticmaps_activity);
- if (geocode == null) {
- showToast("Sorry, c:geo forgot for what cache you want to load static maps.");
+ cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
+
+ if (cache == null) {
+ Log.e("StaticMapsActivity.onCreate: cannot find the cache " + geocode);
finish();
return;
}
+ setCacheTitleBar(cache);
+
waitDialog = ProgressDialog.show(this, null, res.getString(R.string.map_static_loading), true);
waitDialog.setCancelable(true);
@@ -116,7 +117,6 @@ public class StaticMapsActivity extends AbstractActionBarActivity {
for (int level = 1; level <= StaticMapsProvider.MAPS_LEVEL_MAX; level++) {
try {
if (waypointId != null) {
- final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
final Bitmap image = StaticMapsProvider.getWaypointMap(geocode, cache.getWaypointById(waypointId), level);
if (image != null) {
maps.add(image);
@@ -150,7 +150,6 @@ public class StaticMapsActivity extends AbstractActionBarActivity {
}
private boolean downloadStaticMaps() {
- final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
if (waypointId == null) {
showToast(res.getString(R.string.info_storing_static_maps));
RxUtils.waitForCompletion(StaticMapsProvider.storeCacheStaticMap(cache));
diff --git a/main/src/cgeo/geocaching/StaticMapsProvider.java b/main/src/cgeo/geocaching/StaticMapsProvider.java
index 030c379..8c399af 100644
--- a/main/src/cgeo/geocaching/StaticMapsProvider.java
+++ b/main/src/cgeo/geocaching/StaticMapsProvider.java
@@ -2,7 +2,7 @@ package cgeo.geocaching;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.files.LocalStorage;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.location.GeopointFormatter.Format;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
@@ -16,8 +16,7 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import rx.Observable;
-import rx.functions.Action0;
-import rx.util.async.Async;
+import rx.functions.Func0;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -38,6 +37,8 @@ public final class StaticMapsProvider {
private static final String MAP_FILENAME_PREFIX = "map_";
private static final String MARKERS_URL = "http://status.cgeo.org/assets/markers/";
+ private static volatile long last403 = 0;
+
/** We assume there is no real usable image with less than 1k. */
private static final int MIN_MAP_IMAGE_BYTES = 1000;
@@ -54,32 +55,43 @@ public final class StaticMapsProvider {
return LocalStorage.getStorageFile(geocode, MAP_FILENAME_PREFIX + prefix, false, createDirs);
}
+ private static <T> Observable<T> checkDownloadPermission(final Observable<T> ifPermitted) {
+ return Observable.defer(new Func0<Observable<T>>() {
+ @Override
+ public Observable<T> call() {
+ if (System.currentTimeMillis() - last403 >= 30000) {
+ return ifPermitted;
+ }
+ Log.d("StaticMaps.downloadMap: request ignored because of recent \"permission denied\" answer");
+ return Observable.empty();
+ }
+ });
+ }
+
private static Observable<String> downloadDifferentZooms(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int width, final int height, final Parameters waypoints) {
- return Observable.merge(downloadMap(geocode, 20, SATELLITE, markerUrl, prefix + '1', "", latlonMap, width, height, waypoints),
+ return checkDownloadPermission(Observable.merge(downloadMap(geocode, 20, SATELLITE, markerUrl, prefix + '1', "", latlonMap, width, height, waypoints),
downloadMap(geocode, 18, SATELLITE, markerUrl, prefix + '2', "", latlonMap, width, height, waypoints),
downloadMap(geocode, 16, ROADMAP, markerUrl, prefix + '3', "", latlonMap, width, height, waypoints),
downloadMap(geocode, 14, ROADMAP, markerUrl, prefix + '4', "", latlonMap, width, height, waypoints),
- downloadMap(geocode, 11, ROADMAP, markerUrl, prefix + '5', "", latlonMap, width, height, waypoints));
+ downloadMap(geocode, 11, ROADMAP, markerUrl, prefix + '5', "", latlonMap, width, height, waypoints)));
}
private static Observable<String> downloadMap(final String geocode, final int zoom, final String mapType, final String markerUrl, final String prefix, final String shadow, final String latlonMap, final int width, final int height, final Parameters waypoints) {
- int scale = 1;
- if (width > GOOGLE_MAPS_MAX_SIZE) {
- scale = 2;
- }
+ // If it has been less than 30 seconds since we got a 403 (permission denied) from Google servers,
+ // do not try again.
+ final int scale = width <= GOOGLE_MAPS_MAX_SIZE ? 1 : 2;
final float aspectRatio = width / (float) height;
final int requestWidth = Math.min(width / scale, GOOGLE_MAPS_MAX_SIZE);
final int requestHeight = (aspectRatio > 1) ? Math.round(requestWidth / aspectRatio) : requestWidth;
- final int requestScale = scale;
final int requestZoom = Math.min((scale == 2) ? zoom + 1 : zoom, GOOGLE_MAX_ZOOM);
- return Async.fromAction(new Action0() {
+ return checkDownloadPermission(Observable.defer(new Func0<Observable<String>>() {
@Override
- public void call() {
+ public Observable<String> call() {
final Parameters params = new Parameters(
"center", latlonMap,
"zoom", String.valueOf(requestZoom),
"size", String.valueOf(requestWidth) + 'x' + String.valueOf(requestHeight),
- "scale", String.valueOf(requestScale),
+ "scale", String.valueOf(scale),
"maptype", mapType,
"markers", "icon:" + markerUrl + '|' + shadow + latlonMap,
"sensor", "false");
@@ -90,11 +102,15 @@ public final class StaticMapsProvider {
if (httpResponse == null) {
Log.e("StaticMapsProvider.downloadMap: httpResponse is null");
- return;
+ return Observable.just(prefix);
}
- if (httpResponse.getStatusLine().getStatusCode() != 200) {
- Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + httpResponse.getStatusLine().getStatusCode());
- return;
+ final int statusCode = httpResponse.getStatusLine().getStatusCode();
+ if (statusCode != 200) {
+ Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + statusCode);
+ if (statusCode == 403) {
+ last403 = System.currentTimeMillis();
+ }
+ return Observable.just(prefix);
}
final File file = getMapFile(geocode, prefix, true);
if (LocalStorage.saveEntityToFile(httpResponse, file)) {
@@ -104,8 +120,9 @@ public final class StaticMapsProvider {
FileUtils.deleteIgnoringFailure(file);
}
}
+ return Observable.just(prefix);
}
- }, prefix, RxUtils.networkScheduler);
+ }).subscribeOn(RxUtils.networkScheduler));
}
public static Observable<String> downloadMaps(final Geocache cache) {
@@ -132,16 +149,11 @@ public final class StaticMapsProvider {
}
- return Observable.merge(downloaders);
+ return checkDownloadPermission(Observable.merge(downloaders));
}
/**
* Deletes and download all Waypoints static maps.
- *
- * @param cache
- * The cache instance
- * @param edge
- * The boundings
*/
private static Observable<String> refreshAllWpStaticMaps(final Geocache cache, final int width, final int height) {
LocalStorage.deleteFilesWithPrefix(cache.getGeocode(), MAP_FILENAME_PREFIX + WAYPOINT_PREFIX);
@@ -149,7 +161,7 @@ public final class StaticMapsProvider {
for (final Waypoint waypoint : cache.getWaypoints()) {
downloaders.add(storeWaypointStaticMap(cache.getGeocode(), width, height, waypoint));
}
- return Observable.merge(downloaders);
+ return checkDownloadPermission(Observable.merge(downloaders));
}
public static Observable<String> storeWaypointStaticMap(final Geocache cache, final Waypoint waypoint) {
@@ -203,9 +215,8 @@ public final class StaticMapsProvider {
public static Observable<String> storeCachePreviewMap(final Geocache cache) {
final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA);
final Point displaySize = Compatibility.getDisplaySize();
- final int minSize = Math.min(displaySize.x, displaySize.y);
final String markerUrl = MARKERS_URL + "my_location_mdpi.png";
- return downloadMap(cache.getGeocode(), 15, ROADMAP, markerUrl, PREFIX_PREVIEW, "shadow:false|", latlonMap, minSize, minSize, null);
+ return downloadMap(cache.getGeocode(), 15, ROADMAP, markerUrl, PREFIX_PREVIEW, "shadow:false|", latlonMap, displaySize.x, displaySize.y, null);
}
private static Observable<String> downloadMaps(final String geocode, final String markerUrl, final String prefix,
@@ -248,7 +259,6 @@ public final class StaticMapsProvider {
/**
* Check if at least one map file exists for the given cache.
*
- * @param cache
* @return <code>true</code> if at least one map file exists; <code>false</code> otherwise
*/
public static boolean hasStaticMap(@NonNull final Geocache cache) {
@@ -268,8 +278,6 @@ public final class StaticMapsProvider {
/**
* Checks if at least one map file exists for the given geocode and waypoint ID.
*
- * @param geocode
- * @param waypoint
* @return <code>true</code> if at least one map file exists; <code>false</code> otherwise
*/
public static boolean hasStaticMapForWaypoint(final String geocode, final Waypoint waypoint) {
@@ -287,8 +295,6 @@ public final class StaticMapsProvider {
/**
* Checks if all map files exist for the given geocode and waypoint ID.
*
- * @param geocode
- * @param waypoint
* @return <code>true</code> if all map files exist; <code>false</code> otherwise
*/
public static boolean hasAllStaticMapsForWaypoint(final String geocode, final Waypoint waypoint) {
diff --git a/main/src/cgeo/geocaching/StatusFragment.java b/main/src/cgeo/geocaching/StatusFragment.java
index a228363..acc7011 100644
--- a/main/src/cgeo/geocaching/StatusFragment.java
+++ b/main/src/cgeo/geocaching/StatusFragment.java
@@ -1,15 +1,15 @@
package cgeo.geocaching;
import butterknife.ButterKnife;
+import butterknife.InjectView;
import cgeo.geocaching.network.StatusUpdater;
import cgeo.geocaching.network.StatusUpdater.Status;
import cgeo.geocaching.utils.Log;
import rx.Subscription;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
-import rx.schedulers.Schedulers;
import rx.subscriptions.Subscriptions;
import android.content.Intent;
@@ -26,15 +26,17 @@ import android.widget.TextView;
public class StatusFragment extends Fragment {
+ protected @InjectView(R.id.status_icon) ImageView statusIcon;
+ protected @InjectView(R.id.status_message) TextView statusMessage;
+
private Subscription statusSubscription = Subscriptions.empty();
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
final ViewGroup statusGroup = (ViewGroup) inflater.inflate(R.layout.status, container, false);
- final ImageView statusIcon = ButterKnife.findById(statusGroup, R.id.status_icon);
- final TextView statusMessage = ButterKnife.findById(statusGroup, R.id.status_message);
- statusSubscription = AndroidObservable.bindFragment(this, StatusUpdater.latestStatus).subscribeOn(Schedulers.io())
+ ButterKnife.inject(this, statusGroup);
+ statusSubscription = AppObservable.bindFragment(this, StatusUpdater.latestStatus)
.subscribe(new Action1<Status>() {
@Override
public void call(final Status status) {
@@ -89,6 +91,7 @@ public class StatusFragment extends Fragment {
public void onDestroyView() {
statusSubscription.unsubscribe();
super.onDestroyView();
+ ButterKnife.reset(this);
}
}
diff --git a/main/src/cgeo/geocaching/Trackable.java b/main/src/cgeo/geocaching/Trackable.java
index 9c2b044..6ec8c0d 100644
--- a/main/src/cgeo/geocaching/Trackable.java
+++ b/main/src/cgeo/geocaching/Trackable.java
@@ -3,17 +3,21 @@ package cgeo.geocaching;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.utils.ImageUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.text.Html;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
+import java.util.LinkedList;
import java.util.List;
public class Trackable implements ILogable {
- static final public int SPOTTED_UNSET = 0;
+ static final private int SPOTTED_UNSET = 0;
static final public int SPOTTED_CACHE = 1;
static final public int SPOTTED_USER = 2;
static final public int SPOTTED_UNKNOWN = 3;
@@ -38,10 +42,19 @@ public class Trackable implements ILogable {
private List<LogEntry> logs = new ArrayList<>();
private String trackingcode = null;
+ /**
+ * Check whether this trackable has a corresponding URL.
+ */
+ public boolean hasUrl() {
+ return getConnector().hasTrackableUrls();
+ }
+
+ @NonNull
public String getUrl() {
return getConnector().getUrl(this);
}
+ @NonNull
private TrackableConnector getConnector() {
return ConnectorFactory.getConnector(this);
}
@@ -50,7 +63,7 @@ public class Trackable implements ILogable {
return guid;
}
- public void setGuid(String guid) {
+ public void setGuid(final String guid) {
this.guid = guid;
}
@@ -59,7 +72,7 @@ public class Trackable implements ILogable {
return geocode;
}
- public void setGeocode(String geocode) {
+ public void setGeocode(final String geocode) {
this.geocode = StringUtils.upperCase(geocode);
}
@@ -67,7 +80,7 @@ public class Trackable implements ILogable {
return iconUrl;
}
- public void setIconUrl(String iconUrl) {
+ public void setIconUrl(final String iconUrl) {
this.iconUrl = iconUrl;
}
@@ -76,7 +89,7 @@ public class Trackable implements ILogable {
return name;
}
- public void setName(String name) {
+ public void setName(final String name) {
this.name = name;
}
@@ -84,7 +97,7 @@ public class Trackable implements ILogable {
return type;
}
- public void setType(String type) {
+ public void setType(final String type) {
this.type = type;
}
@@ -92,7 +105,7 @@ public class Trackable implements ILogable {
return released;
}
- public void setReleased(Date released) {
+ public void setReleased(final Date released) {
if (released == null) {
this.released = null;
}
@@ -105,7 +118,7 @@ public class Trackable implements ILogable {
return distance;
}
- public void setDistance(float distance) {
+ public void setDistance(final float distance) {
this.distance = distance;
}
@@ -113,7 +126,7 @@ public class Trackable implements ILogable {
return origin;
}
- public void setOrigin(String origin) {
+ public void setOrigin(final String origin) {
this.origin = origin;
}
@@ -121,7 +134,7 @@ public class Trackable implements ILogable {
return owner;
}
- public void setOwner(String owner) {
+ public void setOwner(final String owner) {
this.owner = owner;
}
@@ -129,7 +142,7 @@ public class Trackable implements ILogable {
return ownerGuid;
}
- public void setOwnerGuid(String ownerGuid) {
+ public void setOwnerGuid(final String ownerGuid) {
this.ownerGuid = ownerGuid;
}
@@ -137,7 +150,7 @@ public class Trackable implements ILogable {
return spottedName;
}
- public void setSpottedName(String spottedName) {
+ public void setSpottedName(final String spottedName) {
this.spottedName = spottedName;
}
@@ -145,7 +158,7 @@ public class Trackable implements ILogable {
return spottedType;
}
- public void setSpottedType(int spottedType) {
+ public void setSpottedType(final int spottedType) {
this.spottedType = spottedType;
}
@@ -153,7 +166,7 @@ public class Trackable implements ILogable {
return spottedGuid;
}
- public void setSpottedGuid(String spottedGuid) {
+ public void setSpottedGuid(final String spottedGuid) {
this.spottedGuid = spottedGuid;
}
@@ -161,7 +174,7 @@ public class Trackable implements ILogable {
return goal;
}
- public void setGoal(String goal) {
+ public void setGoal(final String goal) {
this.goal = goal;
}
@@ -169,7 +182,7 @@ public class Trackable implements ILogable {
return details;
}
- public void setDetails(String details) {
+ public void setDetails(final String details) {
this.details = details;
}
@@ -177,15 +190,16 @@ public class Trackable implements ILogable {
return image;
}
- public void setImage(String image) {
+ public void setImage(final String image) {
this.image = image;
}
+ @NonNull
public List<LogEntry> getLogs() {
return logs;
}
- public void setLogs(List<LogEntry> logs) {
+ public void setLogs(final List<LogEntry> logs) {
this.logs = logs != null ? logs : new ArrayList<LogEntry>();
}
@@ -210,11 +224,25 @@ public class Trackable implements ILogable {
return trackingcode;
}
- public void setTrackingcode(String trackingcode) {
+ public void setTrackingcode(final String trackingcode) {
this.trackingcode = trackingcode;
}
- static public List<LogType> getPossibleLogTypes() {
+ @NonNull
+ public Collection<Image> getImages() {
+ final List<Image> images = new LinkedList<>();
+ if (StringUtils.isNotBlank(image)) {
+ images.add(new Image(image, StringUtils.defaultIfBlank(name, geocode)));
+ }
+ ImageUtils.addImagesFromHtml(images, geocode, getDetails());
+ for (final LogEntry log : getLogs()) {
+ images.addAll(log.getLogImages());
+ }
+ return images;
+ }
+
+ @NonNull
+ static List<LogType> getPossibleLogTypes() {
final List<LogType> logTypes = new ArrayList<>();
logTypes.add(LogType.RETRIEVED_IT);
logTypes.add(LogType.GRABBED_IT);
diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java
index 0e784bd..7d10d34 100644
--- a/main/src/cgeo/geocaching/TrackableActivity.java
+++ b/main/src/cgeo/geocaching/TrackableActivity.java
@@ -4,40 +4,46 @@ import butterknife.ButterKnife;
import butterknife.InjectView;
import cgeo.geocaching.activity.AbstractActivity;
-import cgeo.geocaching.activity.AbstractActivity.ActivitySharingInterface;
import cgeo.geocaching.activity.AbstractViewPagerActivity;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.connector.trackable.TravelBugConnector;
import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.network.AndroidBeam;
import cgeo.geocaching.network.HtmlImage;
import cgeo.geocaching.ui.AbstractCachingPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.ui.CacheDetailsCreator;
+import cgeo.geocaching.ui.ImagesList;
import cgeo.geocaching.ui.UserActionsClickListener;
import cgeo.geocaching.ui.UserNameClickListener;
import cgeo.geocaching.ui.logs.TrackableLogsViewCreator;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.HtmlUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
import cgeo.geocaching.utils.UnknownTagsHandler;
+import org.apache.commons.collections4.CollectionUtils;
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.Nullable;
-import rx.android.observables.AndroidObservable;
-import rx.android.observables.ViewObservable;
+import rx.Observable;
+import rx.android.app.AppObservable;
+import rx.android.view.OnClickEvent;
+import rx.android.view.ViewObservable;
import rx.functions.Action1;
+import rx.functions.Func0;
+import rx.subscriptions.CompositeSubscription;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.support.v7.app.ActionBar;
import android.support.v7.view.ActionMode;
import android.text.Html;
@@ -57,11 +63,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivity.Page> implements ActivitySharingInterface {
+public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivity.Page> implements AndroidBeam.ActivitySharingInterface {
+
+ private CompositeSubscription createSubscriptions;
public enum Page {
DETAILS(R.string.detail),
- LOGS(R.string.cache_logs);
+ LOGS(R.string.cache_logs),
+ IMAGES(R.string.cache_images);
private final int resId;
@@ -77,50 +86,9 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
private String id = null;
private LayoutInflater inflater = null;
private ProgressDialog waitDialog = null;
- private final Handler loadTrackableHandler = new Handler() {
-
- @Override
- public void handleMessage(final Message msg) {
- if (trackable == null) {
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- if (StringUtils.isNotBlank(geocode)) {
- showToast(res.getString(R.string.err_tb_find) + " " + geocode + ".");
- } else {
- showToast(res.getString(R.string.err_tb_find_that));
- }
-
- finish();
- return;
- }
-
- try {
- inflater = getLayoutInflater();
- geocode = trackable.getGeocode();
-
- if (StringUtils.isNotBlank(trackable.getName())) {
- setTitle(Html.fromHtml(trackable.getName()).toString());
- } else {
- setTitle(trackable.getName());
- }
-
- invalidateOptionsMenuCompatible();
- reinitializeViewPager();
-
- } catch (final Exception e) {
- Log.e("TrackableActivity.loadTrackableHandler: ", e);
- }
-
- if (waitDialog != null) {
- waitDialog.dismiss();
- }
-
- }
- };
-
private CharSequence clickedItemText = null;
+ private ImagesList imagesList = null;
+
/**
* Action mode of the current contextual action bar (e.g. for copy and share actions).
*/
@@ -129,16 +97,17 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.viewpager_activity);
+ createSubscriptions = new CompositeSubscription();
// set title in code, as the activity needs a hard coded title due to the intent filters
setTitle(res.getString(R.string.trackable));
// get parameters
final Bundle extras = getIntent().getExtras();
- final Uri uri = getIntent().getData();
- // try to get data from extras
+ final Uri uri = AndroidBeam.getUri(getIntent());
if (extras != null) {
+ // try to get data from extras
geocode = extras.getString(Intents.EXTRA_GEOCODE);
name = extras.getString(Intents.EXTRA_NAME);
guid = extras.getString(Intents.EXTRA_GUID);
@@ -150,7 +119,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
geocode = ConnectorFactory.getTrackableFromURL(uri.toString());
final String uriHost = uri.getHost().toLowerCase(Locale.US);
- if (uriHost.contains("geocaching.com")) {
+ if (uriHost.endsWith("geocaching.com")) {
geocode = uri.getQueryParameter("tracker");
guid = uri.getQueryParameter("guid");
id = uri.getQueryParameter("id");
@@ -172,17 +141,6 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
finish();
return;
}
- } else if (uriHost.contains("coord.info")) {
- final String uriPath = uri.getPath().toLowerCase(Locale.US);
- if (StringUtils.startsWith(uriPath, "/tb")) {
- geocode = uriPath.substring(1).toUpperCase(Locale.US);
- guid = null;
- id = null;
- } else {
- showToast(res.getString(R.string.err_tb_details_open));
- finish();
- return;
- }
}
}
@@ -193,7 +151,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
return;
}
- String message;
+ final String message;
if (StringUtils.isNotBlank(name)) {
message = Html.fromHtml(name).toString();
} else if (StringUtils.isNotBlank(geocode)) {
@@ -201,17 +159,34 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
} else {
message = res.getString(R.string.trackable);
}
- waitDialog = ProgressDialog.show(this, message, res.getString(R.string.trackable_details_loading), true, true);
-
// If we have a newer Android device setup Android Beam for easy cache sharing
- initializeAndroidBeam(this);
+ AndroidBeam.enable(this, this);
- createViewPager(0, null);
- final LoadTrackableThread thread = new LoadTrackableThread(loadTrackableHandler, geocode, guid, id);
- thread.start();
+ createViewPager(0, new OnPageSelectedListener() {
+ @Override
+ public void onPageSelected(final int position) {
+ // Lazy loading of trackable images
+ if (getPage(position) == Page.IMAGES) {
+ loadTrackableImages();
+ }
+ }
+ });
+ refreshTrackable(message);
}
+ private void refreshTrackable(final String message) {
+ waitDialog = ProgressDialog.show(this, message, res.getString(R.string.trackable_details_loading), true, true);
+ createSubscriptions.add(AppObservable.bindActivity(this, loadTrackable(geocode, guid, id)).singleOrDefault(null).subscribe(new Action1<Trackable>() {
+ @Override
+ public void call(final Trackable trackable) {
+ TrackableActivity.this.trackable = trackable;
+ displayTrackable();
+ }
+ }));
+ }
+
+ @Nullable
@Override
public String getAndroidBeamUri() {
return trackable != null ? trackable.getUrl() : null;
@@ -227,7 +202,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
public boolean onOptionsItemSelected(final MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_log_touch:
- LogTrackableActivity.startActivity(this, trackable);
+ startActivityForResult(LogTrackableActivity.getIntent(this, trackable), LogTrackableActivity.LOG_TRACKABLE);
return true;
case R.id.menu_browser_trackable:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getUrl())));
@@ -240,92 +215,90 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
public boolean onPrepareOptionsMenu(final Menu menu) {
if (trackable != null) {
menu.findItem(R.id.menu_log_touch).setVisible(StringUtils.isNotBlank(geocode) && trackable.isLoggable());
- menu.findItem(R.id.menu_browser_trackable).setVisible(StringUtils.isNotBlank(trackable.getUrl()));
+ menu.findItem(R.id.menu_browser_trackable).setVisible(trackable.hasUrl());
}
return super.onPrepareOptionsMenu(menu);
}
- private class LoadTrackableThread extends Thread {
- final private Handler handler;
- final private String geocode;
- final private String guid;
- final private String id;
-
- public LoadTrackableThread(final Handler handlerIn, final String geocodeIn, final String guidIn, final String idIn) {
- handler = handlerIn;
- geocode = geocodeIn;
- guid = guidIn;
- id = idIn;
- }
-
- @Override
- public void run() {
- if (StringUtils.isNotEmpty(geocode)) {
-
- // iterate over the connectors as some codes may be handled by multiple connectors
- for (final TrackableConnector trackableConnector : ConnectorFactory.getTrackableConnectors()) {
- if (trackableConnector.canHandleTrackable(geocode)) {
- trackable = trackableConnector.searchTrackable(geocode, guid, id);
- if (trackable != null) {
- break;
+ private static Observable<Trackable> loadTrackable(final String geocode, final String guid, final String id) {
+ return Observable.defer(new Func0<Observable<Trackable>>() {
+ @Override
+ public Observable<Trackable> call() {
+ if (StringUtils.isNotEmpty(geocode)) {
+ // iterate over the connectors as some codes may be handled by multiple connectors
+ for (final TrackableConnector trackableConnector : ConnectorFactory.getTrackableConnectors()) {
+ if (trackableConnector.canHandleTrackable(geocode)) {
+ final Trackable trackable = trackableConnector.searchTrackable(geocode, guid, id);
+ if (trackable != null) {
+ return Observable.just(trackable);
+ }
}
}
+ // Check local storage (offline case)
+ final Trackable trackable = DataStore.loadTrackable(geocode);
+ if (trackable != null) {
+ return Observable.just(trackable);
+ }
}
- // Check local storage (offline case)
- if (trackable == null) {
- trackable = DataStore.loadTrackable(geocode);
- }
- }
- // fall back to GC search by GUID
- if (trackable == null) {
- trackable = TravelBugConnector.getInstance().searchTrackable(geocode, guid, id);
+
+ // Fall back to GC search by GUID
+ final Trackable trackable = TravelBugConnector.getInstance().searchTrackable(geocode, guid, id);
+ return trackable != null ? Observable.just(trackable) : Observable.<Trackable>empty();
}
- handler.sendMessage(Message.obtain());
- }
+ }).subscribeOn(RxUtils.networkScheduler);
}
- private class TrackableIconThread extends Thread {
- final private String url;
- final private Handler handler;
+ public void displayTrackable() {
+ if (trackable == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
- public TrackableIconThread(final String urlIn, final Handler handlerIn) {
- url = urlIn;
- handler = handlerIn;
+ if (StringUtils.isNotBlank(geocode)) {
+ showToast(res.getString(R.string.err_tb_find) + " " + geocode + ".");
+ } else {
+ showToast(res.getString(R.string.err_tb_find_that));
+ }
+
+ finish();
+ return;
}
- @Override
- public void run() {
- if (url == null || handler == null) {
- return;
+ try {
+ inflater = getLayoutInflater();
+ geocode = trackable.getGeocode();
+
+ if (StringUtils.isNotBlank(trackable.getName())) {
+ setTitle(Html.fromHtml(trackable.getName()).toString());
+ } else {
+ setTitle(trackable.getName());
}
- try {
- final HtmlImage imgGetter = new HtmlImage(trackable.getGeocode(), false, 0, false);
+ invalidateOptionsMenuCompatible();
+ reinitializeViewPager();
- final BitmapDrawable image = imgGetter.getDrawable(url);
- final Message message = handler.obtainMessage(0, image);
- handler.sendMessage(message);
- } catch (final Exception e) {
- Log.e("TrackableActivity.TrackableIconThread.run: ", e);
- }
+ } catch (final Exception e) {
+ Log.e("TrackableActivity.loadTrackableHandler: ", e);
}
- }
-
- private static class TrackableIconHandler extends Handler {
- final private ActionBar view;
- public TrackableIconHandler(final ActionBar viewIn) {
- view = viewIn;
+ if (waitDialog != null) {
+ waitDialog.dismiss();
}
- @Override
- public void handleMessage(final Message message) {
- final BitmapDrawable image = (BitmapDrawable) message.obj;
- if (image != null && view != null) {
- image.setBounds(0, 0, view.getHeight(), view.getHeight());
- view.setIcon(image);
+ }
+
+ private void setupIcon(final ActionBar actionBar, final String url) {
+ final HtmlImage imgGetter = new HtmlImage(HtmlImage.SHARED, false, 0, false);
+ AppObservable.bindActivity(this, imgGetter.fetchDrawable(url)).subscribe(new Action1<BitmapDrawable>() {
+ @Override
+ public void call(final BitmapDrawable image) {
+ if (actionBar != null) {
+ final int height = actionBar.getHeight();
+ image.setBounds(0, 0, height, height);
+ actionBar.setIcon(image);
+ }
}
- }
+ });
}
public static void startActivity(final AbstractActivity fromContext,
@@ -343,11 +316,38 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
case DETAILS:
return new DetailsViewCreator();
case LOGS:
- return new TrackableLogsViewCreator(this, trackable);
+ return new TrackableLogsViewCreator(this);
+ case IMAGES:
+ return new ImagesViewCreator();
}
throw new IllegalStateException(); // cannot happen as long as switch case is enum complete
}
+ private class ImagesViewCreator extends AbstractCachingPageViewCreator<View> {
+
+ @Override
+ public View getDispatchedView(final ViewGroup parentView) {
+ view = getLayoutInflater().inflate(R.layout.cachedetail_images_page, parentView, false);
+ return view;
+ }
+ }
+
+ private void loadTrackableImages() {
+ if (imagesList != null) {
+ return;
+ }
+ final PageViewCreator creator = getViewCreator(Page.IMAGES);
+ if (creator == null) {
+ return;
+ }
+ final View imageView = creator.getView(null);
+ if (imageView == null) {
+ return;
+ }
+ imagesList = new ImagesList(this, trackable.getGeocode());
+ createSubscriptions.add(imagesList.loadImages(imageView, trackable.getImages(), false));
+ }
+
@Override
protected String getTitle(final Page page) {
return res.getString(page.resId);
@@ -357,9 +357,12 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
protected Pair<List<? extends Page>, Integer> getOrderedPages() {
final List<Page> pages = new ArrayList<>();
pages.add(Page.DETAILS);
- if (!trackable.getLogs().isEmpty()) {
+ if (CollectionUtils.isNotEmpty(trackable.getLogs())) {
pages.add(Page.LOGS);
}
+ if (CollectionUtils.isNotEmpty(trackable.getImages())) {
+ pages.add(Page.IMAGES);
+ }
return new ImmutablePair<List<? extends Page>, Integer>(pages, 0);
}
@@ -382,16 +385,14 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// action bar icon
if (StringUtils.isNotBlank(trackable.getIconUrl())) {
- final TrackableIconHandler iconHandler = new TrackableIconHandler(getSupportActionBar());
- final TrackableIconThread iconThread = new TrackableIconThread(trackable.getIconUrl(), iconHandler);
- iconThread.start();
+ setupIcon(getSupportActionBar(), trackable.getIconUrl());
}
// trackable name
- addContextMenu(details.add(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)));
+ addContextMenu(details.add(R.string.trackable_name, StringUtils.isNotBlank(trackable.getName()) ? Html.fromHtml(trackable.getName()).toString() : res.getString(R.string.trackable_unknown)).right);
// trackable type
- String tbType;
+ final String tbType;
if (StringUtils.isNotBlank(trackable.getType())) {
tbType = Html.fromHtml(trackable.getType()).toString();
} else {
@@ -400,10 +401,10 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
details.add(R.string.trackable_type, tbType);
// trackable geocode
- addContextMenu(details.add(R.string.trackable_code, trackable.getGeocode()));
+ addContextMenu(details.add(R.string.trackable_code, trackable.getGeocode()).right);
// trackable owner
- final TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown));
+ final TextView owner = details.add(R.string.trackable_owner, res.getString(R.string.trackable_unknown)).right;
if (StringUtils.isNotBlank(trackable.getOwner())) {
owner.setText(Html.fromHtml(trackable.getOwner()), TextView.BufferType.SPANNABLE);
owner.setOnClickListener(new UserActionsClickListener(trackable));
@@ -413,34 +414,39 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
if (StringUtils.isNotBlank(trackable.getSpottedName()) ||
trackable.getSpottedType() == Trackable.SPOTTED_UNKNOWN ||
trackable.getSpottedType() == Trackable.SPOTTED_OWNER) {
+
+ final StringBuilder text;
boolean showTimeSpan = true;
- StringBuilder text;
-
- if (trackable.getSpottedType() == Trackable.SPOTTED_CACHE) {
- text = new StringBuilder(res.getString(R.string.trackable_spotted_in_cache) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString());
- } else if (trackable.getSpottedType() == Trackable.SPOTTED_USER) {
- text = new StringBuilder(res.getString(R.string.trackable_spotted_at_user) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString());
- } else if (trackable.getSpottedType() == Trackable.SPOTTED_UNKNOWN) {
- text = new StringBuilder(res.getString(R.string.trackable_spotted_unknown_location));
- } else if (trackable.getSpottedType() == Trackable.SPOTTED_OWNER) {
- text = new StringBuilder(res.getString(R.string.trackable_spotted_owner));
- } else {
- text = new StringBuilder("N/A");
- showTimeSpan = false;
+ switch (trackable.getSpottedType()) {
+ case Trackable.SPOTTED_CACHE:
+ text = new StringBuilder(res.getString(R.string.trackable_spotted_in_cache) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString());
+ break;
+ case Trackable.SPOTTED_USER:
+ text = new StringBuilder(res.getString(R.string.trackable_spotted_at_user) + ' ' + Html.fromHtml(trackable.getSpottedName()).toString());
+ break;
+ case Trackable.SPOTTED_UNKNOWN:
+ text = new StringBuilder(res.getString(R.string.trackable_spotted_unknown_location));
+ break;
+ case Trackable.SPOTTED_OWNER:
+ text = new StringBuilder(res.getString(R.string.trackable_spotted_owner));
+ break;
+ default:
+ text = new StringBuilder("N/A");
+ showTimeSpan = false;
+ break;
}
// days since last spotting
- if (showTimeSpan && trackable.getLogs() != null) {
+ if (showTimeSpan) {
for (final LogEntry log : trackable.getLogs()) {
if (log.type == LogType.RETRIEVED_IT || log.type == LogType.GRABBED_IT || log.type == LogType.DISCOVERED_IT || log.type == LogType.PLACED_IT) {
- final int days = log.daysSinceLog();
- text.append(" (").append(res.getQuantityString(R.plurals.days_ago, days, days)).append(')');
+ text.append(" (").append(Formatter.formatDaysAgo(log.date)).append(')');
break;
}
}
}
- final TextView spotted = details.add(R.string.trackable_spotted, text.toString());
+ final TextView spotted = details.add(R.string.trackable_spotted, text.toString()).right;
spotted.setClickable(true);
if (Trackable.SPOTTED_CACHE == trackable.getSpottedType()) {
spotted.setOnClickListener(new View.OnClickListener() {
@@ -467,19 +473,19 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
// trackable origin
if (StringUtils.isNotBlank(trackable.getOrigin())) {
- final TextView origin = details.add(R.string.trackable_origin, "");
+ final TextView origin = details.add(R.string.trackable_origin, "").right;
origin.setText(Html.fromHtml(trackable.getOrigin()), TextView.BufferType.SPANNABLE);
addContextMenu(origin);
}
// trackable released
if (trackable.getReleased() != null) {
- addContextMenu(details.add(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())));
+ addContextMenu(details.add(R.string.trackable_released, Formatter.formatDate(trackable.getReleased().getTime())).right);
}
// trackable distance
if (trackable.getDistance() >= 0) {
- addContextMenu(details.add(R.string.trackable_distance, Units.getDistanceFromKilometers(trackable.getDistance())));
+ addContextMenu(details.add(R.string.trackable_distance, Units.getDistanceFromKilometers(trackable.getDistance())).right);
}
// trackable goal
@@ -507,14 +513,14 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
trackableImage.setImageResource(R.drawable.image_not_loaded);
trackableImage.setClickable(true);
- ViewObservable.clicks(trackableImage, false).subscribe(new Action1<View>() {
+ ViewObservable.clicks(trackableImage, false).subscribe(new Action1<OnClickEvent>() {
@Override
- public void call(final View view) {
+ public void call(final OnClickEvent onClickEvent) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.getImage())));
}
});
- AndroidObservable.bindActivity(TrackableActivity.this, new HtmlImage(geocode, true, 0, false).fetchDrawable(trackable.getImage())).subscribe(new Action1<BitmapDrawable>() {
+ AppObservable.bindActivity(TrackableActivity.this, new HtmlImage(geocode, true, 0, false).fetchDrawable(trackable.getImage())).subscribe(new Action1<BitmapDrawable>() {
@Override
public void call(final BitmapDrawable bitmapDrawable) {
trackableImage.setImageDrawable(bitmapDrawable);
@@ -555,6 +561,10 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public boolean onPrepareActionMode(final ActionMode actionMode, final Menu menu) {
+ return prepareClipboardActionMode(view, actionMode, menu);
+ }
+
+ private boolean prepareClipboardActionMode(final View view, final ActionMode actionMode, final Menu menu) {
final int viewId = view.getId();
assert view instanceof TextView;
clickedItemText = ((TextView) view).getText();
@@ -584,6 +594,7 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
@Override
public boolean onCreateActionMode(final ActionMode actionMode, final Menu menu) {
actionMode.getMenuInflater().inflate(R.menu.details_context, menu);
+ prepareClipboardActionMode(view, actionMode, menu);
return true;
}
@@ -595,4 +606,21 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi
return false;
}
+ @Override
+ protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
+ // Refresh the logs view after coming back from logging a trackable
+ if (requestCode == LogTrackableActivity.LOG_TRACKABLE && resultCode == RESULT_OK) {
+ refreshTrackable(StringUtils.defaultIfBlank(trackable.getName(), trackable.getGeocode()));
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ createSubscriptions.unsubscribe();
+ super.onDestroy();
+ }
+
+ public Trackable getTrackable() {
+ return trackable;
+ }
}
diff --git a/main/src/cgeo/geocaching/UsefulAppsActivity.java b/main/src/cgeo/geocaching/UsefulAppsActivity.java
index a2cdaf7..d4517dc 100644
--- a/main/src/cgeo/geocaching/UsefulAppsActivity.java
+++ b/main/src/cgeo/geocaching/UsefulAppsActivity.java
@@ -5,8 +5,10 @@ import butterknife.InjectView;
import cgeo.geocaching.activity.AbstractActionBarActivity;
import cgeo.geocaching.ui.AbstractViewHolder;
+import cgeo.geocaching.utils.ProcessUtils;
+
+import org.eclipse.jdt.annotation.NonNull;
-import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -36,27 +38,16 @@ public class UsefulAppsActivity extends AbstractActionBarActivity {
private final int titleId;
private final int descriptionId;
private final int iconId;
+ @NonNull
private final String packageName;
- public HelperApp(final int title, final int description, final int icon, final String packageName) {
+ public HelperApp(final int title, final int description, final int icon, @NonNull final String packageName) {
this.titleId = title;
this.descriptionId = description;
this.iconId = icon;
this.packageName = packageName;
}
- private void installFromMarket(final Activity activity) {
- try {
- // allow also opening pure http URLs in addition to market packages
- final String url = (packageName.startsWith("http:")) ? packageName : "market://details?id=" + packageName;
- final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- activity.startActivity(marketIntent);
-
- } catch (final RuntimeException e) {
- // market not available in standard emulator
- }
- }
}
private static final HelperApp[] HELPER_APPS = {
@@ -106,7 +97,12 @@ public class UsefulAppsActivity extends AbstractActionBarActivity {
@Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
final HelperApp helperApp = HELPER_APPS[position];
- helperApp.installFromMarket(UsefulAppsActivity.this);
+ if (helperApp.packageName.startsWith("http")) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(helperApp.packageName)));
+ }
+ else {
+ ProcessUtils.openMarket(UsefulAppsActivity.this, helperApp.packageName);
+ }
}
});
}
diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java
index 7381aab..cc00b1c 100644
--- a/main/src/cgeo/geocaching/Waypoint.java
+++ b/main/src/cgeo/geocaching/Waypoint.java
@@ -2,7 +2,7 @@ package cgeo.geocaching;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.lang3.StringUtils;
@@ -21,13 +21,13 @@ public class Waypoint implements IWaypoint {
public static final String PREFIX_OWN = "OWN";
private static final int ORDER_UNDEFINED = -2;
+ private static final Pattern PATTERN_COORDS = Pattern.compile("\\b[nNsS]\\s*\\d");
private int id = -1;
private String geocode = "geocode";
private WaypointType waypointType = WaypointType.WAYPOINT;
private String prefix = "";
private String lookup = "";
private String name = "";
- private String latlon = "";
private Geopoint coords = null;
private String note = "";
private int cachedOrder = ORDER_UNDEFINED;
@@ -37,8 +37,6 @@ public class Waypoint implements IWaypoint {
/**
* require name and type for every waypoint
*
- * @param name
- * @param type
*/
public Waypoint(final String name, final WaypointType type, final boolean own) {
this.name = name;
@@ -49,7 +47,6 @@ public class Waypoint implements IWaypoint {
/**
* copy constructor
*
- * @param other
*/
public Waypoint(final Waypoint other) {
merge(other);
@@ -67,9 +64,6 @@ public class Waypoint implements IWaypoint {
if (StringUtils.isBlank(name)) {
setName(old.name);
}
- if (StringUtils.isBlank(latlon) || latlon.startsWith("?")) { // there are waypoints containing "???"
- latlon = old.latlon;
- }
if (coords == null) {
coords = old.coords;
}
@@ -100,18 +94,11 @@ public class Waypoint implements IWaypoint {
if (newPrefixes.containsKey(prefix)) {
newPrefixes.get(prefix).merge(oldWaypoint);
} else if (oldWaypoint.isUserDefined() || forceMerge) {
- // personal note waypoints should always be taken from the new list only
- if (!isPersonalNoteWaypoint(oldWaypoint)) {
- newPoints.add(oldWaypoint);
- }
+ newPoints.add(oldWaypoint);
}
}
}
- private static boolean isPersonalNoteWaypoint(final @NonNull Waypoint waypoint) {
- return StringUtils.startsWith(waypoint.getName(), CgeoApplication.getInstance().getString(R.string.cache_personal_note) + " ");
- }
-
public boolean isUserDefined() {
return own || WaypointType.OWN == waypointType;
}
@@ -160,6 +147,7 @@ public class Waypoint implements IWaypoint {
cachedOrder = ORDER_UNDEFINED;
}
+ @NonNull
public String getUrl() {
return "http://www.geocaching.com/seek/cache_details.aspx?wp=" + geocode;
}
@@ -204,14 +192,6 @@ public class Waypoint implements IWaypoint {
this.name = name;
}
- public String getLatlon() {
- return latlon;
- }
-
- public void setLatlon(final String latlon) {
- this.latlon = latlon;
- }
-
@Override
public Geopoint getCoords() {
return coords;
@@ -279,7 +259,6 @@ public class Waypoint implements IWaypoint {
/**
* Delegates the creation of the waypoint-id for gpx-export to the waypoint
*
- * @return
*/
public String getGpxId() {
@@ -303,10 +282,9 @@ public class Waypoint implements IWaypoint {
*/
public static Collection<Waypoint> parseWaypointsFromNote(@NonNull final String initialNote) {
final List<Waypoint> waypoints = new LinkedList<>();
- final Pattern COORDPATTERN = Pattern.compile("\\b[nNsS]{1}\\s*\\d"); // begin of coordinates
String note = initialNote;
- MatcherWrapper matcher = new MatcherWrapper(COORDPATTERN, note);
+ MatcherWrapper matcher = new MatcherWrapper(PATTERN_COORDS, note);
int count = 1;
while (matcher.find()) {
try {
@@ -316,17 +294,16 @@ public class Waypoint implements IWaypoint {
((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) {
final String name = CgeoApplication.getInstance().getString(R.string.cache_personal_note) + " " + count;
final String potentialWaypointType = note.substring(Math.max(0, matcher.start() - 15));
- final Waypoint waypoint = new Waypoint(name, parseWaypointType(potentialWaypointType), false);
+ final Waypoint waypoint = new Waypoint(name, parseWaypointType(potentialWaypointType), true);
waypoint.setCoords(point);
waypoints.add(waypoint);
count++;
}
- } catch (final Geopoint.ParseException e) {
- // ignore
+ } catch (final Geopoint.ParseException ignored) {
}
note = note.substring(matcher.start() + 1);
- matcher = new MatcherWrapper(COORDPATTERN, note);
+ matcher = new MatcherWrapper(PATTERN_COORDS, note);
}
return waypoints;
}
diff --git a/main/src/cgeo/geocaching/WaypointPopupFragment.java b/main/src/cgeo/geocaching/WaypointPopupFragment.java
index 03d95e5..227e30d 100644
--- a/main/src/cgeo/geocaching/WaypointPopupFragment.java
+++ b/main/src/cgeo/geocaching/WaypointPopupFragment.java
@@ -4,9 +4,9 @@ import butterknife.ButterKnife;
import butterknife.InjectView;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.ui.CacheDetailsCreator;
import cgeo.geocaching.utils.Log;
@@ -48,8 +48,8 @@ public class WaypointPopupFragment extends AbstractDialogFragment {
}
@Override
- protected void onUpdateGeoData(IGeoData geo) {
- if (geo.getCoords() != null && waypoint != null && waypoint.getCoords() != null) {
+ protected void onUpdateGeoData(GeoData geo) {
+ if (waypoint != null && waypoint.getCoords() != null) {
waypointDistance.setText(Units.getDistanceFromKilometers(geo.getCoords().distanceTo(waypoint.getCoords())));
waypointDistance.bringToFront();
}
@@ -60,6 +60,13 @@ public class WaypointPopupFragment extends AbstractDialogFragment {
super.init();
waypoint = DataStore.loadWaypoint(waypointId);
+
+ if (waypoint == null) {
+ Log.e("WaypointPopupFragment.init: unable to get waypoint " + waypointId);
+ getActivity().finish();
+ return;
+ }
+
try {
if (StringUtils.isNotBlank(waypoint.getName())) {
setTitle(waypoint.getName());
diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java
index cc9931a..6ceead0 100644
--- a/main/src/cgeo/geocaching/activity/AbstractActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java
@@ -3,7 +3,10 @@ package cgeo.geocaching.activity;
import butterknife.ButterKnife;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.network.AndroidBeam;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.ClipboardUtils;
@@ -13,18 +16,13 @@ import cgeo.geocaching.utils.TranslationUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
-import android.annotation.TargetApi;
import android.content.Intent;
import android.content.res.Resources;
-import android.nfc.NdefMessage;
-import android.nfc.NdefRecord;
-import android.nfc.NfcAdapter;
-import android.nfc.NfcEvent;
-import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
@@ -75,6 +73,7 @@ public abstract class AbstractActivity extends ActionBarActivity implements IAbs
supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
initializeCommonFields();
+ AndroidBeam.disable(this);
}
@Override
@@ -96,9 +95,9 @@ public abstract class AbstractActivity extends ActionBarActivity implements IAbs
return super.onOptionsItemSelected(item);
}
- public void onResume(final Subscription resumeSubscription) {
+ public void onResume(final Subscription... resumeSubscriptions) {
super.onResume();
- this.resumeSubscription = resumeSubscription;
+ this.resumeSubscription = Subscriptions.from(resumeSubscriptions);
}
@Override
@@ -203,34 +202,21 @@ public abstract class AbstractActivity extends ActionBarActivity implements IAbs
}
}
- // Do not support older devices than Android 4.0
- // Although there even are 2.3 devices (Nexus S)
- // these are so few that we don't want to deal with the older (non Android Beam) API
-
- public interface ActivitySharingInterface {
- /** Return an URL that represent the current activity for sharing or null for no sharing. */
- public String getAndroidBeamUri();
- }
-
- protected void initializeAndroidBeam(final ActivitySharingInterface sharingInterface) {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- initializeICSAndroidBeam(sharingInterface);
+ protected void setCacheTitleBar(@Nullable final String geocode, @Nullable final String name, @Nullable final CacheType type) {
+ if (StringUtils.isNotBlank(name)) {
+ setTitle(StringUtils.isNotBlank(geocode) ? name + " (" + geocode + ")" : name);
+ } else {
+ setTitle(StringUtils.isNotBlank(geocode) ? geocode : res.getString(R.string.cache));
}
- }
-
- @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
- protected void initializeICSAndroidBeam(final ActivitySharingInterface sharingInterface) {
- final NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- if (nfcAdapter == null) {
- return;
+ if (type != null) {
+ getSupportActionBar().setIcon(getResources().getDrawable(type.markerId));
+ } else {
+ getSupportActionBar().setIcon(android.R.color.transparent);
}
- nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
- @Override
- public NdefMessage createNdefMessage(final NfcEvent event) {
- final String uri = sharingInterface.getAndroidBeamUri();
- return uri != null ? new NdefMessage(new NdefRecord[]{NdefRecord.createUri(uri)}) : null;
- }
- }, this);
+ }
+ protected void setCacheTitleBar(final @NonNull Geocache cache) {
+ setCacheTitleBar(cache.getGeocode(), cache.getName(), cache.getType());
}
+
}
diff --git a/main/src/cgeo/geocaching/activity/AbstractListActivity.java b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
index d7482c3..86ca98f 100644
--- a/main/src/cgeo/geocaching/activity/AbstractListActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractListActivity.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.activity;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.network.AndroidBeam;
import android.content.res.Resources;
import android.os.Bundle;
@@ -48,6 +49,7 @@ public abstract class AbstractListActivity extends ActionBarListActivity impleme
initializeCommonFields();
initUpAction();
+ AndroidBeam.disable(this);
}
protected void initUpAction() {
diff --git a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
index 64186a0..11a5436 100644
--- a/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
+++ b/main/src/cgeo/geocaching/activity/AbstractViewPagerActivity.java
@@ -68,14 +68,12 @@ public abstract class AbstractViewPagerActivity<Page extends Enum<Page>> extends
/**
* Returns a validated view.
*
- * @return
*/
public View getDispatchedView(final ViewGroup parentView);
/**
* Returns a (maybe cached) view.
*
- * @return
*/
public View getView(final ViewGroup parentView);
diff --git a/main/src/cgeo/geocaching/activity/ActionBarListActivity.java b/main/src/cgeo/geocaching/activity/ActionBarListActivity.java
index 07c7ec3..a2d3ddf 100644
--- a/main/src/cgeo/geocaching/activity/ActionBarListActivity.java
+++ b/main/src/cgeo/geocaching/activity/ActionBarListActivity.java
@@ -18,12 +18,12 @@ public class ActionBarListActivity extends ActionBarActivity {
return mListView;
}
- protected void setListAdapter(ListAdapter adapter) {
+ protected void setListAdapter(final ListAdapter adapter) {
getListView().setAdapter(adapter);
}
protected ListAdapter getListAdapter() {
- ListAdapter adapter = getListView().getAdapter();
+ final ListAdapter adapter = getListView().getAdapter();
if (adapter instanceof HeaderViewListAdapter) {
return ((HeaderViewListAdapter)adapter).getWrappedAdapter();
}
diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java
index 28042b0..01fc62e 100644
--- a/main/src/cgeo/geocaching/activity/ActivityMixin.java
+++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java
@@ -1,11 +1,14 @@
package cgeo.geocaching.activity;
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.MainActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.settings.Settings;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.os.Build.VERSION;
@@ -111,10 +114,15 @@ public final class ActivityMixin {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
if (Settings.useHardwareAcceleration()) {
- window.setFlags(LayoutParams.FLAG_HARDWARE_ACCELERATED, LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ enableHardwareAcceleration(window);
}
}
+ @TargetApi(VERSION_CODES.HONEYCOMB)
+ private static void enableHardwareAcceleration(final Window window) {
+ window.addFlags(LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ }
+
public static void invalidateOptionsMenu(final Activity activity) {
if (activity instanceof ActionBarActivity) {
((ActionBarActivity) activity).supportInvalidateOptionsMenu();
@@ -127,8 +135,6 @@ public final class ActivityMixin {
/**
* insert text into the EditText at the current cursor position
*
- * @param editText
- * @param insertText
* @param moveCursor
* place the cursor after the inserted text
*/
@@ -139,7 +145,7 @@ public final class ActivityMixin {
final int end = Math.max(selectionStart, selectionEnd);
final String content = editText.getText().toString();
- String completeText;
+ final String completeText;
if (start > 0 && !Character.isWhitespace(content.charAt(start - 1))) {
completeText = " " + insertText;
} else {
@@ -152,13 +158,18 @@ public final class ActivityMixin {
}
public static boolean navigateUp(@NonNull final Activity activity) {
- // see http://developer.android.com/training/implementing-navigation/ancestral.html
- final Intent upIntent = NavUtils.getParentActivityIntent(activity);
- if (upIntent == null) {
+ // first check if there is a parent declared in the manifest
+ Intent upIntent = NavUtils.getParentActivityIntent(activity);
+ // if there is no parent, and if this was not a new task, then just go back to simulate going to a parent
+ if (upIntent == null && !activity.isTaskRoot()) {
activity.finish();
return true;
}
- if (NavUtils.shouldUpRecreateTask(activity, upIntent)) {
+ // use the main activity, if there was no back stack and no manifest based parent
+ if (upIntent == null) {
+ upIntent = new Intent(CgeoApplication.getInstance(), MainActivity.class);
+ }
+ if (NavUtils.shouldUpRecreateTask(activity, upIntent) || activity.isTaskRoot()) {
// This activity is NOT part of this app's task, so create a new task
// when navigating up, with a synthesized back stack.
TaskStackBuilder.create(activity)
@@ -175,7 +186,7 @@ public final class ActivityMixin {
}
public static void presentShowcase(final IAbstractActivity activity) {
- if (VERSION.SDK_INT < 11) {
+ if (VERSION.SDK_INT < 14) {
return;
}
final ShowcaseViewBuilder builder = activity.getShowcase();
diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/activity/OAuthAuthorizationActivity.java
index eb56f0b..2dfac5b 100644
--- a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/activity/OAuthAuthorizationActivity.java
@@ -1,13 +1,17 @@
-package cgeo.geocaching.network;
+package cgeo.geocaching.activity;
import butterknife.InjectView;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
-import cgeo.geocaching.activity.AbstractActivity;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.OAuth;
+import cgeo.geocaching.network.OAuthTokens;
+import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.BundleUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
+import cgeo.geocaching.utils.RxUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.ParseException;
@@ -19,6 +23,8 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.functions.Action0;
+
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
@@ -40,6 +46,8 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
private static final int STATUS_ERROR = 0;
private static final int STATUS_SUCCESS = 1;
private static final int STATUS_ERROR_EXT_MSG = 2;
+ private static final Pattern PARAMS_PATTERN_1 = Pattern.compile("oauth_token=([\\w_.-]+)");
+ private static final Pattern PARAMS_PATTERN_2 = Pattern.compile("oauth_token_secret=([\\w_.-]+)");
@NonNull private String host = StringUtils.EMPTY;
@NonNull private String pathRequest = StringUtils.EMPTY;
@@ -51,18 +59,16 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
@NonNull private String callback = StringUtils.EMPTY;
private String OAtoken = null;
private String OAtokenSecret = null;
- private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)");
- private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)");
@InjectView(R.id.start) protected Button startButton;
@InjectView(R.id.auth_1) protected TextView auth_1;
@InjectView(R.id.auth_2) protected TextView auth_2;
private ProgressDialog requestTokenDialog = null;
private ProgressDialog changeTokensDialog = null;
- private Handler requestTokenHandler = new Handler() {
+ private final Handler requestTokenHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
if (requestTokenDialog != null && requestTokenDialog.isShowing()) {
requestTokenDialog.dismiss();
}
@@ -85,10 +91,10 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
};
- private Handler changeTokensHandler = new Handler() {
+ private final Handler changeTokensHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
if (changeTokensDialog != null && changeTokensDialog.isShowing()) {
changeTokensDialog.dismiss();
}
@@ -105,10 +111,10 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
};
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.authorization_activity);
- Bundle extras = getIntent().getExtras();
+ final Bundle extras = getIntent().getExtras();
if (extras != null) {
host = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_HOST, host);
pathRequest = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_PATH_REQUEST, pathRequest);
@@ -125,7 +131,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
auth_1.setText(getAuthExplainShort());
auth_2.setText(getAuthExplainLong());
- ImmutablePair<String, String> tempToken = getTempTokens();
+ final ImmutablePair<String, String> tempToken = getTempTokens();
OAtoken = tempToken.left;
OAtokenSecret = tempToken.right;
@@ -167,7 +173,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
final Parameters params = new Parameters();
params.put("oauth_callback", callback);
final String method = "GET";
- OAuth.signOAuth(host, pathRequest, method, https, params, null, null, consumerKey, consumerSecret);
+ OAuth.signOAuth(host, pathRequest, method, https, params, new OAuthTokens(null, null), consumerKey, consumerSecret);
final HttpResponse response = Network.getRequest(getUrlPrefix() + host + pathRequest, params);
if (Network.isSuccess(response)) {
@@ -176,11 +182,11 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
int status = STATUS_ERROR;
if (StringUtils.isNotBlank(line)) {
assert line != null;
- final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(PARAMS_PATTERN_1, line);
if (paramsMatcher1.find()) {
OAtoken = paramsMatcher1.group(1);
}
- final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(PARAMS_PATTERN_2, line);
if (paramsMatcher2.find()) {
OAtokenSecret = paramsMatcher2.group(1);
}
@@ -193,9 +199,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser));
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getUrlPrefix() + host + pathAuthorize + "?" + encodedParams)));
status = STATUS_SUCCESS;
- } catch (ParseException e) {
- Log.e("OAuthAuthorizationActivity.requestToken", e);
- } catch (IOException e) {
+ } catch (ParseException | IOException e) {
Log.e("OAuthAuthorizationActivity.requestToken", e);
}
}
@@ -221,17 +225,17 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
final Parameters params = new Parameters("oauth_verifier", verifier);
final String method = "POST";
- OAuth.signOAuth(host, pathAccess, method, https, params, OAtoken, OAtokenSecret, consumerKey, consumerSecret);
+ OAuth.signOAuth(host, pathAccess, method, https, params, new OAuthTokens(OAtoken, OAtokenSecret), consumerKey, consumerSecret);
final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest(getUrlPrefix() + host + pathAccess, params)));
OAtoken = "";
OAtokenSecret = "";
- final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line);
+ final MatcherWrapper paramsMatcher1 = new MatcherWrapper(PARAMS_PATTERN_1, line);
if (paramsMatcher1.find()) {
OAtoken = paramsMatcher1.group(1);
}
- final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line);
+ final MatcherWrapper paramsMatcher2 = new MatcherWrapper(PARAMS_PATTERN_2, line);
if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) {
OAtokenSecret = paramsMatcher2.group(1);
}
@@ -244,7 +248,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
setTokens(OAtoken, OAtokenSecret, true);
status = AUTHENTICATED;
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("OAuthAuthorizationActivity.changeToken", e);
}
@@ -258,7 +262,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
private class StartListener implements View.OnClickListener {
@Override
- public void onClick(View arg0) {
+ public void onClick(final View arg0) {
if (requestTokenDialog == null) {
requestTokenDialog = new ProgressDialog(OAuthAuthorizationActivity.this);
requestTokenDialog.setCancelable(false);
@@ -270,13 +274,12 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
startButton.setOnClickListener(null);
setTempTokens(null, null);
- (new Thread() {
-
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
@Override
- public void run() {
+ public void call() {
requestToken();
}
- }).start();
+ });
}
}
@@ -288,13 +291,12 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
}
changeTokensDialog.show();
- (new Thread() {
-
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
@Override
- public void run() {
+ public void call() {
changeToken(verifier);
}
- }).start();
+ });
}
protected abstract ImmutablePair<String, String> getTempTokens();
@@ -333,7 +335,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
* @return String with a more detailed error message (user-facing, localized), can be empty
*/
@SuppressWarnings("static-method")
- protected String getExtendedErrorMsg(HttpResponse response) {
+ protected String getExtendedErrorMsg(final HttpResponse response) {
return StringUtils.EMPTY;
}
@@ -363,14 +365,14 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
@NonNull public final String consumerSecret;
@NonNull public final String callback;
- public OAuthParameters(@NonNull String host,
- @NonNull String pathRequest,
- @NonNull String pathAuthorize,
- @NonNull String pathAccess,
- boolean https,
- @NonNull String consumerKey,
- @NonNull String consumerSecret,
- @NonNull String callback) {
+ public OAuthParameters(@NonNull final String host,
+ @NonNull final String pathRequest,
+ @NonNull final String pathAuthorize,
+ @NonNull final String pathAccess,
+ final boolean https,
+ @NonNull final String consumerKey,
+ @NonNull final String consumerSecret,
+ @NonNull final String callback) {
this.host = host;
this.pathRequest = pathRequest;
this.pathAuthorize = pathAuthorize;
@@ -381,7 +383,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity {
this.callback = callback;
}
- public void setOAuthExtras(Intent intent) {
+ public void setOAuthExtras(final Intent intent) {
if (intent != null) {
intent.putExtra(Intents.EXTRA_OAUTH_HOST, host);
intent.putExtra(Intents.EXTRA_OAUTH_PATH_REQUEST, pathRequest);
diff --git a/main/src/cgeo/geocaching/activity/Progress.java b/main/src/cgeo/geocaching/activity/Progress.java
index 8ee88a7..e87eaa6 100644
--- a/main/src/cgeo/geocaching/activity/Progress.java
+++ b/main/src/cgeo/geocaching/activity/Progress.java
@@ -19,7 +19,7 @@ public class Progress {
private int progressDivider = 1;
final private boolean hideAbsolute;
- public Progress(boolean hideAbsolute) {
+ public Progress(final boolean hideAbsolute) {
this.hideAbsolute = hideAbsolute;
}
diff --git a/main/src/cgeo/geocaching/activity/ShowcaseViewBuilder.java b/main/src/cgeo/geocaching/activity/ShowcaseViewBuilder.java
index 04f096d..86f5302 100644
--- a/main/src/cgeo/geocaching/activity/ShowcaseViewBuilder.java
+++ b/main/src/cgeo/geocaching/activity/ShowcaseViewBuilder.java
@@ -29,7 +29,6 @@ public class ShowcaseViewBuilder extends Builder {
/**
* Use the hash of the title for the single shot remembering
*
- * @param resId
*/
private void setSingleshot(final CharSequence title) {
super.singleShot(title.hashCode());
diff --git a/main/src/cgeo/geocaching/apps/AbstractApp.java b/main/src/cgeo/geocaching/apps/AbstractApp.java
index 494e245..3bc7f71 100644
--- a/main/src/cgeo/geocaching/apps/AbstractApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractApp.java
@@ -5,28 +5,31 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.ProcessUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import android.content.Intent;
public abstract class AbstractApp implements App {
- private final String packageName;
- private final String intent;
+ @Nullable private final String packageName;
+ @Nullable private final String intent;
+ @NonNull
private final String name;
/**
* a unique id, defined in res/values/ids.xml
*/
private final int id;
- protected AbstractApp(final String name, final int id, final String intent,
- final String packageName) {
+ protected AbstractApp(@NonNull final String name, final int id, @Nullable final String intent,
+ @Nullable final String packageName) {
this.name = name;
this.id = id;
this.intent = intent;
this.packageName = packageName;
}
- protected AbstractApp(final String name, final int id, final String intent) {
+ protected AbstractApp(@NonNull final String name, final int id, @Nullable final String intent) {
this(name, id, intent, null);
}
@@ -35,9 +38,14 @@ public abstract class AbstractApp implements App {
if (StringUtils.isNotEmpty(packageName) && ProcessUtils.isLaunchable(packageName)) {
return true;
}
+ if (intent == null) {
+ return false;
+ }
+ assert intent != null; // eclipse issue
return ProcessUtils.isIntentAvailable(intent);
}
+ @Nullable
protected Intent getLaunchIntent() {
return ProcessUtils.getLaunchIntent(packageName);
}
@@ -48,6 +56,7 @@ public abstract class AbstractApp implements App {
}
@Override
+ @NonNull
public String getName() {
return name;
}
@@ -57,12 +66,12 @@ public abstract class AbstractApp implements App {
return id;
}
- protected static String getString(int ressourceId) {
+ protected static String getString(final int ressourceId) {
return CgeoApplication.getInstance().getString(ressourceId);
}
@Override
- public boolean isEnabled(Geocache cache) {
+ public boolean isEnabled(final Geocache cache) {
return cache != null;
}
}
diff --git a/main/src/cgeo/geocaching/apps/AbstractAppFactory.java b/main/src/cgeo/geocaching/apps/AbstractAppFactory.java
deleted file mode 100644
index 945f7d6..0000000
--- a/main/src/cgeo/geocaching/apps/AbstractAppFactory.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package cgeo.geocaching.apps;
-
-import android.view.MenuItem;
-
-public abstract class AbstractAppFactory {
-
- protected static App getAppFromMenuItem(MenuItem item, final App[] availableApps) {
- final int id = item.getItemId();
- for (App app : availableApps) {
- if (app.getId() == id) {
- return app;
- }
- }
- return null;
- }
-}
diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
index baf36a4..dfd148d 100644
--- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
+++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.utils.SynchronizedDateFormat;
+import menion.android.locus.LocusDataStorageProvider;
import menion.android.locus.addon.publiclib.DisplayData;
import menion.android.locus.addon.publiclib.LocusUtils;
import menion.android.locus.addon.publiclib.geoData.Point;
@@ -15,6 +16,9 @@ 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.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import android.app.Activity;
import android.location.Location;
@@ -31,7 +35,7 @@ import java.util.Locale;
public abstract class AbstractLocusApp extends AbstractApp {
private static final SynchronizedDateFormat ISO8601DATE = new SynchronizedDateFormat("yyyy-MM-dd'T'", Locale.US);
- protected AbstractLocusApp(final String text, int id, final String intent) {
+ protected AbstractLocusApp(@NonNull final String text, final int id, @NonNull final String intent) {
super(text, id, intent);
}
@@ -47,7 +51,6 @@ public abstract class AbstractLocusApp extends AbstractApp {
* which caches/waypoints to show
* @param withCacheWaypoints
* Whether to give waypoints of caches to Locus or not
- * @param activity
*/
protected static boolean showInLocus(final List<?> objectsToShow, final boolean withCacheWaypoints, final boolean export,
final Activity activity) {
@@ -57,7 +60,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
final boolean withCacheDetails = objectsToShow.size() < 200;
final PointsData pd = new PointsData("c:geo");
- for (Object o : objectsToShow) {
+ for (final Object o : objectsToShow) {
Point p = null;
// get icon and Point
if (o instanceof Geocache) {
@@ -90,7 +93,6 @@ public abstract class AbstractLocusApp extends AbstractApp {
/**
* This method constructs a <code>Point</code> for displaying in Locus
*
- * @param cache
* @param withWaypoints
* whether to give waypoints to Locus or not
* @param withCacheDetails
@@ -98,7 +100,8 @@ public abstract class AbstractLocusApp extends AbstractApp {
* should be false for all if more then 200 Caches are transferred
* @return null, when the <code>Point</code> could not be constructed
*/
- private static Point getCachePoint(Geocache cache, boolean withWaypoints, boolean withCacheDetails) {
+ @Nullable
+ private static Point getCachePoint(final Geocache cache, final boolean withWaypoints, final boolean withCacheDetails) {
if (cache == null || cache.getCoords() == null) {
return null;
}
@@ -141,19 +144,24 @@ public abstract class AbstractLocusApp extends AbstractApp {
if (withWaypoints && cache.hasWaypoints()) {
pg.waypoints = new ArrayList<>();
- for (Waypoint waypoint : cache.getWaypoints()) {
- if (waypoint == null || waypoint.getCoords() == null) {
+ for (final Waypoint waypoint : cache.getWaypoints()) {
+ if (waypoint == null) {
continue;
}
- PointGeocachingDataWaypoint wp = new PointGeocachingDataWaypoint();
- wp.code = waypoint.getGeocode();
+
+ final PointGeocachingDataWaypoint wp = new PointGeocachingDataWaypoint();
+ wp.code = waypoint.getLookup();
wp.name = waypoint.getName();
- String locusWpId = toLocusWaypoint(waypoint.getWaypointType());
+ wp.description = waypoint.getNote();
+ final String locusWpId = toLocusWaypoint(waypoint.getWaypointType());
if (locusWpId != null) {
wp.type = locusWpId;
}
- wp.lat = waypoint.getCoords().getLatitude();
- wp.lon = waypoint.getCoords().getLongitude();
+
+ if (waypoint.getCoords() != null) {
+ wp.lat = waypoint.getCoords().getLatitude();
+ wp.lon = waypoint.getCoords().getLongitude();
+ }
pg.waypoints.add(wp);
}
}
@@ -174,10 +182,10 @@ public abstract class AbstractLocusApp extends AbstractApp {
/**
* This method constructs a <code>Point</code> for displaying in Locus
*
- * @param waypoint
* @return null, when the <code>Point</code> could not be constructed
*/
- private static Point getWaypointPoint(Waypoint waypoint) {
+ @Nullable
+ private static Point getWaypointPoint(final Waypoint waypoint) {
if (waypoint == null || waypoint.getCoords() == null) {
return null;
}
@@ -248,6 +256,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
}
}
+ @Nullable
private static String toLocusWaypoint(final WaypointType wt) {
switch (wt) {
case FINAL:
@@ -268,5 +277,4 @@ public abstract class AbstractLocusApp extends AbstractApp {
return null;
}
}
-
}
diff --git a/main/src/cgeo/geocaching/apps/App.java b/main/src/cgeo/geocaching/apps/App.java
index 7e70581..1383809 100644
--- a/main/src/cgeo/geocaching/apps/App.java
+++ b/main/src/cgeo/geocaching/apps/App.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.apps;
import cgeo.geocaching.Geocache;
+import org.eclipse.jdt.annotation.NonNull;
+
public interface App {
public boolean isInstalled();
@@ -10,6 +12,7 @@ public interface App {
*/
public boolean isUsableAsDefaultNavigationApp();
+ @NonNull
public String getName();
/**
@@ -20,8 +23,6 @@ public interface App {
/**
* Whether or not the app can be used with the given cache (may depend on properties of the cache).
*
- * @param cache
- * @return
*/
boolean isEnabled(final Geocache cache);
}
diff --git a/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java b/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java
index c4f2723..4e542b8 100644
--- a/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java
@@ -4,17 +4,19 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.apps.AbstractApp;
import cgeo.geocaching.apps.cache.navi.CacheNavigationApp;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.app.Activity;
import android.content.Intent;
abstract class AbstractGeneralApp extends AbstractApp implements CacheNavigationApp {
- protected AbstractGeneralApp(final String name, final int id, final String packageName) {
+ protected AbstractGeneralApp(@NonNull final String name, final int id, @NonNull final String packageName) {
super(name, id, null, packageName);
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
final Intent intent = getLaunchIntent();
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
diff --git a/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java b/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java
index b2a2cad..cdfbceb 100644
--- a/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java
@@ -21,16 +21,16 @@ public class WhereYouGoApp extends AbstractGeneralApp {
}
@Override
- public boolean isEnabled(Geocache cache) {
+ public boolean isEnabled(final Geocache cache) {
return cache.getType() == CacheType.WHERIGO && StringUtils.isNotEmpty(getWhereIGoUrl(cache));
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getWhereIGoUrl(cache))));
}
- protected static String getWhereIGoUrl(Geocache cache) {
+ protected static String getWhereIGoUrl(final Geocache cache) {
return TextUtils.getMatch(cache.getDescription(), PATTERN_CARTRIDGE, null);
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
index ec9705c..0bf2c1c 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java
@@ -5,7 +5,9 @@ import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.apps.AbstractApp;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
+
+import org.eclipse.jdt.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
@@ -15,20 +17,20 @@ import android.content.Intent;
*/
abstract class AbstractPointNavigationApp extends AbstractApp implements CacheNavigationApp, WaypointNavigationApp, GeopointNavigationApp {
- protected AbstractPointNavigationApp(final String name, final int id, final String intent) {
+ protected AbstractPointNavigationApp(@NonNull final String name, final int id, final String intent) {
super(name, id, intent);
}
- protected AbstractPointNavigationApp(final String name, final int id, final String intent, final String packageName) {
+ protected AbstractPointNavigationApp(@NonNull final String name, final int id, final String intent, final String packageName) {
super(name, id, intent, packageName);
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
navigateWithNullCheck(activity, cache.getCoords());
}
- private void navigateWithNullCheck(Activity activity, final Geopoint coords) {
+ private void navigateWithNullCheck(final Activity activity, final Geopoint coords) {
if (coords != null) {
navigate(activity, coords);
} else {
@@ -37,17 +39,17 @@ abstract class AbstractPointNavigationApp extends AbstractApp implements CacheNa
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
navigateWithNullCheck(activity, waypoint.getCoords());
}
@Override
- public boolean isEnabled(Geocache cache) {
+ public boolean isEnabled(final Geocache cache) {
return cache.getCoords() != null;
}
@Override
- public boolean isEnabled(Waypoint waypoint) {
+ public boolean isEnabled(final Waypoint waypoint) {
return waypoint.getCoords() != null;
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractRadarApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractRadarApp.java
index 6c6ffda..00b0954 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractRadarApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractRadarApp.java
@@ -2,12 +2,15 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.app.Activity;
import android.content.Intent;
-public abstract class AbstractRadarApp extends AbstractPointNavigationApp {
+abstract class AbstractRadarApp extends AbstractPointNavigationApp {
+
+ protected static final String RADAR_EXTRA_LONGITUDE = "longitude";
+ protected static final String RADAR_EXTRA_LATITUDE = "latitude";
private final String intentAction;
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java
index a2a5803..700c8aa 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java
@@ -11,11 +11,12 @@ import cgeo.geocaching.activity.ActivityMixin;
import cgeo.geocaching.apps.AbstractApp;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.app.Activity;
abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigationApp, WaypointNavigationApp {
- protected AbstractStaticMapsApp(final String name, final int id) {
+ protected AbstractStaticMapsApp(@NonNull final String name, final int id) {
super(name, id, null);
}
@@ -29,11 +30,11 @@ abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigat
return false;
}
- protected static boolean hasStaticMap(Waypoint waypoint) {
+ protected static boolean hasStaticMap(final Waypoint waypoint) {
if (waypoint==null) {
return false;
}
- String geocode = waypoint.getGeocode();
+ final String geocode = waypoint.getGeocode();
if (StringUtils.isNotEmpty(geocode) && DataStore.isOffline(geocode, null)) {
return StaticMapsProvider.hasStaticMapForWaypoint(geocode, waypoint);
}
@@ -49,7 +50,7 @@ abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigat
}
final String geocode = StringUtils.upperCase(logable.getGeocode());
- StaticMapsActivity_.IntentBuilder_ builder = StaticMapsActivity_.intent(activity).geocode(geocode).download(download);
+ final StaticMapsActivity_.IntentBuilder_ builder = StaticMapsActivity_.intent(activity).geocode(geocode).download(download);
if (waypoint != null) {
builder.waypointId(waypoint.getId());
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AndroidWearApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AndroidWearApp.java
new file mode 100644
index 0000000..5abe2fc
--- /dev/null
+++ b/main/src/cgeo/geocaching/apps/cache/navi/AndroidWearApp.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching.apps.cache.navi;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.Intents;
+import cgeo.geocaching.R;
+import cgeo.geocaching.Waypoint;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.utils.ProcessUtils;
+
+import android.app.Activity;
+import android.content.Intent;
+
+/**
+ * For use with any Android Wear geocaching apps which can handle the intent action below.
+ */
+class AndroidWearApp extends AbstractPointNavigationApp {
+ private static final String INTENT_ACTION = "cgeo.geocaching.wear.NAVIGATE_TO";
+
+ public AndroidWearApp() {
+ super(getString(R.string.cache_menu_android_wear), R.id.cache_app_android_wear, INTENT_ACTION, null);
+ }
+
+ @Override
+ public boolean isInstalled() {
+ return ProcessUtils.isIntentAvailable(INTENT_ACTION);
+ }
+
+ @Override
+ public void navigate(final Activity activity, final Geopoint coords) {
+ navigate(activity, null, null, coords);
+ }
+
+ @Override
+ public void navigate(final Activity activity, final Geocache cache) {
+ navigate(activity, cache.getName(), cache.getGeocode(), cache.getCoords());
+ }
+
+ @Override
+ public void navigate(final Activity activity, final Waypoint waypoint) {
+ navigate(activity, waypoint.getName(), waypoint.getGeocode(), waypoint.getCoords());
+ }
+
+ private static void navigate(final Activity activity, final String destName,
+ final String destCode, final Geopoint coords) {
+ final Intent launchIntent = new Intent(INTENT_ACTION);
+ launchIntent.putExtra(Intents.EXTRA_NAME, destName)
+ .putExtra(Intents.EXTRA_GEOCODE, destCode)
+ .putExtra(Intents.EXTRA_LATITUDE, coords.getLatitude())
+ .putExtra(Intents.EXTRA_LONGITUDE, coords.getLongitude());
+ activity.startService(launchIntent);
+ }
+}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CacheNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CacheNavigationApp.java
index d47bdc0..7387e94 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/CacheNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/CacheNavigationApp.java
@@ -11,7 +11,4 @@ import android.app.Activity;
*/
public interface CacheNavigationApp extends App {
void navigate(final Activity activity, final Geocache cache);
-
- @Override
- boolean isEnabled(final Geocache cache);
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
index 03d2220..8e1e4cf 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java
@@ -4,7 +4,7 @@ import cgeo.geocaching.CompassActivity;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.app.Activity;
@@ -20,19 +20,18 @@ class CompassApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
- CompassActivity.startActivity(activity, getString(R.string.navigation_direct_navigation), getString(R.string.navigation_target), coords, null);
+ public void navigate(final Activity activity, final Geopoint coords) {
+ CompassActivity.startActivityPoint(activity, coords, getString(R.string.navigation_direct_navigation));
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
- CompassActivity.startActivity(activity, waypoint.getPrefix() + "/" + waypoint.getLookup(), waypoint.getName(), waypoint.getCoords(), null,
- waypoint.getWaypointType().getL10n());
+ public void navigate(final Activity activity, final Waypoint waypoint) {
+ CompassActivity.startActivityWaypoint(activity, waypoint);
}
@Override
- public void navigate(Activity activity, Geocache cache) {
- CompassActivity.startActivity(activity, cache);
+ public void navigate(final Activity activity, final Geocache cache) {
+ CompassActivity.startActivityCache(activity, cache);
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GeopointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GeopointNavigationApp.java
index fe4fd5d..5031dd8 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GeopointNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GeopointNavigationApp.java
@@ -1,6 +1,6 @@
package cgeo.geocaching.apps.cache.navi;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.app.Activity;
@@ -8,6 +8,6 @@ import android.app.Activity;
* interface for navigation to a coordinate. This one cannot be enabled/disabled.
*
*/
-public interface GeopointNavigationApp {
+interface GeopointNavigationApp {
void navigate(final Activity activity, final Geopoint coords);
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
index 6c184ce..c12b4ca 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java
@@ -4,9 +4,9 @@ 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.geopoint.GeopointFormatter;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.location.GeopointFormatter.Format;
import cgeo.geocaching.utils.Log;
import android.app.Activity;
@@ -25,20 +25,20 @@ class GoogleMapsApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint point) {
+ public void navigate(final Activity activity, final Geopoint point) {
navigate(activity, point, activity.getString(R.string.waypoint));
}
- private static void navigate(Activity activity, Geopoint point, String label) {
+ private static void navigate(final Activity activity, final Geopoint point, final String label) {
try {
- String latitude = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, point);
- String longitude = GeopointFormatter.format(Format.LON_DECDEGREE_RAW, point);
+ final String latitude = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, point);
+ final String longitude = GeopointFormatter.format(Format.LON_DECDEGREE_RAW, point);
final String geoLocation = "geo:" + latitude + "," + longitude;
final String query = latitude + "," + longitude + "(" + label + ")";
final String uriString = geoLocation + "?q=" + Uri.encode(query);
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(uriString)));
return;
- } catch (RuntimeException e) {
+ } catch (final RuntimeException ignored) {
// nothing
}
Log.i("GoogleMapsApp.navigate: No maps application available.");
@@ -47,12 +47,12 @@ class GoogleMapsApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
navigate(activity, cache.getCoords(), cache.getName());
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
navigate(activity, waypoint.getCoords(), waypoint.getName());
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
index 4924786..d14fca4 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java
@@ -1,17 +1,17 @@
package cgeo.geocaching.apps.cache.navi;
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.MapProviderFactory;
+import cgeo.geocaching.sensors.GeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.utils.Log;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
-public class GoogleMapsDirectionApp extends AbstractPointNavigationApp {
+class GoogleMapsDirectionApp extends AbstractPointNavigationApp {
protected GoogleMapsDirectionApp() {
super(getString(R.string.cache_menu_maps_directions), R.id.cache_app_google_maps_direction, null);
@@ -23,23 +23,15 @@ public class GoogleMapsDirectionApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
+ public void navigate(final Activity activity, final Geopoint coords) {
try {
- IGeoData geo = CgeoApplication.getInstance().currentGeo();
- final Geopoint coordsNow = geo == null ? null : geo.getCoords();
-
- if (coordsNow != null) {
- activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri
- .parse("http://maps.google.com/maps?f=d&saddr="
- + coordsNow.getLatitude() + "," + coordsNow.getLongitude() + "&daddr="
- + coords.getLatitude() + "," + coords.getLongitude())));
- } else {
- activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri
- .parse("http://maps.google.com/maps?f=d&daddr="
- + coords.getLatitude() + "," + coords.getLongitude())));
- }
-
- } catch (Exception e) {
+ final GeoData geo = Sensors.getInstance().currentGeo();
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri
+ .parse("http://maps.google.com/maps?f=d&saddr="
+ + geo.getCoords().getLatitude() + "," + geo.getCoords().getLongitude() + "&daddr="
+ + coords.getLatitude() + "," + coords.getLongitude())));
+
+ } catch (final Exception e) {
Log.i("GoogleMapsDirectionApp: application not available.", e);
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
index 902eebf..0e6e97a 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.Log;
import android.app.Activity;
@@ -12,7 +12,7 @@ abstract class GoogleNavigationApp extends AbstractPointNavigationApp {
private final String mode;
- protected GoogleNavigationApp(final int nameResourceId, final int id, final String mode) {
+ private GoogleNavigationApp(final int nameResourceId, final int id, final String mode) {
super(getString(nameResourceId), id, null);
this.mode = mode;
}
@@ -23,7 +23,7 @@ abstract class GoogleNavigationApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
+ public void navigate(final Activity activity, final Geopoint coords) {
try {
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri
.parse("google.navigation:ll=" + coords.getLatitude() + ","
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java
index 540b025..03c6dc1 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java
@@ -4,7 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.CGeoMap;
import android.app.Activity;
@@ -21,17 +21,17 @@ class InternalMap extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
+ public void navigate(final Activity activity, final Geopoint coords) {
CGeoMap.startActivityCoords(activity, coords, WaypointType.WAYPOINT, null);
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
CGeoMap.startActivityCoords(activity, waypoint.getCoords(), waypoint.getWaypointType(), waypoint.getName());
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
CGeoMap.startActivityGeoCode(activity, cache.getGeocode());
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java
index b60d78a..61445c3 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java
@@ -20,12 +20,12 @@ class LocusApp extends AbstractLocusApp implements CacheNavigationApp, WaypointN
}
@Override
- public boolean isEnabled(Waypoint waypoint) {
+ public boolean isEnabled(final Waypoint waypoint) {
return waypoint.getCoords() != null;
}
@Override
- public boolean isEnabled(Geocache cache) {
+ public boolean isEnabled(final Geocache cache) {
return cache.getCoords() != null;
}
@@ -35,12 +35,12 @@ class LocusApp extends AbstractLocusApp implements CacheNavigationApp, WaypointN
*
*/
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
showInLocus(Collections.singletonList(waypoint), true, false, activity);
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
showInLocus(Collections.singletonList(cache), true, false, activity);
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java b/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java
index ea5aebb..9403dcd 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/MapsWithMeApp.java
@@ -3,34 +3,34 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import com.mapswithme.maps.api.MapsWithMeApi;
import android.app.Activity;
-public class MapsWithMeApp extends AbstractPointNavigationApp {
+class MapsWithMeApp extends AbstractPointNavigationApp {
protected MapsWithMeApp() {
super(getString(R.string.cache_menu_mapswithme), R.id.cache_app_mapswithme, null);
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
+ public void navigate(final Activity activity, final Geopoint coords) {
navigate(activity, coords, getString(R.string.unknown));
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
navigate(activity, cache.getCoords(), cache.getName());
}
- private static void navigate(Activity activity, Geopoint coords, String label) {
+ private static void navigate(final Activity activity, final Geopoint coords, final String label) {
MapsWithMeApi.showPointOnMap(activity, coords.getLatitude(), coords.getLongitude(), label);
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
navigate(activity, waypoint.getCoords(), waypoint.getName());
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
index c00723d..32eba7e 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java
@@ -5,13 +5,12 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.apps.AbstractAppFactory;
import cgeo.geocaching.apps.App;
import cgeo.geocaching.apps.cache.WhereYouGoApp;
import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationBikeApp;
import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationDrivingApp;
import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationWalkingApp;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.settings.Settings;
import org.eclipse.jdt.annotation.Nullable;
@@ -25,7 +24,11 @@ import android.widget.ArrayAdapter;
import java.util.ArrayList;
import java.util.List;
-public final class NavigationAppFactory extends AbstractAppFactory {
+public final class NavigationAppFactory {
+
+ private NavigationAppFactory() {
+ // utility class
+ }
public enum NavigationAppsEnum {
/** The internal compass activity */
@@ -69,12 +72,16 @@ public final class NavigationAppFactory extends AbstractAppFactory {
WHERE_YOU_GO(new WhereYouGoApp(), 16, R.string.pref_navigation_menu_where_you_go),
PEBBLE(new PebbleApp(), 17, R.string.pref_navigation_menu_pebble),
+ ANDROID_WEAR(new AndroidWearApp(), 18, R.string.pref_navigation_menu_android_wear),
MAPSWITHME(new MapsWithMeApp(), 22, R.string.pref_navigation_menu_mapswithme);
NavigationAppsEnum(final App app, final int id, final int preferenceKey) {
this.app = app;
this.id = id;
this.preferenceKey = preferenceKey;
+ if (preferenceKey == 0 || preferenceKey == -1) {
+ throw new IllegalStateException("Every navigation app must have a boolean preference in the settings to be enabled/disabled.");
+ }
}
/**
@@ -109,10 +116,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
* Delegates to {@link #showNavigationMenu(Activity, cgeo.geocaching.Geocache, cgeo.geocaching.Waypoint, Geopoint, boolean, boolean)} with
* <code>showInternalMap = true</code> and <code>showDefaultNavigation = false</code>
*
- * @param activity
- * @param cache
- * @param waypoint
- * @param destination
*/
public static void showNavigationMenu(final Activity activity,
final Geocache cache, final Waypoint waypoint, final Geopoint destination) {
@@ -123,7 +126,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
* Specialized way to handle selection of navigation tool.<br />
* A dialog is created for tool selection and the selected tool is started afterwards.
*
- * @param activity
* @param cache
* may be <code>null</code>
* @param waypoint
@@ -188,9 +190,8 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Returns all installed navigation apps.
*
- * @return
*/
- public static List<NavigationAppsEnum> getInstalledNavigationApps() {
+ static List<NavigationAppsEnum> getInstalledNavigationApps() {
final List<NavigationAppsEnum> installedNavigationApps = new ArrayList<>();
for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) {
if (appEnum.app.isInstalled()) {
@@ -203,7 +204,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* @return all navigation apps, which are installed and activated in the settings
*/
- public static List<NavigationAppsEnum> getActiveNavigationApps() {
+ static List<NavigationAppsEnum> getActiveNavigationApps() {
final List<NavigationAppsEnum> activeApps = new ArrayList<>();
for (final NavigationAppsEnum appEnum : getInstalledNavigationApps()) {
if (Settings.isUseNavigationApp(appEnum)) {
@@ -216,7 +217,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Returns all installed navigation apps for default navigation.
*
- * @return
*/
public static List<NavigationAppsEnum> getInstalledDefaultNavigationApps() {
final List<NavigationAppsEnum> installedNavigationApps = new ArrayList<>();
@@ -232,10 +232,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
* Handles menu selections for menu entries created with
* {@link #showNavigationMenu(Activity, Geocache, Waypoint, Geopoint)}.
*
- * @param item
- * @param activity
- * @param cache
- * @return
*/
public static boolean onMenuItemSelected(final MenuItem item, final Activity activity, final Geocache cache) {
final App menuItem = getAppFromMenuItem(item);
@@ -278,10 +274,7 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Starts the default navigation tool if correctly set and installed or the compass app as default fallback.
*
- * @param defaultNavigation
*
- * @param activity
- * @param cache
*/
public static void startDefaultNavigationApplication(final int defaultNavigation, final Activity activity, final Geocache cache) {
if (cache == null || cache.getCoords() == null) {
@@ -302,8 +295,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Starts the default navigation tool if correctly set and installed or the compass app as default fallback.
*
- * @param activity
- * @param waypoint
*/
public static void startDefaultNavigationApplication(final int defaultNavigation, final Activity activity, final Waypoint waypoint) {
if (waypoint == null || waypoint.getCoords() == null) {
@@ -316,8 +307,6 @@ public final class NavigationAppFactory extends AbstractAppFactory {
/**
* Starts the default navigation tool if correctly set and installed or the compass app as default fallback.
*
- * @param activity
- * @param destination
*/
public static void startDefaultNavigationApplication(final int defaultNavigation, final Activity activity, final Geopoint destination) {
if (destination == null) {
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationSelectionActionProvider.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationSelectionActionProvider.java
index 82883a2..43eaee3 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationSelectionActionProvider.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationSelectionActionProvider.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.apps.App;
import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum;
+import cgeo.geocaching.ui.AbstractMenuActionProvider;
import android.app.Activity;
import android.content.Context;
@@ -12,11 +13,13 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.SubMenu;
-import android.view.View;
import java.util.List;
-public class NavigationSelectionActionProvider extends ActionProvider {
+/**
+ * Action provider listing all available navigation actions as sub menu.
+ */
+public class NavigationSelectionActionProvider extends AbstractMenuActionProvider {
private Geocache geocache;
private final Activity activity;
@@ -26,17 +29,6 @@ public class NavigationSelectionActionProvider extends ActionProvider {
activity = (Activity) context;
}
- @Override
- public boolean hasSubMenu() {
- return true;
- }
-
- @Override
- public View onCreateActionView() {
- // must return null, otherwise the menu will not work
- return null;
- }
-
public void setTarget(final Geocache cache) {
geocache = cache;
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java
index 024bf37..9954382 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.app.Activity;
import android.content.Intent;
@@ -17,7 +17,7 @@ class NavigonApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint point) {
+ public void navigate(final Activity activity, final Geopoint point) {
final Intent intent = new Intent(INTENT);
/*
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java
index 5d645f7..b3e21a3 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java
@@ -1,13 +1,15 @@
package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.app.Activity;
import android.content.Intent;
class OruxMapsApp extends AbstractPointNavigationApp {
+ private static final String ORUXMAPS_EXTRA_LONGITUDE = "longitude";
+ private static final String ORUXMAPS_EXTRA_LATITUDE = "latitude";
private static final String INTENT = "com.oruxmaps.VIEW_MAP_ONLINE";
OruxMapsApp() {
@@ -15,10 +17,10 @@ class OruxMapsApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint point) {
+ public void navigate(final Activity activity, final Geopoint point) {
final Intent intent = new Intent(INTENT);
- intent.putExtra("latitude", point.getLatitude());//latitude, wgs84 datum
- intent.putExtra("longitude", point.getLongitude());//longitude, wgs84 datum
+ intent.putExtra(ORUXMAPS_EXTRA_LATITUDE, point.getLatitude());//latitude, wgs84 datum
+ intent.putExtra(ORUXMAPS_EXTRA_LONGITUDE, point.getLongitude());//longitude, wgs84 datum
activity.startActivity(intent);
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
index ac83085..f384192 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/PebbleApp.java
@@ -1,26 +1,26 @@
-package cgeo.geocaching.apps.cache.navi;
-
-import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
-
-import android.content.Intent;
-
-/**
- * Application for communication with the Pebble watch.
- *
- */
-class PebbleApp extends AbstractRadarApp {
-
- private static final String INTENT = "com.webmajstr.pebble_gc.NAVIGATE_TO";
- private static final String PACKAGE_NAME = "com.webmajstr.pebble_gc";
-
- PebbleApp() {
- super(getString(R.string.cache_menu_pebble), R.id.cache_app_pebble, INTENT, PACKAGE_NAME);
- }
-
- @Override
- protected void addCoordinates(final Intent intent, final Geopoint coords) {
- intent.putExtra("latitude", coords.getLatitude());
- intent.putExtra("longitude", coords.getLongitude());
- }
+package cgeo.geocaching.apps.cache.navi;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.location.Geopoint;
+
+import android.content.Intent;
+
+/**
+ * Application for communication with the Pebble watch.
+ *
+ */
+class PebbleApp extends AbstractRadarApp {
+
+ private static final String INTENT = "com.webmajstr.pebble_gc.NAVIGATE_TO";
+ private static final String PACKAGE_NAME = "com.webmajstr.pebble_gc";
+
+ PebbleApp() {
+ super(getString(R.string.cache_menu_pebble), R.id.cache_app_pebble, INTENT, PACKAGE_NAME);
+ }
+
+ @Override
+ protected void addCoordinates(final Intent intent, final Geopoint coords) {
+ intent.putExtra(RADAR_EXTRA_LATITUDE, coords.getLatitude());
+ intent.putExtra(RADAR_EXTRA_LONGITUDE, coords.getLongitude());
+ }
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java
index 4dbb46c..1eefdec 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java
@@ -3,8 +3,8 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter.Format;
import android.app.Activity;
import android.content.Intent;
@@ -20,11 +20,11 @@ class RMapsApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Waypoint waypoint) {
+ public void navigate(final Activity activity, final Waypoint waypoint) {
navigate(activity, waypoint.getCoords(), waypoint.getLookup(), waypoint.getName());
}
- private static void navigate(Activity activity, Geopoint coords, String code, String name) {
+ private static void navigate(final Activity activity, final Geopoint coords, final String code, final String name) {
final ArrayList<String> locations = new ArrayList<>();
locations.add(coords.format(Format.LAT_LON_DECDEGREE_COMMA) + ";" + code + ";" + name);
final Intent intent = new Intent(INTENT);
@@ -33,12 +33,12 @@ class RMapsApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geocache cache) {
+ public void navigate(final Activity activity, final Geocache cache) {
navigate(activity, cache.getCoords(), cache.getGeocode(), cache.getName());
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
+ public void navigate(final Activity activity, final Geopoint coords) {
navigate(activity, coords, "", "");
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
index 41cf2d8..a26edc4 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import android.content.Intent;
@@ -16,8 +16,8 @@ class RadarApp extends AbstractRadarApp {
@Override
protected void addCoordinates(final Intent intent, final Geopoint coords) {
- intent.putExtra("latitude", (float) coords.getLatitude());
- intent.putExtra("longitude", (float) coords.getLongitude());
+ intent.putExtra(RADAR_EXTRA_LATITUDE, (float) coords.getLatitude());
+ intent.putExtra(RADAR_EXTRA_LONGITUDE, (float) coords.getLongitude());
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
index 7294a40..ca3aefe 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.ProcessUtils;
import android.app.Activity;
@@ -26,11 +26,11 @@ class StreetviewApp extends AbstractPointNavigationApp {
}
@Override
- public void navigate(Activity activity, Geopoint point) {
+ public void navigate(final Activity activity, final Geopoint point) {
try {
activity.startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse("google.streetview:cbll=" + point.getLatitude() + "," + point.getLongitude())));
- } catch (final ActivityNotFoundException e) {
+ } catch (final ActivityNotFoundException ignored) {
ActivityMixin.showToast(activity, CgeoApplication.getInstance().getString(R.string.err_application_no));
}
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java
index 76b7f0e..391fa90 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java
@@ -1,7 +1,8 @@
package cgeo.geocaching.apps.cache.navi;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.utils.ProcessUtils;
import android.app.Activity;
import android.content.Intent;
@@ -12,17 +13,26 @@ import android.net.Uri;
* handler
*
*/
-public class SygicNavigationApp extends AbstractPointNavigationApp {
+class SygicNavigationApp extends AbstractPointNavigationApp {
- private static final String PACKAGE = "com.sygic.aura";
+ private static final String PACKAGE_NORMAL = "com.sygic.aura";
+ /**
+ * there is a secondary edition of this app
+ */
+ private static final String PACKAGE_VOUCHER = "com.sygic.aura_voucher";
SygicNavigationApp() {
- super(getString(R.string.cache_menu_sygic), R.id.cache_app_sygic, null, PACKAGE);
+ super(getString(R.string.cache_menu_sygic), R.id.cache_app_sygic, null, PACKAGE_NORMAL);
}
@Override
- public void navigate(Activity activity, Geopoint coords) {
- String str = "http://com.sygic.aura/coordinate|" + coords.getLongitude() + "|" + coords.getLatitude() + "|show";
+ public boolean isInstalled() {
+ return ProcessUtils.isLaunchable(PACKAGE_NORMAL) || ProcessUtils.isLaunchable(PACKAGE_VOUCHER);
+ }
+
+ @Override
+ public void navigate(final Activity activity, final Geopoint coords) {
+ final String str = "http://com.sygic.aura/coordinate|" + coords.getLongitude() + "|" + coords.getLatitude() + "|show";
activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(str)));
}
diff --git a/main/src/cgeo/geocaching/apps/cache/navi/WaypointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/WaypointNavigationApp.java
index c26ec3e..ba85a1d 100644
--- a/main/src/cgeo/geocaching/apps/cache/navi/WaypointNavigationApp.java
+++ b/main/src/cgeo/geocaching/apps/cache/navi/WaypointNavigationApp.java
@@ -8,7 +8,7 @@ import android.app.Activity;
* interface for navigation to a waypoint
*
*/
-public interface WaypointNavigationApp {
+interface WaypointNavigationApp {
void navigate(final Activity activity, final Waypoint waypoint);
boolean isEnabled(final Waypoint waypoint);
diff --git a/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java
index 6411758..d047d1a 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java
@@ -14,9 +14,9 @@ import java.util.List;
abstract class AbstractLocusCacheListApp extends AbstractLocusApp implements CacheListApp {
- private boolean export;
+ private final boolean export;
- public AbstractLocusCacheListApp(final int id, boolean export) {
+ public AbstractLocusCacheListApp(final int id, final boolean export) {
super(getString(export ? R.string.caches_map_locus_export : R.string.caches_map_locus), id, Intent.ACTION_VIEW);
this.export = export;
}
@@ -27,7 +27,7 @@ abstract class AbstractLocusCacheListApp extends AbstractLocusApp implements Cac
* @see AbstractLocusApp#showInLocus
*/
@Override
- public boolean invoke(List<Geocache> cacheList, Activity activity, final SearchResult search) {
+ public boolean invoke(final List<Geocache> cacheList, final Activity activity, final SearchResult search) {
if (CollectionUtils.isEmpty(cacheList)) {
return false;
}
diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
index 40c4d92..8beb5e4 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApp.java
@@ -8,7 +8,7 @@ import android.app.Activity;
import java.util.List;
-interface CacheListApp extends App {
+public interface CacheListApp extends App {
boolean invoke(final List<Geocache> caches,
final Activity activity, final SearchResult search);
diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java
deleted file mode 100644
index 5886168..0000000
--- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package cgeo.geocaching.apps.cachelist;
-
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.R;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.apps.AbstractAppFactory;
-import cgeo.geocaching.utils.Log;
-
-import android.app.Activity;
-import android.content.res.Resources;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public final class CacheListAppFactory extends AbstractAppFactory {
- private static class LazyHolder {
- public static final CacheListApp[] apps = {
- new InternalCacheListMap(),
- new LocusShowCacheListApp(),
- new LocusExportCacheListApp(),
- new MapsWithMeCacheListApp()
- };
- }
-
- /**
- * @param menu
- * @param activity
- * @param res
- */
- public static void addMenuItems(final Menu menu, final Activity activity, final Resources res) {
- final List<CacheListApp> activeApps = getActiveApps();
- if (activeApps.isEmpty()) {
- return;
- }
- if (activeApps.size() == 1) {
- final MenuItem subItem = menu.findItem(R.id.menu_cache_list_app);
- subItem.setVisible(true);
- subItem.setTitle(activeApps.get(0).getName());
- } else {
- final MenuItem subItem = menu.findItem(R.id.submenu_cache_list_app);
- subItem.setVisible(true);
- final SubMenu subMenu = subItem.getSubMenu();
- for (final CacheListApp app : activeApps) {
- subMenu.add(0, app.getId(), 0, app.getName());
- }
- }
- }
-
- private static List<CacheListApp> getActiveApps() {
- final List<CacheListApp> activeApps = new ArrayList<>(LazyHolder.apps.length);
- for (final CacheListApp app : LazyHolder.apps) {
- if (app.isInstalled()) {
- activeApps.add(app);
- }
- }
- return activeApps;
- }
-
- public static boolean onMenuItemSelected(final MenuItem item, final List<Geocache> caches, final Activity activity,
- final SearchResult search) {
- CacheListApp app;
- if (item.getItemId() == R.id.menu_cache_list_app) {
- app = getActiveApps().get(0);
- }
- else {
- app = (CacheListApp) getAppFromMenuItem(item, LazyHolder.apps);
- }
- if (app != null) {
- try {
- boolean result = app.invoke(caches, activity, search);
- ActivityMixin.invalidateOptionsMenu(activity);
- return result;
- } catch (Exception e) {
- Log.e("CacheListAppFactory.onMenuItemSelected", e);
- }
- }
- return false;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListApps.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListApps.java
new file mode 100644
index 0000000..e8e81a8
--- /dev/null
+++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListApps.java
@@ -0,0 +1,29 @@
+package cgeo.geocaching.apps.cachelist;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public enum CacheListApps {
+ INTERNAL(new InternalCacheListMap()),
+ LOCUS_SHOW(new LocusShowCacheListApp()),
+ LOCUS_EXPORT(new LocusExportCacheListApp()),
+ MAPS_ME(new MapsWithMeCacheListApp());
+
+ private final CacheListApp app;
+
+ private CacheListApps(final CacheListApp app) {
+ this.app = app;
+ }
+
+ public static List<CacheListApp> getActiveApps() {
+ final List<CacheListApp> activeApps = new ArrayList<>();
+ for (final CacheListApps appEnum : values()) {
+ if (appEnum.app.isInstalled()) {
+ activeApps.add(appEnum.app);
+ }
+ }
+ return activeApps;
+ }
+
+}
+
diff --git a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java
index 9216bc0..d364cda 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java
@@ -22,7 +22,7 @@ class InternalCacheListMap extends AbstractApp implements CacheListApp {
}
@Override
- public boolean invoke(List<Geocache> caches, Activity activity, final SearchResult search) {
+ public boolean invoke(final List<Geocache> caches, final Activity activity, final SearchResult search) {
CGeoMap.startActivitySearch(activity, search, null);
return true;
}
diff --git a/main/src/cgeo/geocaching/apps/cachelist/ListNavigationSelectionActionProvider.java b/main/src/cgeo/geocaching/apps/cachelist/ListNavigationSelectionActionProvider.java
new file mode 100644
index 0000000..6a49995
--- /dev/null
+++ b/main/src/cgeo/geocaching/apps/cachelist/ListNavigationSelectionActionProvider.java
@@ -0,0 +1,60 @@
+package cgeo.geocaching.apps.cachelist;
+
+import cgeo.geocaching.ui.AbstractMenuActionProvider;
+
+import android.content.Context;
+import android.support.v4.view.ActionProvider;
+import android.support.v4.view.MenuItemCompat;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.SubMenu;
+
+import java.util.List;
+
+public class ListNavigationSelectionActionProvider extends AbstractMenuActionProvider {
+
+ public static interface Callback {
+ void onListNavigationSelected(final CacheListApp app);
+ }
+
+ private Callback callback;
+
+ public ListNavigationSelectionActionProvider(final Context context) {
+ super(context);
+ }
+
+ public void setCallback(final Callback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void onPrepareSubMenu(final SubMenu subMenu) {
+ subMenu.clear();
+ if (callback == null) {
+ return;
+ }
+ final List<CacheListApp> activeApps = CacheListApps.getActiveApps();
+ for (int i = 0; i < activeApps.size(); i++) {
+ final CacheListApp app = activeApps.get(i);
+ subMenu.add(Menu.NONE, i, Menu.NONE, app.getName()).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+
+ @Override
+ public boolean onMenuItemClick(final MenuItem item) {
+ final CacheListApp app = activeApps.get(item.getItemId());
+ callback.onListNavigationSelected(app);
+ return true;
+ }
+ });
+ }
+ }
+
+ public static void initialize(final MenuItem menuItem, final Callback callback) {
+ final ActionProvider actionProvider = MenuItemCompat.getActionProvider(menuItem);
+ if (actionProvider instanceof ListNavigationSelectionActionProvider) {
+ final ListNavigationSelectionActionProvider navigateAction = (ListNavigationSelectionActionProvider) actionProvider;
+ navigateAction.setCallback(callback);
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java
index ba177f0..ed64d2d 100644
--- a/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java
+++ b/main/src/cgeo/geocaching/apps/cachelist/MapsWithMeCacheListApp.java
@@ -26,10 +26,10 @@ public class MapsWithMeCacheListApp extends AbstractApp implements CacheListApp
}
@Override
- public boolean invoke(List<Geocache> caches, Activity activity, SearchResult search) {
+ public boolean invoke(final List<Geocache> caches, final Activity activity, final SearchResult search) {
final MWMPoint[] points = new MWMPoint[caches.size()];
for (int i = 0; i < points.length; i++) {
- Geocache geocache = caches.get(i);
+ final Geocache geocache = caches.get(i);
points[i] = new MWMPoint(geocache.getCoords().getLatitude(), geocache.getCoords().getLongitude(), geocache.getName(), geocache.getGeocode());
}
MapsWithMeApi.showPointsOnMap(activity, null, getPendingIntent(activity), points);
@@ -44,22 +44,19 @@ public class MapsWithMeCacheListApp extends AbstractApp implements CacheListApp
/**
* get cache code from a PendingIntent after an invocation of MapsWithMe
- *
- * @return
+ *
*/
@Nullable
public static String getCacheFromMapsWithMe(final Context context, final Intent intent) {
final MWMResponse mwmResponse = MWMResponse.extractFromIntent(context, intent);
- if (mwmResponse != null) {
- final MWMPoint point = mwmResponse.getPoint();
- if (point != null) {
- return point.getId();
- }
+ final MWMPoint point = mwmResponse.getPoint();
+ if (point != null) {
+ return point.getId();
}
return null;
}
- private static PendingIntent getPendingIntent(Context context) {
+ private static PendingIntent getPendingIntent(final Context context) {
final Intent intent = new Intent(context, CacheDetailActivity.class);
return PendingIntent.getActivity(context, 0, intent, 0);
}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel11.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel11.java
new file mode 100644
index 0000000..8398eb3
--- /dev/null
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel11.java
@@ -0,0 +1,15 @@
+package cgeo.geocaching.compatibility;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.widget.TextView;
+
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+public class AndroidLevel11 implements AndroidLevel11Interface {
+
+ @Override
+ public void setTextIsSelectable(final TextView textView, final boolean selectable) {
+ textView.setTextIsSelectable(selectable);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java
new file mode 100644
index 0000000..b4111ab
--- /dev/null
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Emulation.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.compatibility;
+
+import android.widget.TextView;
+
+public class AndroidLevel11Emulation implements AndroidLevel11Interface {
+
+ @Override
+ public void setTextIsSelectable(final TextView textView, final boolean selectable) {
+ // do nothing
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel11Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Interface.java
new file mode 100644
index 0000000..45c06a4
--- /dev/null
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel11Interface.java
@@ -0,0 +1,9 @@
+package cgeo.geocaching.compatibility;
+
+import android.widget.TextView;
+
+public interface AndroidLevel11Interface {
+
+ void setTextIsSelectable(TextView textView, boolean selectable);
+
+}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java
index eb2be4b..f599611 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13.java
@@ -8,16 +8,11 @@ import android.graphics.Point;
import android.view.WindowManager;
@TargetApi(value = 13)
-public class AndroidLevel13 implements AndroidLevel13Interface {
-
- @Override
- public int getDisplayWidth() {
- return getDisplaySize().x;
- }
+class AndroidLevel13 implements AndroidLevel13Interface {
@Override
public Point getDisplaySize() {
- Point dimensions = new Point();
+ final Point dimensions = new Point();
((WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getSize(dimensions);
return dimensions;
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java
index 56c784f..f9fd3bc 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Emulation.java
@@ -8,12 +8,7 @@ import android.view.Display;
import android.view.WindowManager;
@SuppressWarnings("deprecation")
-public class AndroidLevel13Emulation implements AndroidLevel13Interface {
-
- @Override
- public int getDisplayWidth() {
- return getDisplay().getWidth();
- }
+class AndroidLevel13Emulation implements AndroidLevel13Interface {
@Override
public Point getDisplaySize() {
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java
index 8483e38..b78875f 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel13Interface.java
@@ -2,8 +2,7 @@ package cgeo.geocaching.compatibility;
import android.graphics.Point;
-public interface AndroidLevel13Interface {
- int getDisplayWidth();
+interface AndroidLevel13Interface {
Point getDisplaySize();
}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java
index ed4849f..6b15a00 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19.java
@@ -5,12 +5,12 @@ import android.app.Activity;
import android.content.Intent;
@TargetApi(19)
-public class AndroidLevel19 implements AndroidLevel19Interface {
+class AndroidLevel19 implements AndroidLevel19Interface {
@Override
public void importGpxFromStorageAccessFramework(final Activity activity, final int requestCode) {
// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file browser.
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// Filter to only show results that can be "opened", such as a file (as opposed to a list
// of contacts or timezones)
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java
index 99f140f..7404c82 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Emulation.java
@@ -2,10 +2,10 @@ package cgeo.geocaching.compatibility;
import android.app.Activity;
-public class AndroidLevel19Emulation implements AndroidLevel19Interface {
+class AndroidLevel19Emulation implements AndroidLevel19Interface {
@Override
- public void importGpxFromStorageAccessFramework(Activity activity, int requestCode) {
+ public void importGpxFromStorageAccessFramework(final Activity activity, final int requestCode) {
// do nothing
}
diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java
index 9a27cd8..de397a6 100644
--- a/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java
+++ b/main/src/cgeo/geocaching/compatibility/AndroidLevel19Interface.java
@@ -2,6 +2,6 @@ package cgeo.geocaching.compatibility;
import android.app.Activity;
-public interface AndroidLevel19Interface {
+interface AndroidLevel19Interface {
void importGpxFromStorageAccessFramework(Activity activity, final int requestCode);
}
diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java
index 54e2966..56e18bf 100644
--- a/main/src/cgeo/geocaching/compatibility/Compatibility.java
+++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java
@@ -5,15 +5,18 @@ import org.eclipse.jdt.annotation.NonNull;
import android.app.Activity;
import android.graphics.Point;
import android.os.Build;
+import android.widget.TextView;
public final class Compatibility {
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
+ private static final AndroidLevel11Interface LEVEL_11;
private static final AndroidLevel13Interface LEVEL_13;
private static final AndroidLevel19Interface LEVEL_19;
static {
+ LEVEL_11 = SDK_VERSION >= 11 ? new AndroidLevel11() : new AndroidLevel11Emulation();
LEVEL_13 = SDK_VERSION >= 13 ? new AndroidLevel13() : new AndroidLevel13Emulation();
LEVEL_19 = SDK_VERSION >= 19 ? new AndroidLevel19() : new AndroidLevel19Emulation();
}
@@ -22,19 +25,19 @@ public final class Compatibility {
// utility class
}
- public static int getDisplayWidth() {
- return LEVEL_13.getDisplayWidth();
- }
-
public static Point getDisplaySize() {
return LEVEL_13.getDisplaySize();
}
- public static void importGpxFromStorageAccessFramework(final @NonNull Activity activity, int requestCodeImportGpx) {
+ public static void importGpxFromStorageAccessFramework(final @NonNull Activity activity, final int requestCodeImportGpx) {
LEVEL_19.importGpxFromStorageAccessFramework(activity, requestCodeImportGpx);
}
public static boolean isStorageAccessFrameworkAvailable() {
return SDK_VERSION >= 19;
}
+
+ public static void setTextIsSelectable(final TextView textView, final boolean selectable) {
+ LEVEL_11.setTextIsSelectable(textView, selectable);
+ }
}
diff --git a/main/src/cgeo/geocaching/concurrent/BlockingThreadPool.java b/main/src/cgeo/geocaching/concurrent/BlockingThreadPool.java
deleted file mode 100644
index a6d7e9b..0000000
--- a/main/src/cgeo/geocaching/concurrent/BlockingThreadPool.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package cgeo.geocaching.concurrent;
-
-
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * BlockingThreadPool restricts the amount of parallel threads executing Runnables.
- */
-public class BlockingThreadPool {
- /** The queue holding the Runnable. **/
- private BlockingQueue<Runnable> queue = null;
- /** The Executor. **/
- private ThreadPoolExecutor executor;
-
- /**
- * Creates a ThreadPool with a given maximum of parallel threads running.
- * Idle threads will be stopped until new threads are added.
- *
- * @param poolSize
- * Maximum amout of parallel Threads
- * @param priority
- * The Thread priority e.g. Thread.MIN_PRIORITY
- */
- public BlockingThreadPool(int poolSize, int priority) {
- ThreadFactory threadFactory = new PriorityThreadFactory(priority);
- this.queue = new ArrayBlockingQueue<>(poolSize, true);
- this.executor = new ThreadPoolExecutor(0, poolSize, 5, TimeUnit.SECONDS, this.queue);
- this.executor.setThreadFactory(threadFactory);
- }
-
- /**
- * Add a runnable to the pool. This will start the core threads in the underlying
- * executor and try to add the Runnable to the pool. This method waits until timeout
- * if no free thread is available.
- *
- * @param task
- * The Runnable to add to the pool
- * @param timeout
- * The timeout to wait for a free thread
- * @param unit
- * The timeout unit
- * @return true/false successful added
- * @throws InterruptedException
- * Operation was interrupted
- */
- public boolean add(Runnable task, int timeout, TimeUnit unit) throws InterruptedException {
- this.executor.setCorePoolSize(this.executor.getMaximumPoolSize());
- this.executor.prestartAllCoreThreads();
- boolean successfull = this.queue.offer(task, timeout, unit);
- this.executor.setCorePoolSize(0);
- return successfull;
- }
-}
diff --git a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java b/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
deleted file mode 100644
index 0da198b..0000000
--- a/main/src/cgeo/geocaching/concurrent/PriorityThreadFactory.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package cgeo.geocaching.concurrent;
-
-import org.eclipse.jdt.annotation.NonNull;
-
-import java.util.concurrent.ThreadFactory;
-
-/**
- * Helper class for setting Thread priority in ThreadPool.
- */
-public class PriorityThreadFactory implements ThreadFactory {
- private int priority;
-
- public PriorityThreadFactory(int priority) {
- this.priority = priority;
- }
-
- @NonNull
- @Override
- public Thread newThread(Runnable r) {
- Thread result = new Thread(r);
- result.setPriority(this.priority);
- return result;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 9729e06..0583aa1 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -15,10 +15,12 @@ import cgeo.geocaching.connector.capability.ISearchByOwner;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import rx.functions.Action1;
import java.util.ArrayList;
@@ -38,12 +40,12 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public boolean addToWatchlist(Geocache cache) {
+ public boolean addToWatchlist(@NonNull final Geocache cache) {
return false;
}
@Override
- public boolean removeFromWatchlist(Geocache cache) {
+ public boolean removeFromWatchlist(@NonNull final Geocache cache) {
return false;
}
@@ -53,7 +55,7 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public boolean uploadPersonalNote(Geocache cache) {
+ public boolean uploadPersonalNote(@NonNull final Geocache cache) {
throw new UnsupportedOperationException();
}
@@ -63,7 +65,7 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt) {
+ public boolean uploadModifiedCoordinates(@NonNull final Geocache cache, @NonNull final Geopoint wpt) {
throw new UnsupportedOperationException();
}
@@ -71,12 +73,12 @@ public abstract class AbstractConnector implements IConnector {
* {@link IConnector}
*/
@Override
- public boolean deleteModifiedCoordinates(Geocache cache) {
+ public boolean deleteModifiedCoordinates(@NonNull final Geocache cache) {
throw new UnsupportedOperationException();
}
@Override
- public boolean supportsFavoritePoints(final Geocache cache) {
+ public boolean supportsFavoritePoints(@NonNull final Geocache cache) {
return false;
}
@@ -91,46 +93,48 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public boolean canLog(Geocache cache) {
+ public boolean canLog(@NonNull final Geocache cache) {
return false;
}
@Override
- public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ @NonNull
+ public ILoggingManager getLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final Geocache cache) {
return new NoLoggingManager();
}
@Override
+ @NonNull
public String getLicenseText(final @NonNull Geocache cache) {
- return null;
+ return StringUtils.EMPTY;
}
- protected static boolean isNumericId(final String string) {
+ protected static boolean isNumericId(final String str) {
try {
- return Integer.parseInt(string) > 0;
- } catch (NumberFormatException e) {
+ return Integer.parseInt(str) > 0;
+ } catch (final NumberFormatException ignored) {
}
return false;
}
@Override
- public boolean isZippedGPXFile(String fileName) {
+ public boolean isZippedGPXFile(@NonNull final String fileName) {
// don't accept any file by default
return false;
}
@Override
- public boolean isReliableLatLon(boolean cacheHasReliableLatLon) {
+ public boolean isReliableLatLon(final boolean cacheHasReliableLatLon) {
// let every cache have reliable coordinates by default
return true;
}
@Override
- public String getGeocodeFromUrl(final String url) {
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
final String urlPrefix = getCacheUrlPrefix();
- if (StringUtils.startsWith(url, urlPrefix)) {
- @NonNull
- String geocode = url.substring(urlPrefix.length());
+ if (StringUtils.isEmpty(urlPrefix) || StringUtils.startsWith(url, urlPrefix)) {
+ @NonNull final String geocode = url.substring(urlPrefix.length());
if (canHandle(geocode)) {
return geocode;
}
@@ -138,9 +142,11 @@ public abstract class AbstractConnector implements IConnector {
return null;
}
+ @NonNull
abstract protected String getCacheUrlPrefix();
@Override
+ @Nullable
public String getLongCacheUrl(final @NonNull Geocache cache) {
return getCacheUrl(cache);
}
@@ -151,7 +157,7 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public int getCacheMapMarkerId(boolean disabled) {
+ public int getCacheMapMarkerId(final boolean disabled) {
if (disabled) {
return R.drawable.marker_disabled_other;
}
@@ -159,7 +165,8 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public List<LogType> getPossibleLogTypes(Geocache geocache) {
+ @NonNull
+ public List<LogType> getPossibleLogTypes(@NonNull final Geocache geocache) {
final List<LogType> logTypes = new ArrayList<>();
if (geocache.isEventCache()) {
logTypes.add(LogType.WILL_ATTEND);
@@ -196,13 +203,14 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
- public String getWaypointGpxId(String prefix, String geocode) {
+ public String getWaypointGpxId(final String prefix, @NonNull final String geocode) {
// Default: just return the prefix
return prefix;
}
@Override
- public String getWaypointPrefix(String name) {
+ @NonNull
+ public String getWaypointPrefix(final String name) {
// Default: just return the name
return name;
}
@@ -213,8 +221,9 @@ public abstract class AbstractConnector implements IConnector {
}
@Override
+ @NonNull
public final Collection<String> getCapabilities() {
- ArrayList<String> list = new ArrayList<>();
+ final ArrayList<String> list = new ArrayList<>();
addCapability(list, ISearchByViewPort.class, R.string.feature_search_live_map);
addCapability(list, ISearchByKeyword.class, R.string.feature_search_keyword);
addCapability(list, ISearchByCenter.class, R.string.feature_search_center);
@@ -245,20 +254,20 @@ public abstract class AbstractConnector implements IConnector {
}
}
- private static String feature(int featureResourceId) {
+ private static String feature(final int featureResourceId) {
return CgeoApplication.getInstance().getString(featureResourceId);
}
@Override
public @NonNull
List<UserAction> getUserActions() {
- List<UserAction> actions = getDefaultUserActions();
+ final List<UserAction> actions = getDefaultUserActions();
if (this instanceof ISearchByOwner) {
actions.add(new UserAction(R.string.user_menu_view_hidden, new Action1<Context>() {
@Override
- public void call(Context context) {
+ public void call(final Context context) {
CacheListActivity.startActivityOwner(context.activity, context.userName);
}
}));
@@ -268,7 +277,7 @@ public abstract class AbstractConnector implements IConnector {
actions.add(new UserAction(R.string.user_menu_view_found, new Action1<UserAction.Context>() {
@Override
- public void call(Context context) {
+ public void call(final Context context) {
CacheListActivity.startActivityFinder(context.activity, context.userName);
}
}));
@@ -286,7 +295,7 @@ public abstract class AbstractConnector implements IConnector {
actions.add(new UserAction(R.string.user_menu_open_contact, new Action1<UserAction.Context>() {
@Override
- public void call(Context context) {
+ public void call(final Context context) {
ContactsAddon.openContactCard(context.activity, context.userName);
}
}));
@@ -295,4 +304,6 @@ public abstract class AbstractConnector implements IConnector {
return actions;
}
+ public void logout() {
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java b/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java
index 9e702c4..e53fcf1 100644
--- a/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/AbstractLoggingManager.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.connector;
import cgeo.geocaching.TrackableLog;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.Collections;
import java.util.List;
@@ -13,6 +15,7 @@ public abstract class AbstractLoggingManager implements ILoggingManager {
}
@Override
+ @NonNull
public List<TrackableLog> getTrackables() {
return Collections.emptyList();
}
diff --git a/main/src/cgeo/geocaching/connector/AbstractLogin.java b/main/src/cgeo/geocaching/connector/AbstractLogin.java
index 6527685..252daeb 100644
--- a/main/src/cgeo/geocaching/connector/AbstractLogin.java
+++ b/main/src/cgeo/geocaching/connector/AbstractLogin.java
@@ -4,9 +4,11 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.network.Network;
import cgeo.geocaching.settings.Settings;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
public abstract class AbstractLogin {
@@ -38,7 +40,7 @@ public abstract class AbstractLogin {
return actualLoginStatus;
}
- protected void setActualLoginStatus(boolean loginStatus) {
+ protected void setActualLoginStatus(final boolean loginStatus) {
actualLoginStatus = loginStatus;
}
@@ -46,7 +48,7 @@ public abstract class AbstractLogin {
return actualUserName;
}
- protected void setActualUserName(String userName) {
+ protected void setActualUserName(final String userName) {
actualUserName = userName;
}
@@ -68,10 +70,15 @@ public abstract class AbstractLogin {
setActualStatus(CgeoApplication.getInstance().getString(R.string.err_login));
}
+ @NonNull
public StatusCode login() {
+ if (!Network.isNetworkConnected()) {
+ return StatusCode.COMMUNICATION_ERROR;
+ }
return login(true);
}
+ @NonNull
protected abstract StatusCode login(boolean retry);
}
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index e6ef829..918911a 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -1,6 +1,6 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.ICache;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Trackable;
@@ -15,13 +15,15 @@ import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.oc.OCApiConnector.ApiSupport;
import cgeo.geocaching.connector.oc.OCApiLiveConnector;
+import cgeo.geocaching.connector.oc.OCCZConnector;
import cgeo.geocaching.connector.oc.OCConnector;
import cgeo.geocaching.connector.ox.OXConnector;
import cgeo.geocaching.connector.trackable.GeokretyConnector;
+import cgeo.geocaching.connector.trackable.SwaggieConnector;
import cgeo.geocaching.connector.trackable.TrackableConnector;
import cgeo.geocaching.connector.trackable.TravelBugConnector;
import cgeo.geocaching.connector.trackable.UnknownTrackableConnector;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Viewport;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
@@ -36,14 +38,14 @@ import java.util.Collections;
import java.util.List;
public final class ConnectorFactory {
- private static final @NonNull UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
- private static final Collection<IConnector> CONNECTORS = Collections.unmodifiableCollection(Arrays.asList(new IConnector[] {
+ @NonNull private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
+ @NonNull private static final Collection<IConnector> CONNECTORS = Collections.unmodifiableCollection(Arrays.asList(new IConnector[] {
GCConnector.getInstance(),
ECConnector.getInstance(),
new OCApiLiveConnector("opencaching.de", "www.opencaching.de", "OC", "CC BY-NC-ND, alle Logeinträge © jeweiliger Autor",
R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret,
R.string.pref_connectorOCActive, R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret, ApiSupport.current),
- new OCConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"),
+ new OCCZConnector(),
new OCApiLiveConnector("opencaching.org.uk", "www.opencaching.org.uk", "OK", "CC BY-NC-SA 2.5",
R.string.oc_uk_okapi_consumer_key, R.string.oc_uk_okapi_consumer_secret,
R.string.pref_connectorOCUKActive, R.string.pref_ocuk_tokenpublic, R.string.pref_ocuk_tokensecret, ApiSupport.oldapi),
@@ -71,22 +73,31 @@ public final class ConnectorFactory {
}));
@NonNull public static final UnknownTrackableConnector UNKNOWN_TRACKABLE_CONNECTOR = new UnknownTrackableConnector();
+
+ @NonNull
private static final Collection<TrackableConnector> TRACKABLE_CONNECTORS = Collections.unmodifiableCollection(Arrays.asList(new TrackableConnector[] {
- new GeokretyConnector(), // GK must be first, as it overlaps with the secret codes of travel bugs
- TravelBugConnector.getInstance(),
+ new GeokretyConnector(),
+ new SwaggieConnector(),
+ TravelBugConnector.getInstance(), // travel bugs last, as their secret codes overlap with other connectors
UNKNOWN_TRACKABLE_CONNECTOR // must be last
}));
+ @NonNull
private static final Collection<ISearchByViewPort> searchByViewPortConns = getMatchingConnectors(ISearchByViewPort.class);
+ @NonNull
private static final Collection<ISearchByCenter> searchByCenterConns = getMatchingConnectors(ISearchByCenter.class);
+ @NonNull
private static final Collection<ISearchByKeyword> searchByKeywordConns = getMatchingConnectors(ISearchByKeyword.class);
+ @NonNull
private static final Collection<ISearchByOwner> SEARCH_BY_OWNER_CONNECTORS = getMatchingConnectors(ISearchByOwner.class);
+ @NonNull
private static final Collection<ISearchByFinder> SEARCH_BY_FINDER_CONNECTORS = getMatchingConnectors(ISearchByFinder.class);
+ @NonNull
@SuppressWarnings("unchecked")
private static <T extends IConnector> Collection<T> getMatchingConnectors(final Class<T> clazz) {
final List<T> matching = new ArrayList<>();
@@ -98,26 +109,32 @@ public final class ConnectorFactory {
return Collections.unmodifiableCollection(matching);
}
+ @NonNull
public static Collection<IConnector> getConnectors() {
return CONNECTORS;
}
+ @NonNull
public static Collection<ISearchByCenter> getSearchByCenterConnectors() {
return searchByCenterConns;
}
+ @NonNull
public static Collection<ISearchByKeyword> getSearchByKeywordConnectors() {
return searchByKeywordConns;
}
+ @NonNull
public static Collection<ISearchByOwner> getSearchByOwnerConnectors() {
return SEARCH_BY_OWNER_CONNECTORS;
}
+ @NonNull
public static Collection<ISearchByFinder> getSearchByFinderConnectors() {
return SEARCH_BY_FINDER_CONNECTORS;
}
+ @NonNull
public static ILogin[] getActiveLiveConnectors() {
final List<ILogin> liveConns = new ArrayList<>();
for (final IConnector conn : CONNECTORS) {
@@ -143,11 +160,12 @@ public final class ConnectorFactory {
return false;
}
- public static @NonNull
- IConnector getConnector(final ICache cache) {
+ @NonNull
+ public static IConnector getConnector(final Geocache cache) {
return getConnector(cache.getGeocode());
}
+ @NonNull
public static TrackableConnector getConnector(final Trackable trackable) {
return getTrackableConnector(trackable.getGeocode());
}
@@ -162,8 +180,8 @@ public final class ConnectorFactory {
return UNKNOWN_TRACKABLE_CONNECTOR; // avoid null checks by returning a non implementing connector
}
- public static @NonNull
- IConnector getConnector(final String geocodeInput) {
+ @NonNull
+ public static IConnector getConnector(final String geocodeInput) {
// this may come from user input
final String geocode = StringUtils.trim(geocodeInput);
if (geocode == null) {
@@ -186,7 +204,8 @@ public final class ConnectorFactory {
}
/** @see ISearchByViewPort#searchByViewport */
- public static SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
+ @NonNull
+ public static SearchResult searchByViewport(final @NonNull Viewport viewport, @NonNull final MapTokens tokens) {
return SearchResult.parallelCombineActive(searchByViewPortConns, new Func1<ISearchByViewPort, SearchResult>() {
@Override
public SearchResult call(final ISearchByViewPort connector) {
@@ -195,9 +214,13 @@ public final class ConnectorFactory {
});
}
- public static String getGeocodeFromURL(final String url) {
+ @Nullable
+ public static String getGeocodeFromURL(@Nullable final String url) {
+ if (url == null) {
+ return null;
+ }
for (final IConnector connector : CONNECTORS) {
- final String geocode = connector.getGeocodeFromUrl(url);
+ @Nullable final String geocode = connector.getGeocodeFromUrl(url);
if (StringUtils.isNotBlank(geocode)) {
return geocode;
}
@@ -205,6 +228,7 @@ public final class ConnectorFactory {
return null;
}
+ @NonNull
public static Collection<TrackableConnector> getTrackableConnectors() {
return TRACKABLE_CONNECTORS;
}
@@ -212,9 +236,9 @@ public final class ConnectorFactory {
/**
* Get the geocode of a trackable from a URL.
*
- * @param url
* @return {@code null} if the URL cannot be decoded
*/
+ @Nullable
public static String getTrackableFromURL(final String url) {
if (url == null) {
return null;
diff --git a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
index 3992013..9377d6d 100644
--- a/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
+++ b/main/src/cgeo/geocaching/connector/GeocachingAustraliaConnector.java
@@ -1,30 +1,32 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
-public class GeocachingAustraliaConnector extends AbstractConnector {
+class GeocachingAustraliaConnector extends AbstractConnector {
@Override
+ @NonNull
public String getName() {
return "Geocaching Australia";
}
@Override
+ @NonNull
public String getCacheUrl(final @NonNull Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@Override
+ @NonNull
public String getHost() {
return "geocaching.com.au";
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@@ -34,6 +36,7 @@ public class GeocachingAustraliaConnector extends AbstractConnector {
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return "http://" + getHost() + "/cache/";
}
diff --git a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
index aa08485..4340cac 100644
--- a/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
+++ b/main/src/cgeo/geocaching/connector/GeopeitusConnector.java
@@ -1,39 +1,42 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
-public class GeopeitusConnector extends AbstractConnector {
+class GeopeitusConnector extends AbstractConnector {
@Override
+ @NonNull
public String getName() {
return "geopeitus.ee";
}
@Override
+ @NonNull
public String getCacheUrl(final @NonNull Geocache cache) {
return getCacheUrlPrefix() + StringUtils.stripStart(cache.getGeocode().substring(2), "0");
}
@Override
+ @NonNull
public String getHost() {
return "www.geopeitus.ee";
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return StringUtils.startsWith(geocode, "GE") && isNumericId(geocode.substring(2));
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return "http://" + getHost() + "/aare/";
}
diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java
index e6b6674..74b1028 100644
--- a/main/src/cgeo/geocaching/connector/IConnector.java
+++ b/main/src/cgeo/geocaching/connector/IConnector.java
@@ -1,12 +1,12 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.Collection;
import java.util.List;
@@ -15,8 +15,8 @@ public interface IConnector {
/**
* get name for display (currently only used in links)
*
- * @return
*/
+ @NonNull
public String getName();
/**
@@ -31,109 +31,96 @@ public interface IConnector {
/**
* Get the browser URL for the given cache.
*
- * @param cache
- * @return
*/
+ @Nullable
public String getCacheUrl(final @NonNull Geocache cache);
/**
* get long browser URL for the given cache
*
- * @param cache
- * @return
*/
+ @Nullable
public String getLongCacheUrl(final @NonNull Geocache cache);
/**
* enable/disable watchlist controls in cache details
*
- * @return
*/
public boolean supportsWatchList();
/**
* Add the cache to the watchlist
*
- * @param cache
* @return True - success/False - failure
*/
- public boolean addToWatchlist(Geocache cache);
+ public boolean addToWatchlist(@NonNull Geocache cache);
/**
* Remove the cache from the watchlist
*
- * @param cache
* @return True - success/False - failure
*/
- public boolean removeFromWatchlist(Geocache cache);
+ public boolean removeFromWatchlist(@NonNull Geocache cache);
/**
* enable/disable favorite points controls in cache details
*
- * @return
*/
- public boolean supportsFavoritePoints(final Geocache cache);
+ public boolean supportsFavoritePoints(@NonNull final Geocache cache);
/**
* enable/disable logging controls in cache details
*
- * @return
*/
public boolean supportsLogging();
/**
* enable/disable attaching image to log
*
- * @return
*/
public boolean supportsLogImages();
/**
* Get an ILoggingManager to guide the logging process.
*
- * @return
*/
- public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache);
+ @NonNull
+ public ILoggingManager getLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final Geocache cache);
/**
* Get host name of the connector server for dynamic loading of data.
*
- * @return
*/
+ @NonNull
public String getHost();
/**
* Get cache data license text. This is displayed somewhere near the cache details.
*
- * @param cache
- * @return
*/
+ @NonNull
public String getLicenseText(final @NonNull Geocache cache);
/**
* return true if this is a ZIP file containing a GPX file
*
- * @param fileName
- * @return
*/
- public boolean isZippedGPXFile(final String fileName);
+ public boolean isZippedGPXFile(@NonNull final String fileName);
/**
* return true if coordinates of a cache are reliable. only implemented by GC connector
*
* @param cacheHasReliableLatLon
* flag of the cache
- * @return
*/
public boolean isReliableLatLon(boolean cacheHasReliableLatLon);
/**
* extract a geocode from the given URL, if this connector can handle that URL somehow
*
- * @param url
- * @return
*/
- public String getGeocodeFromUrl(final String url);
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url);
/**
* enable/disable uploading personal note
@@ -145,10 +132,9 @@ public interface IConnector {
/**
* Uploading personal note to website
*
- * @param cache
* @return success
*/
- public boolean uploadPersonalNote(Geocache cache);
+ public boolean uploadPersonalNote(@NonNull Geocache cache);
/**
* enable/disable uploading modified coordinates to website
@@ -160,25 +146,21 @@ public interface IConnector {
/**
* Resetting of modified coordinates on website to details
*
- * @param cache
* @return success
*/
- public boolean deleteModifiedCoordinates(Geocache cache);
+ public boolean deleteModifiedCoordinates(@NonNull Geocache cache);
/**
* Uploading modified coordinates to website
*
- * @param cache
- * @param wpt
* @return success
*/
- public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt);
+ public boolean uploadModifiedCoordinates(@NonNull Geocache cache, @NonNull Geopoint wpt);
/**
* Return {@code true} if this connector is active for online interaction (download details, do searches, ...). If
* this is {@code false}, the connector will still be used for already stored offline caches.
*
- * @return
*/
public boolean isActive();
@@ -189,16 +171,14 @@ public interface IConnector {
* @param cache a cache that this connector must be able to handle
* @return <code>true</code> if the current user is the cache owner, <code>false</code> otherwise
*/
- public boolean isOwner(final ICache cache);
+ public boolean isOwner(@NonNull final Geocache cache);
/**
* Check if the cache information is complete enough to be
* able to log online.
*
- * @param geocache
- * @return
*/
- public boolean canLog(Geocache geocache);
+ public boolean canLog(@NonNull Geocache geocache);
/**
* Return the marker id of the caches for this connector. This creates the different backgrounds for cache markers
@@ -213,42 +193,37 @@ public interface IConnector {
* Get the list of <b>potentially</b> possible log types for a cache. Those may still be filtered further during the
* actual logging activity.
*
- * @param geocache
- * @return
*/
- public List<LogType> getPossibleLogTypes(Geocache geocache);
+ @NonNull
+ public List<LogType> getPossibleLogTypes(@NonNull Geocache geocache);
/**
* Get the GPX id for a waypoint when exporting. For some connectors there is an inherent name logic,
* for others its just the 'prefix'.
*
- * @param prefix
- * @return
*/
- public String getWaypointGpxId(String prefix, String geocode);
+ public String getWaypointGpxId(String prefix, @NonNull String geocode);
/**
* Get the 'prefix' (key) for a waypoint from the 'name' in the GPX file
*
- * @param name
- * @return
*/
+ @NonNull
public String getWaypointPrefix(String name);
/**
* Get the maximum value for Terrain
*
- * @return
*/
public int getMaxTerrain();
/**
* Get a user readable collection of all online features of this connector.
*
- * @return
*/
+ @NonNull
public Collection<String> getCapabilities();
- public @NonNull
- List<UserAction> getUserActions();
+ @NonNull
+ public List<UserAction> getUserActions();
}
diff --git a/main/src/cgeo/geocaching/connector/ILoggingManager.java b/main/src/cgeo/geocaching/connector/ILoggingManager.java
index c5586b3..2b0a067 100644
--- a/main/src/cgeo/geocaching/connector/ILoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/ILoggingManager.java
@@ -1,9 +1,11 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.Geocache;
import cgeo.geocaching.TrackableLog;
import cgeo.geocaching.enumerations.LogType;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import android.net.Uri;
import java.util.Calendar;
@@ -13,23 +15,18 @@ public interface ILoggingManager {
/**
* Post a log for a cache online
- *
- * @param cache
- * @param logType
- * @param date
- * @param log
+ *
* @param logPassword
* optional, maybe null
- * @param trackableLogs
- * @return
*/
- LogResult postLog(Geocache cache,
- LogType logType,
- Calendar date,
- String log,
- String logPassword,
- List<TrackableLog> trackableLogs);
-
+ @NonNull
+ LogResult postLog(@NonNull LogType logType,
+ @NonNull Calendar date,
+ @NonNull String log,
+ @Nullable String logPassword,
+ @NonNull List<TrackableLog> trackableLogs);
+
+ @NonNull
ImageResult postLogImage(String logId,
String imageCaption,
String imageDescription,
@@ -37,8 +34,10 @@ public interface ILoggingManager {
public boolean hasLoaderError();
+ @NonNull
public List<TrackableLog> getTrackables();
+ @NonNull
public List<LogType> getPossibleLogTypes();
public void init();
diff --git a/main/src/cgeo/geocaching/connector/ImageResult.java b/main/src/cgeo/geocaching/connector/ImageResult.java
index 9314cad..ec11a6d 100644
--- a/main/src/cgeo/geocaching/connector/ImageResult.java
+++ b/main/src/cgeo/geocaching/connector/ImageResult.java
@@ -2,20 +2,26 @@ package cgeo.geocaching.connector;
import cgeo.geocaching.enumerations.StatusCode;
+import org.eclipse.jdt.annotation.NonNull;
+
public class ImageResult {
+ @NonNull
private final StatusCode postResult;
+ @NonNull
private final String imageUri;
- public ImageResult(StatusCode postResult, String imageUri) {
+ public ImageResult(@NonNull final StatusCode postResult, @NonNull final String imageUri) {
this.postResult = postResult;
this.imageUri = imageUri;
}
+ @NonNull
public StatusCode getPostResult() {
return postResult;
}
+ @NonNull
public String getImageUri() {
return imageUri;
}
diff --git a/main/src/cgeo/geocaching/connector/LogResult.java b/main/src/cgeo/geocaching/connector/LogResult.java
index 62111a4..9d0cb61 100644
--- a/main/src/cgeo/geocaching/connector/LogResult.java
+++ b/main/src/cgeo/geocaching/connector/LogResult.java
@@ -2,20 +2,26 @@ package cgeo.geocaching.connector;
import cgeo.geocaching.enumerations.StatusCode;
+import org.eclipse.jdt.annotation.NonNull;
+
public class LogResult {
+ @NonNull
private final StatusCode postLogResult;
+ @NonNull
private final String logId;
- public LogResult(StatusCode postLogResult, String logId) {
+ public LogResult(@NonNull final StatusCode postLogResult, @NonNull final String logId) {
this.postLogResult = postLogResult;
this.logId = logId;
}
+ @NonNull
public StatusCode getPostLogResult() {
return postLogResult;
}
+ @NonNull
public String getLogId() {
return logId;
}
diff --git a/main/src/cgeo/geocaching/connector/NoLoggingManager.java b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
index e2e5d4c..103db68 100644
--- a/main/src/cgeo/geocaching/connector/NoLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/NoLoggingManager.java
@@ -1,17 +1,19 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.Geocache;
import cgeo.geocaching.TrackableLog;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import android.net.Uri;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
-public class NoLoggingManager extends AbstractLoggingManager {
+class NoLoggingManager extends AbstractLoggingManager {
@Override
public void init() {
@@ -19,12 +21,14 @@ public class NoLoggingManager extends AbstractLoggingManager {
}
@Override
- public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, String logPassword, List<TrackableLog> trackableLogs) {
+ @NonNull
+ public LogResult postLog(@NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log, @Nullable final String logPassword, @NonNull final List<TrackableLog> trackableLogs) {
return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
@Override
- public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) {
+ @NonNull
+ public ImageResult postLogImage(final String logId, final String imageCaption, final String imageDescription, final Uri imageUri) {
return new ImageResult(StatusCode.LOG_POST_ERROR, "");
}
@@ -34,6 +38,7 @@ public class NoLoggingManager extends AbstractLoggingManager {
}
@Override
+ @NonNull
public List<LogType> getPossibleLogTypes() {
return Collections.emptyList();
}
diff --git a/main/src/cgeo/geocaching/connector/UnknownConnector.java b/main/src/cgeo/geocaching/connector/UnknownConnector.java
index 05593d7..cabf03e 100644
--- a/main/src/cgeo/geocaching/connector/UnknownConnector.java
+++ b/main/src/cgeo/geocaching/connector/UnknownConnector.java
@@ -1,30 +1,33 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
-public class UnknownConnector extends AbstractConnector {
+class UnknownConnector extends AbstractConnector {
@Override
+ @NonNull
public String getName() {
return "Unknown caches";
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
- return null; // we have no url for these caches
+ @Nullable
+ public String getCacheUrl(@NonNull final Geocache cache) {
+ return null;
}
@Override
+ @NonNull
public String getHost() {
- return null; // we have no host for these caches
+ return StringUtils.EMPTY; // we have no host for these caches
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@@ -34,7 +37,14 @@ public class UnknownConnector extends AbstractConnector {
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
+ throw new IllegalStateException("getCacheUrl cannot be called on unknown caches");
+ }
+
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/UserAction.java b/main/src/cgeo/geocaching/connector/UserAction.java
index e9ee4a3..082e32c 100644
--- a/main/src/cgeo/geocaching/connector/UserAction.java
+++ b/main/src/cgeo/geocaching/connector/UserAction.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.connector;
import org.eclipse.jdt.annotation.NonNull;
+
import rx.functions.Action1;
import android.app.Activity;
@@ -8,25 +9,26 @@ import android.app.Activity;
public class UserAction {
public static class Context {
+ @NonNull
public final String userName;
+ @NonNull
public final Activity activity;
- public Context(String userName, Activity activity) {
+ public Context(@NonNull final String userName, @NonNull final Activity activity) {
this.userName = userName;
this.activity = activity;
}
}
public final int displayResourceId;
- private final @NonNull
- Action1<Context> runnable;
+ @NonNull private final Action1<Context> runnable;
- public UserAction(int displayResourceId, final @NonNull Action1<Context> runnable) {
+ public UserAction(final int displayResourceId, final @NonNull Action1<Context> runnable) {
this.displayResourceId = displayResourceId;
this.runnable = runnable;
}
- public void run(Context context) {
+ public void run(@NonNull final Context context) {
runnable.call(context);
}
}
diff --git a/main/src/cgeo/geocaching/connector/WaymarkingConnector.java b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
index 282ee31..3361341 100644
--- a/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
+++ b/main/src/cgeo/geocaching/connector/WaymarkingConnector.java
@@ -1,41 +1,61 @@
package cgeo.geocaching.connector;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
-public class WaymarkingConnector extends AbstractConnector {
+class WaymarkingConnector extends AbstractConnector {
@Override
+ @NonNull
public String getName() {
return "Waymarking";
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getCacheUrl(@NonNull final Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@Override
+ @NonNull
public String getHost() {
return "www.waymarking.com";
}
@Override
- public boolean isOwner(ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
// this connector has no user management
return false;
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return "http://" + getHost() + "/waymarks/";
}
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return StringUtils.startsWith(geocode, "WM");
}
+
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ // waymarking URLs http://www.waymarking.com/waymarks/WMNCDT_American_Legion_Flagpole_1983_University_of_Oregon
+ code = StringUtils.substringBetween(url, "waymarks/", "_");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ return null;
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/capability/FieldNotesCapability.java b/main/src/cgeo/geocaching/connector/capability/FieldNotesCapability.java
index 4da9705..dd2bc8d 100644
--- a/main/src/cgeo/geocaching/connector/capability/FieldNotesCapability.java
+++ b/main/src/cgeo/geocaching/connector/capability/FieldNotesCapability.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.connector.IConnector;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.io.File;
/**
@@ -9,5 +11,5 @@ import java.io.File;
*
*/
public interface FieldNotesCapability extends IConnector {
- public boolean uploadFieldNotes(final File exportFile);
+ public boolean uploadFieldNotes(@NonNull final File exportFile);
}
diff --git a/main/src/cgeo/geocaching/connector/capability/ILogin.java b/main/src/cgeo/geocaching/connector/capability/ILogin.java
index 4a839c8..437eec8 100644
--- a/main/src/cgeo/geocaching/connector/capability/ILogin.java
+++ b/main/src/cgeo/geocaching/connector/capability/ILogin.java
@@ -7,13 +7,10 @@ import android.os.Handler;
public interface ILogin extends IConnector {
-
/**
- * Contacts the server the connector belongs to
- * and verifies/establishes authentication and
- * retrieves information about the current user
- * (Name, found caches) if applicable.
- *
+ * Contacts the server the connector belongs to and verifies/establishes authentication and retrieves information
+ * about the current user (Name, found caches) if applicable.
+ *
* @param handler
* Handler to receive status feedback
* @param fromActivity
@@ -23,34 +20,34 @@ public interface ILogin extends IConnector {
boolean login(Handler handler, Context fromActivity);
/**
- * Returns the status of the last {@link}login() request
+ * Log out of the connector if possible.
+ */
+ void logout();
+
+ /**
+ * Returns the status of the last {@link #login(Handler, Context)} request.
*
- * @return
*/
boolean isLoggedIn();
/**
* User-centered string describing the current login/connection status
*
- * @return
*/
String getLoginStatusString();
/**
- * Name the user has in this connector or empty string if not applicable
- * It might be necessary to execute login before this information is valid.
+ * Name the user has in this connector or empty string if not applicable.
+ * It might be necessary to execute {@link #login(Handler, Context)} before this information is valid.
*
- * @return
*/
String getUserName();
/**
- * Number of caches the user has found in this connector
- * Normally retrieved/updated with (@see login).
- * Might be out dated as changes on the connectors site
- * are generally not notified.
+ * Number of caches the user has found in this connector.
+ * Normally retrieved/updated with {@link #login(Handler, Context)}.
+ * Might be stale as changes on the connectors site are generally not notified.
*
- * @return
*/
int getCachesFound();
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
index adc36c7..576220d 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.Geopoint;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
index 7981ba8..0137c3b 100644
--- a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
+++ b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java
@@ -3,10 +3,11 @@ package cgeo.geocaching.connector.capability;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.gc.MapTokens;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Viewport;
import org.eclipse.jdt.annotation.NonNull;
public interface ISearchByViewPort extends IConnector {
- public SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens);
+ @NonNull
+ public SearchResult searchByViewport(final @NonNull Viewport viewport, @NonNull final MapTokens tokens);
}
diff --git a/main/src/cgeo/geocaching/connector/capability/IgnoreCapability.java b/main/src/cgeo/geocaching/connector/capability/IgnoreCapability.java
new file mode 100644
index 0000000..5eca3f2
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/capability/IgnoreCapability.java
@@ -0,0 +1,14 @@
+package cgeo.geocaching.connector.capability;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.connector.IConnector;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Connector capability to ignore caches.
+ */
+public interface IgnoreCapability extends IConnector {
+ public boolean canIgnoreCache(final @NonNull Geocache cache);
+ public void ignoreCache(final @NonNull Geocache cache);
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
index 421d112..86f7717 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECApi.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -9,22 +9,25 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.files.GPX10Parser;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.SynchronizedDateFormat;
import ch.boye.httpclientandroidlib.HttpResponse;
+import com.fasterxml.jackson.databind.JsonNode;
+
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -34,18 +37,27 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
-public class ECApi {
+final class ECApi {
+ @NonNull
private static final String API_HOST = "https://extremcaching.com/exports/";
+ @NonNull
private static final ECLogin ecLogin = ECLogin.getInstance();
+
+ @NonNull
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) {
+ private ECApi() {
+ // utility class with static methods
+ }
+
+ static String getIdFromGeocode(final String geocode) {
return StringUtils.removeStartIgnoreCase(geocode, "EC");
}
- public static Geocache searchByGeoCode(final String geocode) {
+ @Nullable
+ static Geocache searchByGeoCode(final String geocode) {
final Parameters params = new Parameters("id", getIdFromGeocode(geocode));
final HttpResponse response = apiRequest("gpx.php", params);
@@ -56,7 +68,8 @@ public class ECApi {
return null;
}
- public static Collection<Geocache> searchByBBox(final Viewport viewport) {
+ @NonNull
+ static Collection<Geocache> searchByBBox(final Viewport viewport) {
if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
return Collections.emptyList();
@@ -72,8 +85,8 @@ public class ECApi {
return importCachesFromJSON(response);
}
-
- public static Collection<Geocache> searchByCenter(final Geopoint center) {
+ @NonNull
+ static Collection<Geocache> searchByCenter(final Geopoint center) {
final Parameters params = new Parameters("fnc", "center");
params.add("distance", "20");
@@ -84,11 +97,13 @@ public class ECApi {
return importCachesFromJSON(response);
}
- public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log) {
+ @NonNull
+ static LogResult postLog(@NonNull final Geocache cache, @NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log) {
return postLog(cache, logType, date, log, false);
}
- public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, boolean isRetry) {
+ @NonNull
+ private static LogResult postLog(@NonNull final Geocache cache, @NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log, final boolean isRetry) {
final Parameters params = new Parameters("cache_id", cache.getGeocode());
params.add("type", logType.type);
params.add("log", log);
@@ -99,7 +114,7 @@ public class ECApi {
final HttpResponse response = Network.postRequest(uri, params);
if (response == null) {
- return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
if (!isRetry && response.getStatusLine().getStatusCode() == 403) {
if (ecLogin.login() == StatusCode.NO_ERROR) {
@@ -107,7 +122,7 @@ public class ECApi {
}
}
if (response.getStatusLine().getStatusCode() != 200) {
- return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
final String data = Network.getResponseDataAlways(response);
@@ -119,18 +134,20 @@ public class ECApi {
return new LogResult(StatusCode.NO_ERROR, uid);
}
- return new LogResult(StatusCode.LOG_POST_ERROR_EC, "");
+ return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
-
+ @Nullable
private static HttpResponse apiRequest(final Parameters params) {
return apiRequest("api.php", params);
}
+ @Nullable
private static HttpResponse apiRequest(final String uri, final Parameters params) {
return apiRequest(uri, params, false);
}
+ @Nullable
private static HttpResponse apiRequest(final String uri, final Parameters params, final boolean isRetry) {
// add session and cgeo marker on every request
if (!isRetry) {
@@ -155,64 +172,66 @@ public class ECApi {
return response;
}
+ @NonNull
private static Collection<Geocache> importCachesFromGPXResponse(final HttpResponse response) {
if (response == null) {
return Collections.emptyList();
}
try {
- return new GPX10Parser(StoredList.TEMPORARY_LIST_ID).parse(response.getEntity().getContent(), null);
- } catch (Exception e) {
+ return new GPX10Parser(StoredList.TEMPORARY_LIST.id).parse(response.getEntity().getContent(), null);
+ } catch (final Exception e) {
Log.e("Error importing gpx from extremcaching.com", e);
return Collections.emptyList();
}
}
+ @NonNull
private static List<Geocache> importCachesFromJSON(final HttpResponse response) {
if (response != null) {
try {
- final String data = Network.getResponseDataAlways(response);
- if (StringUtils.isBlank(data) || StringUtils.equals(data, "[]")) {
+ final JsonNode json = JsonUtils.reader.readTree(Network.getResponseDataAlways(response));
+ if (!json.isArray()) {
return Collections.emptyList();
}
- final JSONArray json = new JSONArray(data);
- final int len = json.length();
- final List<Geocache> caches = new ArrayList<>(len);
- for (int i = 0; i < len; i++) {
- final Geocache cache = parseCache(json.getJSONObject(i));
+ final List<Geocache> caches = new ArrayList<>(json.size());
+ for (final JsonNode node: json) {
+ final Geocache cache = parseCache(node);
if (cache != null) {
caches.add(cache);
}
}
return caches;
- } catch (final JSONException e) {
- Log.w("JSONResult", e);
+ } catch (IOException | ClassCastException e) {
+ Log.w("importCachesFromJSON", e);
}
}
return Collections.emptyList();
}
- private static Geocache parseCache(final JSONObject response) {
- final Geocache cache = new Geocache();
- cache.setReliableLatLon(true);
+ @Nullable
+ private static Geocache parseCache(final JsonNode response) {
try {
- cache.setGeocode("EC" + response.getString("cache_id"));
- cache.setName(response.getString("title"));
- cache.setCoords(new Geopoint(response.getString("lat"), response.getString("lon")));
- cache.setType(getCacheType(response.getString("type")));
- cache.setDifficulty((float) response.getDouble("difficulty"));
- cache.setTerrain((float) response.getDouble("terrain"));
- cache.setSize(CacheSize.getById(response.getString("size")));
- cache.setFound(response.getInt("found") == 1);
+ final Geocache cache = new Geocache();
+ cache.setReliableLatLon(true);
+ cache.setGeocode("EC" + response.get("cache_id").asText());
+ cache.setName(response.get("title").asText());
+ cache.setCoords(new Geopoint(response.get("lat").asText(), response.get("lon").asText()));
+ cache.setType(getCacheType(response.get("type").asText()));
+ cache.setDifficulty((float) response.get("difficulty").asDouble());
+ cache.setTerrain((float) response.get("terrain").asDouble());
+ cache.setSize(CacheSize.getById(response.get("size").asText()));
+ cache.setFound(response.get("found").asInt() == 1);
DataStore.saveCache(cache, EnumSet.of(SaveFlag.CACHE));
- } catch (final JSONException e) {
+ return cache;
+ } catch (final NullPointerException e) {
Log.e("ECApi.parseCache", e);
return null;
}
- return cache;
}
+ @NonNull
private static CacheType getCacheType(final String cacheType) {
if (cacheType.equalsIgnoreCase("Tradi")) {
return CacheType.TRADITIONAL;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
index a266eee..68dbee7 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECConnector.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -2,7 +2,6 @@ package cgeo.geocaching.connector.ec;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
@@ -16,9 +15,9 @@ import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.utils.CancellableHandler;
@@ -37,13 +36,18 @@ import java.util.regex.Pattern;
public class ECConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ILogin, ICredentials {
+ @NonNull
private static final String CACHE_URL = "http://extremcaching.com/index.php/output-2/";
/**
* Pattern for EC codes
*/
+ @NonNull
private final static Pattern PATTERN_EC_CODE = Pattern.compile("EC[0-9]+", Pattern.CASE_INSENSITIVE);
+
private final CgeoApplication app = CgeoApplication.getInstance();
+
+ @NonNull
private final ECLogin ecLogin = ECLogin.getInstance();
private ECConnector() {
@@ -57,27 +61,30 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
private static final @NonNull ECConnector INSTANCE = new ECConnector();
}
- public static @NonNull
- ECConnector getInstance() {
+ @NonNull
+ public static ECConnector getInstance() {
return Holder.INSTANCE;
}
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return ECConnector.PATTERN_EC_CODE.matcher(geocode).matches();
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getCacheUrl(@NonNull final Geocache cache) {
return CACHE_URL + cache.getGeocode().replace("EC", "");
}
@Override
+ @NonNull
public String getName() {
return "extremcaching.com";
}
@Override
+ @NonNull
public String getHost() {
return "extremcaching.com";
}
@@ -95,31 +102,28 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
+ @NonNull
+ public SearchResult searchByViewport(@NonNull final Viewport viewport, @NonNull final MapTokens tokens) {
final Collection<Geocache> caches = ECApi.searchByBBox(viewport);
- if (caches == null) {
- return null;
- }
final SearchResult searchResult = new SearchResult(caches);
return searchResult.filterSearchResults(false, false, Settings.getCacheType());
}
@Override
- public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ @NonNull
+ public SearchResult searchByCenter(@NonNull final Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
final Collection<Geocache> caches = ECApi.searchByCenter(center);
- if (caches == null) {
- return null;
- }
final SearchResult searchResult = new SearchResult(caches);
return searchResult.filterSearchResults(false, false, Settings.getCacheType());
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return CACHE_URL;
}
@@ -130,7 +134,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean login(Handler handler, Context fromActivity) {
+ public boolean login(final Handler handler, final Context fromActivity) {
// login
final StatusCode status = ecLogin.login();
@@ -167,7 +171,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public int getCacheMapMarkerId(boolean disabled) {
+ public int getCacheMapMarkerId(final boolean disabled) {
final String icons = Settings.getECIconSet();
if (StringUtils.equals(icons, "1")) {
return disabled ? R.drawable.marker_disabled_other : R.drawable.marker_other;
@@ -176,6 +180,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
+ @NonNull
public String getLicenseText(final @NonNull Geocache cache) {
// NOT TO BE TRANSLATED
return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, CC BY-NC-ND 3.0, alle Logeinträge © jeweiliger Autor";
@@ -187,17 +192,19 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean canLog(Geocache cache) {
+ public boolean canLog(@NonNull final Geocache cache) {
return true;
}
@Override
- public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ @NonNull
+ public ILoggingManager getLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final Geocache cache) {
return new ECLoggingManager(activity, this, cache);
}
@Override
- public List<LogType> getPossibleLogTypes(Geocache geocache) {
+ @NonNull
+ public List<LogType> getPossibleLogTypes(@NonNull final Geocache geocache) {
final List<LogType> logTypes = new ArrayList<>();
if (geocache.isEventCache()) {
logTypes.add(LogType.WILL_ATTEND);
@@ -227,4 +234,14 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
return R.string.pref_ecpassword;
}
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ final String geocode = "EC" + StringUtils.substringAfter(url, "extremcaching.com/index.php/output-2/");
+ if (canHandle(geocode)) {
+ return geocode;
+ }
+ return super.getGeocodeFromUrl(url);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java b/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java
index ded2d71..34c3d1b 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECLoggingManager.java
@@ -7,19 +7,28 @@ import cgeo.geocaching.connector.AbstractLoggingManager;
import cgeo.geocaching.connector.ImageResult;
import cgeo.geocaching.connector.LogResult;
import cgeo.geocaching.enumerations.LogType;
+import cgeo.geocaching.enumerations.StatusCode;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import android.net.Uri;
import java.util.Calendar;
import java.util.List;
-public class ECLoggingManager extends AbstractLoggingManager {
+class ECLoggingManager extends AbstractLoggingManager {
+ @NonNull
private final ECConnector connector;
+
+ @NonNull
private final Geocache cache;
- private LogCacheActivity activity;
- public ECLoggingManager(final LogCacheActivity activity, final ECConnector connector, final Geocache cache) {
+ @NonNull
+ private final LogCacheActivity activity;
+
+ ECLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final ECConnector connector, @NonNull final Geocache cache) {
this.connector = connector;
this.cache = cache;
this.activity = activity;
@@ -31,16 +40,19 @@ public class ECLoggingManager extends AbstractLoggingManager {
}
@Override
- public final LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, final String logPassword, final List<TrackableLog> trackableLogs) {
+ @NonNull
+ public final LogResult postLog(@NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log, @Nullable final String logPassword, @NonNull final List<TrackableLog> trackableLogs) {
return ECApi.postLog(cache, logType, date, log);
}
@Override
+ @NonNull
public final ImageResult postLogImage(final String logId, final String imageCaption, final String imageDescription, final Uri imageUri) {
- return null;
+ return new ImageResult(StatusCode.LOG_POST_ERROR, "");
}
@Override
+ @NonNull
public List<LogType> getPossibleLogTypes() {
return connector.getPossibleLogTypes(cache);
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
index 012bdc9..94b450b 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECLogin.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -7,34 +7,42 @@ import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.json.JSONException;
-import org.json.JSONObject;
+
+import java.io.IOException;
public class ECLogin extends AbstractLogin {
private final CgeoApplication app = CgeoApplication.getInstance();
- protected String sessionId = null;
+ private String sessionId = null;
private ECLogin() {
// singleton
}
private static class SingletonHolder {
- private static ECLogin INSTANCE = new ECLogin();
+ @NonNull
+ private final static ECLogin INSTANCE = new ECLogin();
}
+ @NonNull
public static ECLogin getInstance() {
return SingletonHolder.INSTANCE;
}
@Override
- protected StatusCode login(boolean retry) {
+ @NonNull
+ protected StatusCode login(final boolean retry) {
final ImmutablePair<String, String> login = Settings.getCredentials(ECConnector.getInstance());
if (StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
@@ -46,9 +54,9 @@ public class ECLogin extends AbstractLogin {
setActualStatus(app.getString(R.string.init_login_popup_working));
final Parameters params = new Parameters("user", login.left, "pass", login.right);
- HttpResponse loginResponse = Network.postRequest("https://extremcaching.com/exports/apilogin.php", params);
+ final HttpResponse loginResponse = Network.postRequest("https://extremcaching.com/exports/apilogin.php", params);
- String loginData = Network.getResponseData(loginResponse);
+ final String loginData = Network.getResponseData(loginResponse);
if (StringUtils.isBlank(loginData)) {
Log.e("ECLogin.login: Failed to retrieve login data");
@@ -80,10 +88,9 @@ public class ECLogin extends AbstractLogin {
/**
* Check if the user has been logged in when he retrieved the data.
*
- * @param data
* @return <code>true</code> if user is logged in, <code>false</code> otherwise
*/
- public boolean getLoginStatus(@Nullable final String data) {
+ private boolean getLoginStatus(@Nullable final String data) {
if (StringUtils.isBlank(data) || StringUtils.equals(data, "[]")) {
Log.e("ECLogin.getLoginStatus: No or empty data given");
return false;
@@ -93,18 +100,18 @@ public class ECLogin extends AbstractLogin {
setActualStatus(app.getString(R.string.init_login_popup_ok));
try {
- final JSONObject json = new JSONObject(data);
+ final JsonNode json = JsonUtils.reader.readTree(data);
- final String sid = json.getString("sid");
+ final String sid = json.get("sid").asText();
if (!StringUtils.isBlank(sid)) {
sessionId = sid;
setActualLoginStatus(true);
- setActualUserName(json.getString("username"));
- setActualCachesFound(json.getInt("found"));
+ setActualUserName(json.get("username").asText());
+ setActualCachesFound(json.get("found").asInt());
return true;
}
resetLoginStatus();
- } catch (final JSONException e) {
+ } catch (IOException | NullPointerException e) {
Log.e("ECLogin.getLoginStatus", e);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index 3b7c31e..b38d2e4 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.connector.gc;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
@@ -20,10 +19,11 @@ import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByOwner;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.capability.IgnoreCapability;
import cgeo.geocaching.enumerations.StatusCode;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
@@ -48,20 +48,24 @@ import java.io.File;
import java.util.List;
import java.util.regex.Pattern;
-public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ISearchByKeyword, ILogin, ICredentials, ISearchByOwner, ISearchByFinder, FieldNotesCapability {
+public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ISearchByKeyword, ILogin, ICredentials, ISearchByOwner, ISearchByFinder, FieldNotesCapability, IgnoreCapability {
+ @NonNull
private static final String CACHE_URL_SHORT = "http://coord.info/";
// Double slash is used to force open in browser
+ @NonNull
private static final String CACHE_URL_LONG = "http://www.geocaching.com/seek/cache_details.aspx?wp=";
/**
* Pocket queries downloaded from the website use a numeric prefix. The pocket query creator Android app adds a
* verbatim "pocketquery" prefix.
*/
+ @NonNull
private static final Pattern GPX_ZIP_FILE_PATTERN = Pattern.compile("((\\d{7,})|(pocketquery))" + "(_.+)?" + "\\.zip", Pattern.CASE_INSENSITIVE);
/**
* Pattern for GC codes
*/
+ @NonNull
private final static Pattern PATTERN_GC_CODE = Pattern.compile("GC[0-9A-Z]+", Pattern.CASE_INSENSITIVE);
private GCConnector() {
@@ -75,23 +79,25 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
private static final @NonNull GCConnector INSTANCE = new GCConnector();
}
- public static @NonNull
- GCConnector getInstance() {
+ @NonNull
+ public static GCConnector getInstance() {
return Holder.INSTANCE;
}
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return GCConnector.PATTERN_GC_CODE.matcher(geocode).matches();
}
@Override
- public String getLongCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getLongCacheUrl(@NonNull final Geocache cache) {
return CACHE_URL_LONG + cache.getGeocode();
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getCacheUrl(@NonNull final Geocache cache) {
return CACHE_URL_SHORT + cache.getGeocode();
}
@@ -121,21 +127,24 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ @NonNull
+ public ILoggingManager getLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final Geocache cache) {
return new GCLoggingManager(activity, cache);
}
@Override
- public boolean canLog(Geocache cache) {
+ public boolean canLog(@NonNull final Geocache cache) {
return StringUtils.isNotBlank(cache.getCacheId());
}
@Override
+ @NonNull
public String getName() {
return "geocaching.com";
}
@Override
+ @NonNull
public String getHost() {
return "www.geocaching.com";
}
@@ -178,28 +187,29 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
+ @NonNull
+ public SearchResult searchByViewport(@NonNull final Viewport viewport, @NonNull final MapTokens tokens) {
return GCMap.searchByViewport(viewport, tokens);
}
@Override
- public boolean isZippedGPXFile(final String fileName) {
+ public boolean isZippedGPXFile(@NonNull final String fileName) {
return GPX_ZIP_FILE_PATTERN.matcher(fileName).matches();
}
@Override
- public boolean isReliableLatLon(boolean cacheHasReliableLatLon) {
+ public boolean isReliableLatLon(final boolean cacheHasReliableLatLon) {
return cacheHasReliableLatLon;
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
final String user = Settings.getUsername();
return StringUtils.isNotEmpty(user) && StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), user);
}
@Override
- public boolean addToWatchlist(Geocache cache) {
+ public boolean addToWatchlist(@NonNull final Geocache cache) {
final boolean added = GCParser.addToWatchlist(cache);
if (added) {
DataStore.saveChangedCache(cache);
@@ -208,7 +218,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean removeFromWatchlist(Geocache cache) {
+ public boolean removeFromWatchlist(@NonNull final Geocache cache) {
final boolean removed = GCParser.removeFromWatchlist(cache);
if (removed) {
DataStore.saveChangedCache(cache);
@@ -226,7 +236,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
* @return <code>true</code> if the cache was successfully added, <code>false</code> otherwise
*/
- public static boolean addToFavorites(Geocache cache) {
+ public static boolean addToFavorites(final Geocache cache) {
final boolean added = GCParser.addToFavorites(cache);
if (added) {
DataStore.saveChangedCache(cache);
@@ -244,7 +254,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
* @return <code>true</code> if the cache was successfully added, <code>false</code> otherwise
*/
- public static boolean removeFromFavorites(Geocache cache) {
+ public static boolean removeFromFavorites(final Geocache cache) {
final boolean removed = GCParser.removeFromFavorites(cache);
if (removed) {
DataStore.saveChangedCache(cache);
@@ -253,7 +263,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt) {
+ public boolean uploadModifiedCoordinates(@NonNull final Geocache cache, @NonNull final Geopoint wpt) {
final boolean uploaded = GCParser.uploadModifiedCoordinates(cache, wpt);
if (uploaded) {
DataStore.saveChangedCache(cache);
@@ -262,7 +272,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean deleteModifiedCoordinates(Geocache cache) {
+ public boolean deleteModifiedCoordinates(@NonNull final Geocache cache) {
final boolean deleted = GCParser.deleteModifiedCoordinates(cache);
if (deleted) {
DataStore.saveChangedCache(cache);
@@ -271,7 +281,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean uploadPersonalNote(Geocache cache) {
+ public boolean uploadPersonalNote(@NonNull final Geocache cache) {
final boolean uploaded = GCParser.uploadPersonalNote(cache);
if (uploaded) {
DataStore.saveChangedCache(cache);
@@ -280,31 +290,34 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ public SearchResult searchByCenter(@NonNull final Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
return GCParser.searchByCoords(center, Settings.getCacheType(), Settings.isShowCaptcha(), recaptchaReceiver);
}
@Override
- public boolean supportsFavoritePoints(final Geocache cache) {
+ public boolean supportsFavoritePoints(@NonNull final Geocache cache) {
return !cache.getType().isEvent();
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
- return null; // UNUSED
+ return StringUtils.EMPTY; // UNUSED
}
@Override
- public String getGeocodeFromUrl(String url) {
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ final String noQueryString = StringUtils.substringBefore(url, "?");
// coord.info URLs
- String code = StringUtils.substringAfterLast(url, "coord.info/");
- if (code != null && canHandle(code)) {
- return code;
+ final String afterCoord = StringUtils.substringAfterLast(noQueryString, "coord.info/");
+ if (canHandle(afterCoord)) {
+ return afterCoord;
}
// expanded geocaching.com URLs
- code = StringUtils.substringBetween(url, "/geocache/", "_");
- if (code != null && canHandle(code)) {
- return code;
+ final String afterGeocache = StringUtils.substringBetween(noQueryString, "/geocache/", "_");
+ if (afterGeocache != null && canHandle(afterGeocache)) {
+ return afterGeocache;
}
return null;
}
@@ -315,7 +328,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public int getCacheMapMarkerId(boolean disabled) {
+ public int getCacheMapMarkerId(final boolean disabled) {
if (disabled) {
return R.drawable.marker_disabled;
}
@@ -323,14 +336,10 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean login(Handler handler, Context fromActivity) {
+ public boolean login(final Handler handler, final Context fromActivity) {
// login
final StatusCode status = GCLogin.getInstance().login();
- if (status == StatusCode.NO_ERROR) {
- GCLogin.detectGcCustomDate();
- }
-
if (CgeoApplication.getInstance().showLoginToast && handler != null) {
handler.sendMessage(handler.obtainMessage(0, status));
CgeoApplication.getInstance().showLoginToast = false;
@@ -344,6 +353,11 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
+ public void logout() {
+ GCLogin.getInstance().logout();
+ }
+
+ @Override
public String getUserName() {
return GCLogin.getInstance().getActualUserName();
}
@@ -364,7 +378,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public String getWaypointGpxId(String prefix, String geocode) {
+ public String getWaypointGpxId(final String prefix, @NonNull final String geocode) {
String gpxId = prefix;
if (StringUtils.isNotBlank(geocode) && geocode.length() > 2) {
gpxId += geocode.substring(2);
@@ -373,7 +387,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public String getWaypointPrefix(String name) {
+ @NonNull
+ public String getWaypointPrefix(final String name) {
String prefix = name;
if (StringUtils.isNotBlank(prefix) && prefix.length() >= 2) {
prefix = name.substring(0, 2);
@@ -382,7 +397,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public SearchResult searchByKeyword(@NonNull String keyword, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ public SearchResult searchByKeyword(@NonNull final String keyword, final @NonNull RecaptchaReceiver recaptchaReceiver) {
return GCParser.searchByKeyword(keyword, Settings.getCacheType(), Settings.isShowCaptcha(), recaptchaReceiver);
}
@@ -399,18 +414,18 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public @NonNull
List<UserAction> getUserActions() {
- List<UserAction> actions = super.getUserActions();
+ final List<UserAction> actions = super.getUserActions();
actions.add(new UserAction(R.string.user_menu_open_browser, new Action1<UserAction.Context>() {
@Override
- public void call(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(final 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 Action1<UserAction.Context>() {
@Override
- public void call(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(final cgeo.geocaching.connector.UserAction.Context context) {
try {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(context.userName))));
} catch (final ActivityNotFoundException e) {
@@ -433,7 +448,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
}
@Override
- public boolean uploadFieldNotes(final File exportFile) {
+ public boolean uploadFieldNotes(@NonNull final File exportFile) {
if (!GCLogin.getInstance().isActualLoginStatus()) {
// no need to upload (possibly large file) if we're not logged in
final StatusCode loginState = GCLogin.getInstance().login();
@@ -468,4 +483,14 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
return true;
}
+ @Override
+ public boolean canIgnoreCache(@NonNull final Geocache cache) {
+ return StringUtils.isNotEmpty(cache.getType().wptTypeId);
+ }
+
+ @Override
+ public void ignoreCache(@NonNull final Geocache cache) {
+ GCParser.ignoreCache(cache);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConstants.java b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
index 3f16156..1b4c5a6 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConstants.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConstants.java
@@ -15,172 +15,175 @@ import java.util.regex.Pattern;
public final class GCConstants {
static final String GC_URL = "http://www.geocaching.com/";
- static final String GC_TILE_URL = "http://tiles.geocaching.com/";
+ private static final String GC_TILE_URL = "http://tiles.geocaching.com/";
/** Live Map */
- public final static @NonNull String URL_LIVE_MAP = GC_URL + "map/default.aspx";
+ final static @NonNull String URL_LIVE_MAP = GC_URL + "map/default.aspx";
/** Live Map pop-up */
- public final static @NonNull String URL_LIVE_MAP_DETAILS = GC_TILE_URL + "map.details";
+ final static @NonNull String URL_LIVE_MAP_DETAILS = GC_TILE_URL + "map.details";
/** Caches in a tile */
- public final static @NonNull String URL_MAP_INFO = GC_TILE_URL + "map.info";
+ final static @NonNull String URL_MAP_INFO = GC_TILE_URL + "map.info";
/** Tile itself */
- public final static @NonNull String URL_MAP_TILE = GC_TILE_URL + "map.png";
+ final static @NonNull String URL_MAP_TILE = GC_TILE_URL + "map.png";
+ /** Format used by geocaching.com when user is not logged in. */
+ public static final String DEFAULT_GC_DATE = "MM/dd/yyyy";
/**
* Patterns for parsing the result of a (detailed) search
*/
- public final static Pattern PATTERN_HINT = Pattern.compile("<div id=\"div_hint\"[^>]*>(.*?)</div>", Pattern.DOTALL);
- public final static Pattern PATTERN_DESC = Pattern.compile("<span id=\"ctl00_ContentBody_LongDescription\">(.*?)</span>\\s*</div>\\s*<p>\\s*</p>\\s*<p id=\"ctl00_ContentBody_hints\">", Pattern.DOTALL);
- public final static Pattern PATTERN_SHORTDESC = Pattern.compile("<span id=\"ctl00_ContentBody_ShortDescription\">(.*?)</span>\\s*</div>", Pattern.DOTALL);
- public final static Pattern PATTERN_GEOCODE = Pattern.compile("class=\"CoordInfoCode\">(GC[0-9A-Z]+)</span>");
- public final static Pattern PATTERN_CACHEID = Pattern.compile("/seek/log\\.aspx\\?ID=(\\d+)");
- public final static Pattern PATTERN_GUID = Pattern.compile(Pattern.quote("&wid=") + "([0-9a-z\\-]+)" + Pattern.quote("&"));
- public final static Pattern PATTERN_SIZE = Pattern.compile("<div id=\"ctl00_ContentBody_size\" class=\"CacheSize[^\"]*\">[^<]*<p[^>]*>[^S]*Size[^:]*:[^<]*<span[^>]*>[^<]*<img src=\"[^\"]*/icons/container/[a-z_]+\\.gif\" alt=\"\\w+: ([^\"]+)\"[^>]*>[^<]*<small>[^<]*</small>[^<]*</span>[^<]*</p>");
- public final static Pattern PATTERN_LATLON = Pattern.compile("<span id=\"uxLatLon\"[^>]*>(.*?)</span>");
- public final static Pattern PATTERN_LATLON_ORIG = Pattern.compile("\\{\"isUserDefined\":true[^}]+?\"oldLatLngDisplay\":\"([^\"]+)\"\\}");
- public final static Pattern PATTERN_LOCATION = Pattern.compile(Pattern.quote("<span id=\"ctl00_ContentBody_Location\">In ") + "(?:<a href=[^>]*>)?(.*?)<");
- public final static Pattern PATTERN_PERSONALNOTE = Pattern.compile("<span id=\"cache_note\"[^>]*>(.*?)</span>", Pattern.DOTALL);
- public final static Pattern PATTERN_NAME = Pattern.compile("<span id=\"ctl00_ContentBody_CacheName\">(.*?)</span>");
- public final static Pattern PATTERN_DIFFICULTY = Pattern.compile("<span id=\"ctl00_ContentBody_uxLegendScale\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\"");
- public final static Pattern PATTERN_TERRAIN = Pattern.compile("<span id=\"ctl00_ContentBody_Localize[\\d]+\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\"");
- public final static Pattern PATTERN_OWNER_USERID = Pattern.compile("other caches <a href=\"/seek/nearest\\.aspx\\?u=(.*?)\">hidden</a> or");
- public final static Pattern PATTERN_FOUND = Pattern.compile("ctl00_ContentBody_GeoNav_logText\">(Found It|Attended)");
- public final static Pattern PATTERN_FOUND_ALTERNATIVE = Pattern.compile("<div class=\"StatusInformationWidget FavoriteWidget\"");
- public final static Pattern PATTERN_FOUND_DATE = Pattern.compile(">Logged on: ([^<]+?)<");
- public final static Pattern PATTERN_OWNER_DISPLAYNAME = Pattern.compile("<div id=\"ctl00_ContentBody_mcd1\">[^<]+<a href=\"[^\"]+\">([^<]+)</a>");
- public final static Pattern PATTERN_TYPE = Pattern.compile("<a href=\"/seek/nearest.aspx\\?tx=([0-9a-f-]+)");
- public final static Pattern PATTERN_HIDDEN = Pattern.compile("<div id=\"ctl00_ContentBody_mcd2\">\\W*Hidden[\\s:]*([^<]+?)</div>");
- public final static Pattern PATTERN_HIDDENEVENT = Pattern.compile("Event\\s*Date\\s*:\\s*([^<]+)<div id=\"calLinks\">", Pattern.DOTALL);
- public final static Pattern PATTERN_FAVORITE = Pattern.compile("<div id=\"pnlFavoriteCache\">"); // without 'class="hideMe"' inside the tag !
- public final static Pattern PATTERN_FAVORITECOUNT = Pattern.compile("<span class=\"favorite-value\">\\D*([0-9]+?)\\D*</span>");
- public final static Pattern PATTERN_COUNTLOGS = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p(.+?)</p></span>");
- public final static Pattern PATTERN_LOGBOOK = Pattern.compile("initalLogs = (\\{.+\\});"); // The "inital" typo really comes from gc.com site
+ final static Pattern PATTERN_HINT = Pattern.compile("<div id=\"div_hint\"[^>]*>(.*?)</div>", Pattern.DOTALL);
+ final static Pattern PATTERN_DESC = Pattern.compile("<span id=\"ctl00_ContentBody_LongDescription\">(.*?)</span>\\s*</div>\\s*<p>\\s*</p>\\s*<p id=\"ctl00_ContentBody_hints\">", Pattern.DOTALL);
+ final static Pattern PATTERN_SHORTDESC = Pattern.compile("<span id=\"ctl00_ContentBody_ShortDescription\">(.*?)</span>\\s*</div>", Pattern.DOTALL);
+ final static Pattern PATTERN_GEOCODE = Pattern.compile("class=\"CoordInfoCode\">(GC[0-9A-Z]+)</span>");
+ final static Pattern PATTERN_CACHEID = Pattern.compile("/seek/log\\.aspx\\?ID=(\\d+)");
+ final static Pattern PATTERN_GUID = Pattern.compile(Pattern.quote("&wid=") + "([0-9a-z\\-]+)" + Pattern.quote("&"));
+ final static Pattern PATTERN_SIZE = Pattern.compile("<div id=\"ctl00_ContentBody_size\" class=\"CacheSize[^\"]*\">[^<]*<p[^>]*>[^S]*Size[^:]*:[^<]*<span[^>]*>[^<]*<img src=\"[^\"]*/icons/container/[a-z_]+\\.gif\" alt=\"\\w+: ([^\"]+)\"[^>]*>[^<]*<small>[^<]*</small>[^<]*</span>[^<]*</p>");
+ final static Pattern PATTERN_LATLON = Pattern.compile("<span id=\"uxLatLon\"[^>]*>(.*?)</span>");
+ final static Pattern PATTERN_LATLON_ORIG = Pattern.compile("\\{\"isUserDefined\":true[^}]+?\"oldLatLngDisplay\":\"([^\"]+)\"\\}");
+ final static Pattern PATTERN_LOCATION = Pattern.compile(Pattern.quote("<span id=\"ctl00_ContentBody_Location\">In ") + "(?:<a href=[^>]*>)?(.*?)<");
+ final static Pattern PATTERN_PERSONALNOTE = Pattern.compile("<span id=\"cache_note\"[^>]*>(.*?)</span>", Pattern.DOTALL);
+ final static Pattern PATTERN_NAME = Pattern.compile("<span id=\"ctl00_ContentBody_CacheName\">(.*?)</span>");
+ final static Pattern PATTERN_DIFFICULTY = Pattern.compile("<span id=\"ctl00_ContentBody_uxLegendScale\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\"");
+ final static Pattern PATTERN_TERRAIN = Pattern.compile("<span id=\"ctl00_ContentBody_Localize[\\d]+\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\"");
+ final static Pattern PATTERN_OWNER_USERID = Pattern.compile("other caches <a href=\"/seek/nearest\\.aspx\\?u=(.*?)\">hidden</a> or");
+ final static Pattern PATTERN_FOUND = Pattern.compile("ctl00_ContentBody_GeoNav_logText\">(Found It|Attended)");
+ final static Pattern PATTERN_FOUND_ALTERNATIVE = Pattern.compile("<div class=\"StatusInformationWidget FavoriteWidget\"");
+ final static Pattern PATTERN_OWNER_DISPLAYNAME = Pattern.compile("<div id=\"ctl00_ContentBody_mcd1\">[^<]+<a href=\"[^\"]+\">([^<]+)</a>");
+ final static Pattern PATTERN_TYPE = Pattern.compile("<a href=\"/seek/nearest.aspx\\?tx=([0-9a-f-]+)");
+ final static Pattern PATTERN_HIDDEN = Pattern.compile("<div id=\"ctl00_ContentBody_mcd2\">\\W*Hidden[\\s:]*([^<]+?)</div>");
+ final static Pattern PATTERN_HIDDENEVENT = Pattern.compile("Event\\s*Date\\s*:\\s*([^<]+)<div id=\"calLinks\">", Pattern.DOTALL);
+ final static Pattern PATTERN_FAVORITE = Pattern.compile("<div id=\"pnlFavoriteCache\">"); // without 'class="hideMe"' inside the tag !
+ final static Pattern PATTERN_FAVORITECOUNT = Pattern.compile("<span class=\"favorite-value\">\\D*([0-9]+?)\\D*</span>");
+ final static Pattern PATTERN_COUNTLOGS = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p(.+?)</p></span>");
/** Two groups ! */
- public final static Pattern PATTERN_COUNTLOG = Pattern.compile("<img src=\"/images/logtypes/([0-9]+)\\.png\"[^>]+> (\\d*[,.]?\\d+)");
- public static final Pattern PATTERN_PREMIUMMEMBERS = Pattern.compile("<p class=\"Warning NoBottomSpacing\">This is a Premium Member Only cache.</p>");
- public final static Pattern PATTERN_ATTRIBUTES = Pattern.compile("Attributes\\s*</h3>[^<]*<div class=\"WidgetBody\">((?:[^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+?)[^<]*<p");
+ final static Pattern PATTERN_COUNTLOG = Pattern.compile("<img src=\"/images/logtypes/([0-9]+)\\.png\"[^>]+> (\\d*[,.]?\\d+)");
+ static final Pattern PATTERN_PREMIUMMEMBERS = Pattern.compile("<p class=\"Warning NoBottomSpacing\">This is a Premium Member Only cache.</p>");
+ final static Pattern PATTERN_ATTRIBUTES = Pattern.compile("Attributes\\s*</h3>[^<]*<div class=\"WidgetBody\">((?:[^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+?)[^<]*<p");
/** Two groups ! */
- public final static Pattern PATTERN_ATTRIBUTESINSIDE = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+?)\"");
- public final static Pattern PATTERN_SPOILER_IMAGE = Pattern.compile("<a href=\"(http://imgcdn\\.geocaching\\.com[^.]+\\.(jpg|jpeg|png|gif))\"[^>]+>([^<]+)</a>(?:<br />([^<]+)<br /><br />)?");
- public final static Pattern PATTERN_INVENTORY = Pattern.compile("<span id=\"ctl00_ContentBody_uxTravelBugList_uxInventoryLabel\">\\W*Inventory[^<]*</span>[^<]*</h3>[^<]*<div class=\"WidgetBody\">([^<]*<ul>(([^<]*<li>[^<]*<a href=\"[^\"]+\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>[^<]+<\\/span>[^<]*<\\/a>[^<]*<\\/li>)+)[^<]*<\\/ul>)?");
- public final static Pattern PATTERN_INVENTORYINSIDE = Pattern.compile("[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>");
- public final static Pattern PATTERN_WATCHLIST = Pattern.compile(Pattern.quote("watchlist.aspx") + ".{1,50}" + Pattern.quote("action=rem"));
- public final static Pattern PATTERN_RELATED_WEB_PAGE = Pattern.compile("id=\"ctl00_ContentBody_uxCacheUrl\" title=\"Related Web Page\" href=\"(.*?)\">");
+ final static Pattern PATTERN_ATTRIBUTESINSIDE = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+?)\"");
+ final static Pattern PATTERN_SPOILER_IMAGE = Pattern.compile("<a href=\"(http://img(?:cdn)?\\.geocaching\\.com[^.]+\\.(jpg|jpeg|png|gif))\"[^>]+>([^<]+)</a>(?:<br />([^<]+)<br /><br />)?");
+ final static Pattern PATTERN_INVENTORY = Pattern.compile("<span id=\"ctl00_ContentBody_uxTravelBugList_uxInventoryLabel\">\\W*Inventory[^<]*</span>[^<]*</h3>[^<]*<div class=\"WidgetBody\">([^<]*<ul>(([^<]*<li>[^<]*<a href=\"[^\"]+\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>[^<]+<\\/span>[^<]*<\\/a>[^<]*<\\/li>)+)[^<]*<\\/ul>)?");
+ final static Pattern PATTERN_INVENTORYINSIDE = Pattern.compile("[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>");
+ final static Pattern PATTERN_WATCHLIST = Pattern.compile(Pattern.quote("watchlist.aspx") + ".{1,50}" + Pattern.quote("action=rem"));
+ final static Pattern PATTERN_RELATED_WEB_PAGE = Pattern.compile("id=\"ctl00_ContentBody_uxCacheUrl\" title=\"Related Web Page\" href=\"(.*?)\">");
// Info box top-right
- public static final Pattern PATTERN_LOGIN_NAME = Pattern.compile("\"SignedInProfileLink\">(.*?)</a>");
- public static final Pattern PATTERN_MEMBER_STATUS = Pattern.compile("<span id=\"ctl00_litPMLevel\">([^<]+)</span>");
- public static final String MEMBER_STATUS_RENEW = "<a id=\"ctl00_hlRenew";
- public static final String MEMBER_STATUS_PM = "Premium Member";
+ public static final Pattern PATTERN_LOGIN_NAME = Pattern.compile("class=\"li-user-info\"[^>]*>.*?<span>(.*?)</span>", Pattern.DOTALL);
+ public static final Pattern PATTERN_MEMBERSHIP = Pattern.compile("<dl class=\"membership-details\">.*?<dt>Membership</dt>.*?<dd>\\s*(\\p{Alpha}+)\\s*</dd>", Pattern.DOTALL);
+ public static final String MEMBER_STATUS_PREMIUM = "Premium";
+ public static final String MEMBER_STATUS_CHARTER = "Charter";
/** Use replaceAll("[,.]","") on the resulting string before converting to an int */
- public static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("<strong[^>]*>.*?([\\d,.]+) Caches? Found", Pattern.DOTALL);
- public static final Pattern PATTERN_AVATAR_IMAGE_PROFILE_PAGE = Pattern.compile("src=\"(https?://(imgcdn\\.geocaching\\.com|[^>\"]+\\.cloudfront\\.net)/avatar/[0-9a-f-]+\\.jpg)\"[^>]*alt=\"");
- public static final Pattern PATTERN_LOGIN_NAME_LOGIN_PAGE = Pattern.compile("ctl00_ContentBody_lbUsername\">.*<strong>(.*)</strong>");
- public static final Pattern PATTERN_CUSTOMDATE = Pattern.compile("<option selected=\"selected\" value=\"([ /.Mdy-]+)\">");
- public static final Pattern PATTERN_MAP_LOGGED_IN = Pattern.compile("<a href=\"https?://www.geocaching.com/my/\" class=\"CommonUsername\"");
+ static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("<span[^>]*>.*?([\\d,.]+) Finds?", Pattern.DOTALL);
+ static final Pattern PATTERN_AVATAR_IMAGE_PROFILE_PAGE = Pattern.compile("src=\"(https?://(img(?:cdn)?\\.geocaching\\.com|[^>\"]+\\.cloudfront\\.net)/avatar/[0-9a-f-]+\\.jpg)\"[^>]*alt=\"");
+ static final Pattern PATTERN_LOGIN_NAME_LOGIN_PAGE = Pattern.compile("ctl00_ContentBody_lbUsername\">.*<strong>(.*)</strong>");
+ static final Pattern PATTERN_CUSTOMDATE = Pattern.compile("<option selected=\"selected\" value=\"([ /.Mdy-]+)\">");
+ static final Pattern PATTERN_HOME_LOCATION = Pattern.compile("<input class=\"search-coordinates\"[^>]* value=\"(.*?)\"");
+ static final Pattern PATTERN_MAP_LOGGED_IN = Pattern.compile("<a href=\"https?://www.geocaching.com/my/\" class=\"CommonUsername\"");
/**
* Patterns for parsing trackables
*/
- public final static Pattern PATTERN_TRACKABLE_GUID = Pattern.compile("<a id=\"ctl00_ContentBody_lnkPrint\" title=\"[^\"]*\" href=\".*sheet\\.aspx\\?guid=([a-z0-9\\-]+)\"[^>]*>[^<]*</a>");
- public final static Pattern PATTERN_TRACKABLE_GEOCODE = Pattern.compile("<strong>(TB[0-9A-Z]+)[^<]*</strong> to reference this item.");
+ final static Pattern PATTERN_TRACKABLE_GUID = Pattern.compile("<a id=\"ctl00_ContentBody_lnkPrint\" title=\"[^\"]*\" href=\".*sheet\\.aspx\\?guid=([a-z0-9\\-]+)\"[^>]*>[^<]*</a>");
+ final static Pattern PATTERN_TRACKABLE_GEOCODE = Pattern.compile("<strong>(TB[0-9A-Z]+)[^<]*</strong> to reference this item.");
// multiple error codes, depending on the search term for the trackable code
- public final static String ERROR_TB_DOES_NOT_EXIST = "does not exist in the system";
- public final static String ERROR_TB_ELEMENT_EXCEPTION = "ElementNotFound Exception";
- public final static String ERROR_TB_ARITHMETIC_OVERFLOW = "operation resulted in an overflow";
- public final static String ERROR_TB_NOT_ACTIVATED = "hasn't been activated";
+ final static String ERROR_TB_DOES_NOT_EXIST = "does not exist in the system";
+ final static String ERROR_TB_ELEMENT_EXCEPTION = "ElementNotFound Exception";
+ final static String ERROR_TB_ARITHMETIC_OVERFLOW = "operation resulted in an overflow";
+ final static String ERROR_TB_NOT_ACTIVATED = "hasn't been activated";
/**
* some parts of the webpage don't correctly encode the name, therefore this pattern must be checked with a
* trackable name that needs HTML encoding
*/
- public final static Pattern PATTERN_TRACKABLE_NAME = Pattern.compile("<span id=\"ctl00_ContentBody_lbHeading\">(.*?)</span>");
+ final static Pattern PATTERN_TRACKABLE_NAME = Pattern.compile("<span id=\"ctl00_ContentBody_lbHeading\">(.*?)</span>");
/** Two groups ! */
- public final static Pattern PATTERN_TRACKABLE_OWNER = Pattern.compile("<a id=\"ctl00_ContentBody_BugDetails_BugOwner\"[^>]+href=\"https?://www.geocaching.com/profile/\\?guid=(.*?)\">(.*?)</a>");
- public final static Pattern PATTERN_TRACKABLE_RELEASES = Pattern.compile("<dt>\\W*Released:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugReleaseDate\">([^<]+)<\\/span>[^<]*</dd>");
- public final static Pattern PATTERN_TRACKABLE_ORIGIN = Pattern.compile("<dt>\\W*Origin:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugOrigin\">([^<]+)<\\/span>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_OWNER = Pattern.compile("<a id=\"ctl00_ContentBody_BugDetails_BugOwner\"[^>]+href=\"https?://www.geocaching.com/profile/\\?guid=(.*?)\">(.*?)</a>");
+ final static Pattern PATTERN_TRACKABLE_RELEASES = Pattern.compile("<dt>\\W*Released:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugReleaseDate\">([^<]+)<\\/span>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_ORIGIN = Pattern.compile("<dt>\\W*Origin:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugOrigin\">([^<]+)<\\/span>[^<]*</dd>");
/** Two groups ! */
- public final static Pattern PATTERN_TRACKABLE_SPOTTEDCACHE = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" title=\"[^\"]*\" href=\"[^\"]*/seek/cache_details.aspx\\?guid=([a-z0-9\\-]+)\">In ([^<]+)</a>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_SPOTTEDCACHE = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" title=\"[^\"]*\" href=\"[^\"]*/seek/cache_details.aspx\\?guid=([a-z0-9\\-]+)\">In ([^<]+)</a>[^<]*</dd>");
/** Two groups ! */
- public final static Pattern PATTERN_TRACKABLE_SPOTTEDUSER = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">In the hands of ([^<]+).</a>[^<]*</dd>");
- public final static Pattern PATTERN_TRACKABLE_SPOTTEDUNKNOWN = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">Unknown Location[^<]*</a>[^<]*</dd>");
- public final static Pattern PATTERN_TRACKABLE_SPOTTEDOWNER = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">In the hands of the owner[^<]*</a>[^<]*</dd>");
- public final static Pattern PATTERN_TRACKABLE_GOAL = Pattern.compile("<div id=\"TrackableGoal\">[^<]*<p>(.*?)</p>[^<]*</div>", Pattern.DOTALL);
+ final static Pattern PATTERN_TRACKABLE_SPOTTEDUSER = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">In the hands of ([^<]+).</a>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_SPOTTEDUNKNOWN = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">Unknown Location[^<]*</a>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_SPOTTEDOWNER = Pattern.compile("<dt>\\W*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">In the hands of the owner[^<]*</a>[^<]*</dd>");
+ final static Pattern PATTERN_TRACKABLE_GOAL = Pattern.compile("<div id=\"TrackableGoal\">[^<]*<p>(.*?)</p>[^<]*</div>", Pattern.DOTALL);
/** Four groups */
- public final static Pattern PATTERN_TRACKABLE_DETAILSIMAGE = Pattern.compile("<h3>\\W*About This Item[^<]*</h3>[^<]*<div id=\"TrackableDetails\">([^<]*<p>([^<]*<img id=\"ctl00_ContentBody_BugDetails_BugImage\" class=\"[^\"]+\" src=\"([^\"]+)\"[^>]*>)?[^<]*</p>)?[^<]*<p[^>]*>(.*)</p>[^<]*</div> <div id=\"ctl00_ContentBody_BugDetails_uxAbuseReport\">");
- public final static Pattern PATTERN_TRACKABLE_ICON = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>");
- public final static Pattern PATTERN_TRACKABLE_TYPE = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>");
- public final static Pattern PATTERN_TRACKABLE_DISTANCE = Pattern.compile("<h4[^>]*\\W*Tracking History \\(([0-9.,]+(km|mi))[^\\)]*\\)");
- public final static Pattern PATTERN_TRACKABLE_LOG = Pattern.compile("<tr class=\"Data BorderTop .+?/images/logtypes/([^.]+)\\.png[^>]+>&nbsp;([^<]+)</td>.+?guid.+?>([^<]+)</a>.+?(?:guid=([^\"]+)\">(<span[^>]+>)?([^<]+)</.+?)?<td colspan=\"4\">\\s*<div>(.*?)</div>\\s*(?:<ul.+?ul>)?\\s*</td>\\s*</tr>");
- public final static Pattern PATTERN_TRACKABLE_LOG_IMAGES = Pattern.compile("<li><a href=\"([^\"]+)\".+?LogImgTitle.+?>([^<]+)</");
+ final static Pattern PATTERN_TRACKABLE_DETAILSIMAGE = Pattern.compile("<h3>\\W*About This Item[^<]*</h3>[^<]*<div id=\"TrackableDetails\">([^<]*<p>([^<]*<img id=\"ctl00_ContentBody_BugDetails_BugImage\" class=\"[^\"]+\" src=\"([^\"]+)\"[^>]*>)?[^<]*</p>)?[^<]*<p[^>]*>(.*)</p>[^<]*</div> <div id=\"ctl00_ContentBody_BugDetails_uxAbuseReport\">");
+ final static Pattern PATTERN_TRACKABLE_ICON = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>");
+ final static Pattern PATTERN_TRACKABLE_TYPE = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>");
+ final static Pattern PATTERN_TRACKABLE_DISTANCE = Pattern.compile("<h4[^>]*\\W*Tracking History \\(([0-9.,]+(km|mi))[^\\)]*\\)");
+ final static Pattern PATTERN_TRACKABLE_LOG = Pattern.compile("<tr class=\"Data BorderTop .+?/images/logtypes/([^.]+)\\.png[^>]+>&nbsp;([^<]+)</td>.+?guid.+?>([^<]+)</a>.+?(?:guid=([^\"]+)\">(<span[^>]+>)?([^<]+)</.+?)?<td colspan=\"4\">\\s*<div>(.*?)</div>\\s*(?:<ul.+?ul>)?\\s*</td>\\s*</tr>");
+ final static Pattern PATTERN_TRACKABLE_LOG_IMAGES = Pattern.compile("<li><a href=\"([^\"]+)\".+?LogImgTitle.+?>([^<]*)</");
/**
* Patterns for parsing the result of a search (next)
*/
- public final static Pattern PATTERN_SEARCH_TYPE = Pattern.compile("<td class=\"Merge\">.*?<img src=\"[^\"]*/images/wpttypes/[^.]+\\.gif\" alt=\"([^\"]+)\" title=\"[^\"]+\"[^>]*>[^<]*</a>");
- public final static Pattern PATTERN_SEARCH_GUIDANDDISABLED = Pattern.compile("SearchResultsWptType.*?<a href=\"[^\"]*\" class=\"lnk ([^\"]*)\"><span>([^<]*)</span>[^|]*[|][^|]*[|]([^<]*)<");
+ final static Pattern PATTERN_SEARCH_TYPE = Pattern.compile("<td class=\"Merge\">.*?<img src=\"[^\"]*/images/wpttypes/[^.]+\\.gif\" alt=\"([^\"]+)\" title=\"[^\"]+\"[^>]*>[^<]*</a>");
+ final static Pattern PATTERN_SEARCH_GUIDANDDISABLED = Pattern.compile("SearchResultsWptType.*?<a href=\"[^\"]*\" class=\"lnk ([^\"]*)\"><span>([^<]*)</span>[^|]*[|][^|]*[|]([^<]*)<");
/** Two groups **/
- public final static Pattern PATTERN_SEARCH_TRACKABLES = Pattern.compile("<a id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxTravelBugList\" class=\"tblist\" data-tbcount=\"([0-9]+)\" data-id=\"[^\"]*\"[^>]*>(.*)</a>");
+ final static Pattern PATTERN_SEARCH_TRACKABLES = Pattern.compile("<a id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxTravelBugList\" class=\"tblist\" data-tbcount=\"([0-9]+)\" data-id=\"[^\"]*\"[^>]*>(.*)</a>");
/** Second group used */
- public final static Pattern PATTERN_SEARCH_TRACKABLESINSIDE = Pattern.compile("(<img src=\"[^\"]+\" alt=\"([^\"]+)\" title=\"[^\"]*\" />[^<]*)");
- public final static Pattern PATTERN_SEARCH_DIRECTION_DISTANCE = Pattern.compile("<img src=\"/images/icons/compass/([^\\.]+)\\.gif\"[^>]*>[^<]*<br />([^<]+)</span>");
- public final static Pattern PATTERN_SEARCH_DIFFICULTY_TERRAIN = Pattern.compile("<span class=\"small\">([0-5]([\\.,]5)?)/([0-5]([\\.,]5)?)</span><br />");
- public final static Pattern PATTERN_SEARCH_CONTAINER = Pattern.compile("<img src=\"/images/icons/container/([^\\.]+)\\.gif\"");
- public final static Pattern PATTERN_SEARCH_GEOCODE = Pattern.compile("\\|\\W*(GC[0-9A-Z]+)[^\\|]*\\|");
- public final static Pattern PATTERN_SEARCH_ID = Pattern.compile("name=\"CID\"[^v]*value=\"(\\d+)\"");
- public final static Pattern PATTERN_SEARCH_FAVORITE = Pattern.compile("favorite-rank\">([0-9,.]+)</span>");
- public final static Pattern PATTERN_SEARCH_TOTALCOUNT = Pattern.compile("<span>Total Records\\D*(\\d+)<");
- public final static Pattern PATTERN_SEARCH_RECAPTCHA = Pattern.compile("<script[^>]*src=\"[^\"]*/recaptcha/api/challenge\\?k=([^\"]+)\"[^>]*>");
+ final static Pattern PATTERN_SEARCH_TRACKABLESINSIDE = Pattern.compile("(<img src=\"[^\"]+\" alt=\"([^\"]+)\" title=\"[^\"]*\" />[^<]*)");
+ final static Pattern PATTERN_SEARCH_DIRECTION_DISTANCE = Pattern.compile("<img src=\"/images/icons/compass/([^\\.]+)\\.gif\"[^>]*>[^<]*<br />([^<]+)</span>");
+ final static Pattern PATTERN_SEARCH_DIFFICULTY_TERRAIN = Pattern.compile("<span class=\"small\">([0-5]([\\.,]5)?)/([0-5]([\\.,]5)?)</span><br />");
+ final static Pattern PATTERN_SEARCH_CONTAINER = Pattern.compile("<img src=\"/images/icons/container/([^\\.]+)\\.gif\"");
+ final static Pattern PATTERN_SEARCH_GEOCODE = Pattern.compile("\\|\\W*(GC[0-9A-Z]+)[^\\|]*\\|");
+ final static Pattern PATTERN_SEARCH_ID = Pattern.compile("name=\"CID\"[^v]*value=\"(\\d+)\"");
+ final static Pattern PATTERN_SEARCH_FAVORITE = Pattern.compile("favorite-rank\">([0-9,.]+)</span>");
+ final static Pattern PATTERN_SEARCH_TOTALCOUNT = Pattern.compile("<span>Total Records\\D*(\\d+)<");
+ final static Pattern PATTERN_SEARCH_RECAPTCHA = Pattern.compile("<script[^>]*src=\"[^\"]*/recaptcha/api/challenge\\?k=([^\"]+)\"[^>]*>");
public final static Pattern PATTERN_SEARCH_RECAPTCHACHALLENGE = Pattern.compile("challenge : '([^']+)'");
- public final static Pattern PATTERN_SEARCH_HIDDEN_DATE = Pattern.compile("<td style=\"width:70px\">[^<]+<span class=\"small\">([^<]+)</span>");
+ final static Pattern PATTERN_SEARCH_HIDDEN_DATE = Pattern.compile("<td style=\"width:70px\">[^<]+<span class=\"small\">([^<]+)</span>");
+ final static Pattern PATTERN_SEARCH_POST_ACTION = Pattern.compile("<form name=\"aspnetForm\" method=\"post\" action=\"(.*)\" id=\"aspnetForm\"");
/**
* Patterns for waypoints
*/
- public final static Pattern PATTERN_WPTYPE = Pattern.compile("\\/wpttypes\\/sm\\/(.+)\\.jpg");
- public final static Pattern PATTERN_WPPREFIXORLOOKUPORLATLON = Pattern.compile(">([^<]*<[^>]+>)?([^<]+)(<[^>]+>[^<]*)?<\\/td>");
- public final static Pattern PATTERN_WPNAME = Pattern.compile(">[^<]*<a[^>]+>([^<]*)<\\/a>");
- public final static Pattern PATTERN_WPNOTE = Pattern.compile("colspan=\"6\">(.*)" + Pattern.quote("</td>"), Pattern.DOTALL);
+ final static Pattern PATTERN_WPTYPE = Pattern.compile("\\/wpttypes\\/sm\\/(.+)\\.jpg");
+ final static Pattern PATTERN_WPPREFIXORLOOKUPORLATLON = Pattern.compile(">([^<]*<[^>]+>)?([^<]+)(<[^>]+>[^<]*)?<\\/td>");
+ final static Pattern PATTERN_WPNAME = Pattern.compile(">[^<]*<a[^>]+>([^<]*)<\\/a>");
+ final static Pattern PATTERN_WPNOTE = Pattern.compile("colspan=\"6\">(.*)" + Pattern.quote("</td>"), Pattern.DOTALL);
/**
* Patterns for different purposes
*/
/** replace line break and paragraph tags */
- public final static Pattern PATTERN_LINEBREAK = Pattern.compile("<(br|p)[^>]*>");
- public final static Pattern PATTERN_TYPEBOX = Pattern.compile("<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$ddLogType\" id=\"ctl00_ContentBody_LogBookPanel1_ddLogType\"[^>]*>"
+ final static Pattern PATTERN_LINEBREAK = Pattern.compile("<(br|p)[^>]*>");
+ final static Pattern PATTERN_TYPEBOX = Pattern.compile("<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$ddLogType\" id=\"ctl00_ContentBody_LogBookPanel1_ddLogType\"[^>]*>"
+ "(([^<]*<option[^>]*>[^<]+</option>)+)[^<]*</select>", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_TYPE2 = Pattern.compile("<option( selected=\"selected\")? value=\"(\\d+)\">[^<]+</option>", Pattern.CASE_INSENSITIVE);
+ final static Pattern PATTERN_TYPE2 = Pattern.compile("<option( selected=\"selected\")? value=\"(\\d+)\">[^<]+</option>", Pattern.CASE_INSENSITIVE);
// FIXME: pattern is over specified
- public final static Pattern PATTERN_TRACKABLE = Pattern.compile("<tr id=\"ctl00_ContentBody_LogBookPanel1_uxTrackables_repTravelBugs_ctl[0-9]+_row\"[^>]*>"
+ final static Pattern PATTERN_TRACKABLE = Pattern.compile("<tr id=\"ctl00_ContentBody_LogBookPanel1_uxTrackables_repTravelBugs_ctl[0-9]+_row\"[^>]*>"
+ "[^<]*<td>[^<]*<a href=\"[^\"]+\">([A-Z0-9]+)</a>[^<]*</td>[^<]*<td>([^<]+)</td>[^<]*<td>"
+ "[^<]*<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$uxTrackables\\$repTravelBugs\\$ctl([0-9]+)\\$ddlAction\"[^>]*>"
+ "([^<]*<option value=\"([0-9]+)(_[a-z]+)?\">[^<]+</option>)+"
+ "[^<]*</select>[^<]*</td>[^<]*</tr>", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_MAINTENANCE = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_OK1 = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
- public final static Pattern PATTERN_OK2 = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE);
- public final static Pattern PATTERN_IMAGE_UPLOAD_URL = Pattern.compile("title=\"Click for Larger Image\"\\s*src=\"(.*?)\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
- public final static Pattern PATTERN_VIEWSTATEFIELDCOUNT = Pattern.compile("id=\"__VIEWSTATEFIELDCOUNT\"[^(value)]+value=\"(\\d+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
- public final static Pattern PATTERN_VIEWSTATES = Pattern.compile("id=\"__VIEWSTATE(\\d*)\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
- public final static Pattern PATTERN_USERTOKEN = Pattern.compile("userToken\\s*=\\s*'([^']+)'");
- public final static Pattern PATTERN_LIST_PQ = Pattern.compile(Pattern.quote("(") + "(\\d+)" + Pattern.quote(")") + ".+?guid=(.+?)\".*?title=\"(.+?)\"");
+ final static Pattern PATTERN_MAINTENANCE = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE);
+ final static Pattern PATTERN_OK1 = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final static Pattern PATTERN_OK2 = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE);
+ final static Pattern PATTERN_IMAGE_UPLOAD_URL = Pattern.compile("title=\"Click for Larger Image\"\\s*src=\"(.*?)\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final static Pattern PATTERN_VIEWSTATEFIELDCOUNT = Pattern.compile("id=\"__VIEWSTATEFIELDCOUNT\"[^(value)]+value=\"(\\d+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final static Pattern PATTERN_VIEWSTATES = Pattern.compile("id=\"__VIEWSTATE(\\d*)\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final static Pattern PATTERN_USERTOKEN = Pattern.compile("userToken\\s*=\\s*'([^']+)'");
+ final static Pattern PATTERN_LIST_PQ = Pattern.compile(Pattern.quote("(") + "(\\d+)" + Pattern.quote(")") + ".+?guid=(.+?)\".*?title=\"(.+?)\"");
/** Live Map since 14.02.2012 */
- public final static Pattern PATTERN_USERSESSION = Pattern.compile("UserSession\\('([^']+)'");
- public final static Pattern PATTERN_SESSIONTOKEN = Pattern.compile("sessionToken:'([^']+)'");
+ final static Pattern PATTERN_USERSESSION = Pattern.compile("UserSession\\('([^']+)'");
+ final static Pattern PATTERN_SESSIONTOKEN = Pattern.compile("sessionToken:'([^']+)'");
- public final static Pattern PATTERN_LOG_IMAGE_UPLOAD = Pattern.compile("/seek/upload\\.aspx\\?LID=(\\d+)", Pattern.CASE_INSENSITIVE);
+ static final Pattern PATTERN_LOG_GUID = Pattern.compile("<a id=\"ctl00_ContentBody_LogBookPanel1_WaypointLink\"[^>]* href=\"https?://www\\.geocaching\\.com/seek/cache_details\\.aspx\\?guid=([0-9a-f-]+)\"");
+ final static Pattern PATTERN_LOG_IMAGE_UPLOAD = Pattern.compile("/seek/upload\\.aspx\\?LID=(\\d+)", Pattern.CASE_INSENSITIVE);
- public final static String STRING_PREMIUMONLY_2 = "Sorry, the owner of this listing has made it viewable to Premium Members only.";
- public final static String STRING_PREMIUMONLY_1 = "has chosen to make this cache listing visible to Premium Members only.";
- public final static String STRING_UNPUBLISHED_OTHER = "you cannot view this cache listing until it has been published";
- public final static String STRING_UNPUBLISHED_FROM_SEARCH = "class=\"UnpublishedCacheSearchWidget"; // do not include closing brace as the CSS can contain additional styles
- public final static String STRING_UNKNOWN_ERROR = "An Error Has Occurred";
- public final static String STRING_DISABLED = "<li>This cache is temporarily unavailable.";
- public final static String STRING_ARCHIVED = "<li>This cache has been archived,";
- public final static String STRING_CACHEDETAILS = "id=\"cacheDetails\"";
+ final static String STRING_PREMIUMONLY_2 = "Sorry, the owner of this listing has made it viewable to Premium Members only.";
+ final static String STRING_PREMIUMONLY_1 = "has chosen to make this cache listing visible to Premium Members only.";
+ final static String STRING_UNPUBLISHED_OTHER = "you cannot view this cache listing until it has been published";
+ final static String STRING_UNPUBLISHED_FROM_SEARCH = "class=\"UnpublishedCacheSearchWidget"; // do not include closing brace as the CSS can contain additional styles
+ final static String STRING_UNKNOWN_ERROR = "An Error Has Occurred";
+ final static String STRING_DISABLED = "<li>This cache is temporarily unavailable.";
+ final static String STRING_ARCHIVED = "<li>This cache has been archived,";
+ final static String STRING_CACHEDETAILS = "id=\"cacheDetails\"";
/** Number of logs to retrieve from GC.com */
- public final static int NUMBER_OF_LOGS = 35;
+ final static int NUMBER_OF_LOGS = 35;
/** Maximum number of chars for personal note. **/
public final static int PERSONAL_NOTE_MAX_CHARS = 500;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
index bf021b9..bdea155 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.connector.gc;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.R;
@@ -14,9 +15,11 @@ import cgeo.geocaching.loaders.UrlLoader;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.TextUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import android.net.Uri;
@@ -28,24 +31,24 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.List;
-public class GCLoggingManager extends AbstractLoggingManager implements LoaderManager.LoaderCallbacks<String> {
+class GCLoggingManager extends AbstractLoggingManager implements LoaderManager.LoaderCallbacks<String> {
private final LogCacheActivity activity;
private final Geocache cache;
private String[] viewstates;
- private List<TrackableLog> trackables;
+ @NonNull private List<TrackableLog> trackables = Collections.emptyList();
private List<LogType> possibleLogTypes;
private boolean hasLoaderError = true;
- public GCLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ GCLoggingManager(final LogCacheActivity activity, final Geocache cache) {
this.activity = activity;
this.cache = cache;
}
@Nullable
@Override
- public Loader<String> onCreateLoader(int arg0, Bundle arg1) {
+ public Loader<String> onCreateLoader(final int arg0, final Bundle arg1) {
if (!Settings.isLogin()) { // allow offline logging
ActivityMixin.showToast(activity, activity.getResources().getString(R.string.err_login));
return null;
@@ -54,15 +57,24 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
- public void onLoadFinished(Loader<String> arg0, String page) {
-
+ public void onLoadFinished(final Loader<String> arg0, final String page) {
if (page == null) {
hasLoaderError = true;
} else {
-
viewstates = GCLogin.getViewstates(page);
trackables = GCParser.parseTrackableLog(page);
possibleLogTypes = GCParser.parseTypes(page);
+ if (StringUtils.isBlank(cache.getGuid())) {
+ // Acquire the cache GUID from the log page. This will not only complete the information in the database,
+ // but also allow the user to post a rating using GCVote since it requires the GUID to do so.
+ final String guid = TextUtils.getMatch(page, GCConstants.PATTERN_LOG_GUID, null);
+ if (StringUtils.isNotBlank(guid)) {
+ cache.setGuid(guid);
+ DataStore.saveChangedCache(cache);
+ } else {
+ Log.w("Could not acquire GUID from log page for " + cache.getGeocode());
+ }
+ }
hasLoaderError = possibleLogTypes.isEmpty();
}
@@ -71,7 +83,7 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
- public void onLoaderReset(Loader<String> arg0) {
+ public void onLoaderReset(final Loader<String> arg0) {
// nothing to do
}
@@ -81,7 +93,8 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
- public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, String logPassword, List<TrackableLog> trackableLogs) {
+ @NonNull
+ public LogResult postLog(@NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log, @Nullable final String logPassword, @NonNull final List<TrackableLog> trackableLogs) {
try {
final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(cache.getGeocode(), cache.getCacheId(), viewstates, logType,
@@ -96,7 +109,7 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
}
return new LogResult(postResult.left, postResult.right);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCLoggingManager.postLog", e);
}
@@ -104,11 +117,12 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
- public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) {
+ @NonNull
+ public ImageResult postLogImage(final String logId, final String imageCaption, final String imageDescription, final Uri imageUri) {
if (StringUtils.isNotBlank(imageUri.getPath())) {
- ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(logId, imageCaption, imageDescription, imageUri);
+ final ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(logId, imageCaption, imageDescription, imageUri);
return new ImageResult(imageResult.left, imageResult.right);
}
@@ -122,6 +136,7 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
+ @NonNull
public List<TrackableLog> getTrackables() {
if (hasLoaderError) {
return Collections.emptyList();
@@ -130,6 +145,7 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa
}
@Override
+ @NonNull
public List<LogType> getPossibleLogTypes() {
if (hasLoaderError) {
return Collections.emptyList();
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLogin.java b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
index 9f430c0..16de511 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLogin.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
@@ -11,6 +11,7 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
+import cgeo.geocaching.utils.RxUtils;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -22,47 +23,22 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import rx.Observable;
+import rx.functions.Action0;
import android.graphics.drawable.Drawable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
+import java.util.GregorianCalendar;
import java.util.Locale;
-import java.util.Map;
+import java.util.regex.Matcher;
public class GCLogin extends AbstractLogin {
- private static final String DEFAULT_CUSTOM_DATE_FORMAT = "MM/dd/yyyy";
+ private final static String ENGLISH = "<a href=\"#\">English</a>";
- private final static String ENGLISH = "<a href=\"#\">English &#9660;</a>";
-
- private final static Map<String, SimpleDateFormat> GC_CUSTOM_DATE_FORMATS;
- public static final String LANGUAGE_CHANGE_URI = "http://www.geocaching.com/my/souvenirs.aspx";
-
- static {
- final String[] formats = new String[] {
- DEFAULT_CUSTOM_DATE_FORMAT,
- "yyyy-MM-dd",
- "yyyy/MM/dd",
- "dd.MM.yyyy",
- "dd/MMM/yyyy",
- "dd.MMM.yyyy",
- "MMM/dd/yyyy",
- "dd MMM yy",
- "dd/MM/yyyy"
- };
-
- final Map<String, SimpleDateFormat> map = new HashMap<>();
-
- for (final String format : formats) {
- map.put(format, new SimpleDateFormat(format, Locale.ENGLISH));
- }
-
- GC_CUSTOM_DATE_FORMATS = Collections.unmodifiableMap(map);
- }
+ private static final String LANGUAGE_CHANGE_URI = "http://www.geocaching.com/my/souvenirs.aspx";
private GCLogin() {
// singleton
@@ -76,8 +52,14 @@ public class GCLogin extends AbstractLogin {
private static final GCLogin INSTANCE = new GCLogin();
}
+ private static StatusCode resetGcCustomDate(final StatusCode statusCode) {
+ Settings.setGcCustomDate(GCConstants.DEFAULT_GC_DATE);
+ return statusCode;
+ }
+
@Override
- protected StatusCode login(boolean retry) {
+ @NonNull
+ protected StatusCode login(final boolean retry) {
final ImmutablePair<String, String> credentials = Settings.getGcCredentials();
final String username = credentials.left;
final String password = credentials.right;
@@ -85,7 +67,7 @@ public class GCLogin extends AbstractLogin {
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
clearLoginInfo();
Log.e("Login.login: No login information stored");
- return StatusCode.NO_LOGIN_INFO_STORED;
+ return resetGcCustomDate(StatusCode.NO_LOGIN_INFO_STORED);
}
setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_working));
@@ -105,6 +87,9 @@ public class GCLogin extends AbstractLogin {
if (switchToEnglish(loginData) && retry) {
return login(false);
}
+ setHomeLocation();
+ refreshMemberStatus();
+ detectGcCustomDate();
return StatusCode.NO_ERROR; // logged in
}
@@ -141,17 +126,20 @@ public class GCLogin extends AbstractLogin {
}
Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
Settings.setCookieStore(Cookies.dumpCookieStore());
+ setHomeLocation();
+ refreshMemberStatus();
+ detectGcCustomDate();
return StatusCode.NO_ERROR; // logged in
}
- if (loginData.contains("Your username/password combination does not match.")) {
+ if (loginData.contains("your username or password is incorrect")) {
Log.i("Failed to log in Geocaching.com as " + username + " because of wrong username/password");
- return StatusCode.WRONG_LOGIN_DATA; // wrong login
+ return resetGcCustomDate(StatusCode.WRONG_LOGIN_DATA); // wrong login
}
if (loginData.contains("You must validate your account before you can log in.")) {
Log.i("Failed to log in Geocaching.com as " + username + " because account needs to be validated first");
- return StatusCode.UNVALIDATED_ACCOUNT;
+ return resetGcCustomDate(StatusCode.UNVALIDATED_ACCOUNT);
}
Log.i("Failed to log in Geocaching.com as " + username + " for some unknown reason");
@@ -160,7 +148,7 @@ public class GCLogin extends AbstractLogin {
return login(false);
}
- return StatusCode.UNKNOWN_ERROR; // can't login
+ return resetGcCustomDate(StatusCode.UNKNOWN_ERROR); // can't login
}
public StatusCode logout() {
@@ -175,14 +163,16 @@ public class GCLogin extends AbstractLogin {
return StatusCode.NO_ERROR;
}
+ private static String removeDotAndComma(final String str) {
+ return StringUtils.replaceChars(str, ".,", null);
+ }
/**
* Check if the user has been logged in when he retrieved the data.
*
- * @param page
* @return <code>true</code> if user is logged in, <code>false</code> otherwise
*/
- public boolean getLoginStatus(@Nullable final String page) {
+ boolean getLoginStatus(@Nullable final String page) {
if (StringUtils.isBlank(page)) {
Log.e("Login.checkLogin: No page given");
return false;
@@ -201,15 +191,11 @@ public class GCLogin extends AbstractLogin {
setActualUserName(TextUtils.getMatch(page, GCConstants.PATTERN_LOGIN_NAME, true, "???"));
int cachesCount = 0;
try {
- cachesCount = Integer.parseInt(TextUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0").replaceAll("[,.]", ""));
+ cachesCount = Integer.parseInt(removeDotAndComma(TextUtils.getMatch(page, GCConstants.PATTERN_CACHES_FOUND, true, "0")));
} catch (final NumberFormatException e) {
Log.e("getLoginStatus: bad cache count", e);
}
setActualCachesFound(cachesCount);
- Settings.setGCMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
- if (page.contains(GCConstants.MEMBER_STATUS_RENEW)) {
- Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
- }
return true;
}
@@ -231,7 +217,7 @@ public class GCLogin extends AbstractLogin {
* @param previousPage the content of the last loaded page
* @return <code>true</code> if a switch was necessary and succesfully performed (non-English -> English)
*/
- private boolean switchToEnglish(String previousPage) {
+ private boolean switchToEnglish(final String previousPage) {
if (previousPage != null && previousPage.contains(ENGLISH)) {
Log.i("Geocaching.com language already set to English");
// get find count
@@ -256,21 +242,16 @@ public class GCLogin extends AbstractLogin {
return false;
}
- public Observable<Drawable> downloadAvatarAndGetMemberStatus() {
+ public Observable<Drawable> downloadAvatar() {
try {
final String responseData = StringUtils.defaultString(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
final String profile = TextUtils.replaceWhitespace(responseData);
- Settings.setGCMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
- if (profile.contains(GCConstants.MEMBER_STATUS_RENEW)) {
- Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
- }
-
- setActualCachesFound(Integer.parseInt(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
+ setActualCachesFound(Integer.parseInt(removeDotAndComma(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1"))));
final String avatarURL = TextUtils.getMatch(profile, GCConstants.PATTERN_AVATAR_IMAGE_PROFILE_PAGE, false, null);
if (avatarURL != null) {
- final HtmlImage imgGetter = new HtmlImage("", false, 0, false);
+ final HtmlImage imgGetter = new HtmlImage(HtmlImage.SHARED, false, 0, false);
return imgGetter.fetchDrawable(avatarURL.replace("avatar", "user/large")).cast(Drawable.class);
}
// No match? There may be no avatar set by user.
@@ -281,12 +262,47 @@ public class GCLogin extends AbstractLogin {
return null;
}
+ @Nullable
+ static String retrieveHomeLocation() {
+ final String result = Network.getResponseData(Network.getRequest("https://www.geocaching.com/account/settings/homelocation"));
+ return TextUtils.getMatch(result, GCConstants.PATTERN_HOME_LOCATION, null);
+ }
+
+ private static void setHomeLocation() {
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ final String homeLocationStr = retrieveHomeLocation();
+ if (StringUtils.isNotBlank(homeLocationStr) && !StringUtils.equals(homeLocationStr, Settings.getHomeLocation())) {
+ assert homeLocationStr != null;
+ Log.i("Setting home location to " + homeLocationStr);
+ Settings.setHomeLocation(homeLocationStr);
+ }
+ }
+ });
+ }
+
+ private static void refreshMemberStatus() {
+ RxUtils.networkScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ final String page = StringUtils.defaultString(Network.getResponseData(Network.getRequest("https://www.geocaching.com/account/settings/membership")));
+ final Matcher match = GCConstants.PATTERN_MEMBERSHIP.matcher(page);
+ if (match.find()) {
+ Log.d("Setting member status to " + match.group(1));
+ Settings.setGCMemberStatus(match.group(1));
+ } else {
+ Log.w("Cannot determine member status");
+ }
+ }
+ });
+ }
+
/**
* Detect user date settings on geocaching.com
*/
- public static void detectGcCustomDate() {
-
- final String result = Network.getResponseData(Network.getRequest("http://www.geocaching.com/account/ManagePreferences.aspx"));
+ private static void detectGcCustomDate() {
+ final String result = Network.getResponseData(Network.getRequest("https://www.geocaching.com/account/settings/preferences"));
if (null == result) {
Log.w("Login.detectGcCustomDate: result is null");
@@ -300,40 +316,15 @@ public class GCLogin extends AbstractLogin {
}
public static Date parseGcCustomDate(final String input, final String format) throws ParseException {
- if (StringUtils.isBlank(input)) {
- throw new ParseException("Input is null", 0);
- }
-
- final String trimmed = input.trim();
-
- if (GC_CUSTOM_DATE_FORMATS.containsKey(format)) {
- try {
- return GC_CUSTOM_DATE_FORMATS.get(format).parse(trimmed);
- } catch (final ParseException e) {
- }
- }
-
- for (final SimpleDateFormat sdf : GC_CUSTOM_DATE_FORMATS.values()) {
- try {
- return sdf.parse(trimmed);
- } catch (final ParseException e) {
- }
- }
-
- throw new ParseException("No matching pattern", 0);
+ return new SimpleDateFormat(format, Locale.ENGLISH).parse(input.trim());
}
- public static Date parseGcCustomDate(final String input) throws ParseException {
+ static Date parseGcCustomDate(final String input) throws ParseException {
return parseGcCustomDate(input, Settings.getGcCustomDate());
}
- public static SimpleDateFormat getCustomGcDateFormat() {
- final String format = Settings.getGcCustomDate();
- if (GC_CUSTOM_DATE_FORMATS.containsKey(format)) {
- return GC_CUSTOM_DATE_FORMATS.get(format);
- }
-
- return GC_CUSTOM_DATE_FORMATS.get(DEFAULT_CUSTOM_DATE_FORMAT);
+ static String formatGcCustomDate(final int year, final int month, final int day) {
+ return new SimpleDateFormat(Settings.getGcCustomDate(), Locale.ENGLISH).format(new GregorianCalendar(year, month - 1, day).getTime());
}
/**
@@ -341,7 +332,7 @@ public class GCLogin extends AbstractLogin {
* - Array is null
* - or all elements are null or empty strings
*/
- public static boolean isEmpty(String[] a) {
+ public static boolean isEmpty(final String[] a) {
if (a == null) {
return true;
}
@@ -359,7 +350,7 @@ public class GCLogin extends AbstractLogin {
*
* @return String[] with all view states
*/
- public static String[] getViewstates(String page) {
+ public static String[] getViewstates(final String page) {
// Get the number of viewstates.
// If there is only one viewstate, __VIEWSTATEFIELDCOUNT is not present
@@ -407,7 +398,7 @@ public class GCLogin extends AbstractLogin {
/**
* put viewstates into request parameters
*/
- public static void putViewstates(final Parameters params, final String[] viewstates) {
+ static void putViewstates(final Parameters params, final String[] viewstates) {
if (ArrayUtils.isEmpty(viewstates)) {
return;
}
@@ -424,17 +415,15 @@ public class GCLogin extends AbstractLogin {
* transfers the viewstates variables from a page (response) to parameters
* (next request)
*/
- public static void transferViewstates(final String page, final Parameters params) {
+ static void transferViewstates(final String page, final Parameters params) {
putViewstates(params, getViewstates(page));
}
/**
* POST HTTP request. Do the request a second time if the user is not logged in
*
- * @param uri
- * @return
*/
- public String postRequestLogged(final String uri, final Parameters params) {
+ String postRequestLogged(final String uri, final Parameters params) {
final String data = Network.getResponseData(Network.postRequest(uri, params));
if (getLoginStatus(data)) {
@@ -452,12 +441,9 @@ public class GCLogin extends AbstractLogin {
/**
* GET HTTP request. Do the request a second time if the user is not logged in
*
- * @param uri
- * @param params
- * @return
*/
@Nullable
- public String getRequestLogged(@NonNull final String uri, @Nullable final Parameters params) {
+ String getRequestLogged(@NonNull final String uri, @Nullable final Parameters params) {
final HttpResponse response = Network.getRequest(uri, params);
final String data = Network.getResponseData(response, canRemoveWhitespace(uri));
@@ -478,8 +464,6 @@ public class GCLogin extends AbstractLogin {
* Unfortunately the cache details page contains user generated whitespace in the personal note, therefore we cannot
* remove the white space from cache details pages.
*
- * @param uri
- * @return
*/
private static boolean canRemoveWhitespace(final String uri) {
return !StringUtils.contains(uri, "cache_details");
@@ -490,8 +474,8 @@ public class GCLogin extends AbstractLogin {
*
* @return first is user session, second is session token
*/
- public @NonNull
- MapTokens getMapTokens() {
+ @NonNull
+ public MapTokens getMapTokens() {
final String data = getRequestLogged(GCConstants.URL_LIVE_MAP, null);
final String userSession = TextUtils.getMatch(data, GCConstants.PATTERN_USERSESSION, "");
final String sessionToken = TextUtils.getMatch(data, GCConstants.PATTERN_SESSIONTOKEN, "");
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index 27ce06e..243d84c 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -1,35 +1,40 @@
package cgeo.geocaching.connector.gc;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
-import cgeo.geocaching.enumerations.LiveMapStrategy.StrategyFlag;
import cgeo.geocaching.enumerations.StatusCode;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
-import cgeo.geocaching.geopoint.Units;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.files.ParserException;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter.Format;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.location.Viewport;
+import cgeo.geocaching.maps.LivemapStrategy;
+import cgeo.geocaching.maps.LivemapStrategy.Flag;
import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Formatter;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
+import org.eclipse.jdt.annotation.NonNull;
import rx.Observable;
import rx.functions.Func2;
import android.graphics.Bitmap;
+import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -43,7 +48,7 @@ import java.util.Set;
public class GCMap {
private static Viewport lastSearchViewport = null;
- public static SearchResult searchByGeocodes(Set<String> geocodes) {
+ public static SearchResult searchByGeocodes(final Set<String> geocodes) {
final SearchResult result = new SearchResult();
final String geocodeList = StringUtils.join(geocodes.toArray(), "|");
@@ -60,53 +65,41 @@ public class GCMap {
// {"name":"HP: Hannover - Sahlkamp","gc":"GC2Q97X","g":"a09149ca-00e0-4aa2-b332-db2b4dfb18d2","available":true,"archived":false,"subrOnly":false,"li":false,"fp":"0","difficulty":{"text":1.0,"value":"1"},"terrain":{"text":1.5,"value":"1_5"},"hidden":"5/29/2011","container":{"text":"Small","value":"small.gif"},"type":{"text":"Traditional Cache","value":2},"owner":{"text":"GeoM@n","value":"1deaa69e-6bcc-421d-95a1-7d32b468cb82"}}]
// }
- final JSONObject json = new JSONObject(data);
- final String status = json.getString("status");
+ final ObjectNode json = (ObjectNode) JsonUtils.reader.readTree(data);
+ final String status = json.path("status").asText();
if (StringUtils.isBlank(status)) {
-
- throw new JSONException("No status inside JSON");
+ throw new ParserException("No status inside JSON");
}
if ("success".compareTo(status) != 0) {
- throw new JSONException("Wrong status inside JSON");
+ throw new ParserException("Wrong status inside JSON");
}
- final JSONArray dataArray = json.getJSONArray("data");
+ final ArrayNode dataArray = (ArrayNode) json.get("data");
if (dataArray == null) {
- throw new JSONException("No data inside JSON");
+ throw new ParserException("No data inside JSON");
}
final ArrayList<Geocache> caches = new ArrayList<>();
- for (int j = 0; j < dataArray.length(); j++) {
+ for (final JsonNode dataObject: dataArray) {
final Geocache cache = new Geocache();
-
- JSONObject dataObject = dataArray.getJSONObject(j);
- cache.setName(dataObject.getString("name"));
- cache.setGeocode(dataObject.getString("gc"));
- cache.setGuid(dataObject.getString("g")); // 34c2e609-5246-4f91-9029-d6c02b0f2a82"
- cache.setDisabled(!dataObject.getBoolean("available"));
- cache.setArchived(dataObject.getBoolean("archived"));
- cache.setPremiumMembersOnly(dataObject.getBoolean("subrOnly"));
+ cache.setName(dataObject.path("name").asText());
+ cache.setGeocode(dataObject.path("gc").asText());
+ cache.setGuid(dataObject.path("g").asText()); // 34c2e609-5246-4f91-9029-d6c02b0f2a82"
+ cache.setDisabled(!dataObject.path("available").asBoolean());
+ cache.setArchived(dataObject.path("archived").asBoolean());
+ cache.setPremiumMembersOnly(dataObject.path("subrOnly").asBoolean());
// "li" seems to be "false" always
- cache.setFavoritePoints(Integer.parseInt(dataObject.getString("fp")));
- JSONObject difficultyObj = dataObject.getJSONObject("difficulty");
- cache.setDifficulty(Float.parseFloat(difficultyObj.getString("text"))); // 3.5
- JSONObject terrainObj = dataObject.getJSONObject("terrain");
- cache.setTerrain(Float.parseFloat(terrainObj.getString("text"))); // 1.5
- cache.setHidden(GCLogin.parseGcCustomDate(dataObject.getString("hidden"), "MM/dd/yyyy")); // 7/23/2001
- JSONObject containerObj = dataObject.getJSONObject("container");
- cache.setSize(CacheSize.getById(containerObj.getString("text"))); // Regular
- JSONObject typeObj = dataObject.getJSONObject("type");
- cache.setType(CacheType.getByPattern(typeObj.getString("text"))); // Traditional Cache
- JSONObject ownerObj = dataObject.getJSONObject("owner");
- cache.setOwnerDisplayName(ownerObj.getString("text"));
+ cache.setFavoritePoints(Integer.parseInt(dataObject.path("fp").asText()));
+ cache.setDifficulty(Float.parseFloat(dataObject.path("difficulty").path("text").asText())); // 3.5
+ cache.setTerrain(Float.parseFloat(dataObject.path("terrain").path("text").asText())); // 1.5
+ cache.setHidden(GCLogin.parseGcCustomDate(dataObject.path("hidden").asText(), "MM/dd/yyyy")); // 7/23/2001
+ cache.setSize(CacheSize.getById(dataObject.path("container").path("text").asText())); // Regular
+ cache.setType(CacheType.getByPattern(dataObject.path("type").path("text").asText())); // Traditional Cache
+ cache.setOwnerDisplayName(dataObject.path("owner").path("text").asText());
caches.add(cache);
}
result.addAndPutInCache(caches);
- } catch (JSONException e) {
- result.setError(StatusCode.UNKNOWN_ERROR);
- } catch (ParseException e) {
- result.setError(StatusCode.UNKNOWN_ERROR);
- } catch (NumberFormatException e) {
+ } catch (ParserException | ParseException | IOException | NumberFormatException ignored) {
result.setError(StatusCode.UNKNOWN_ERROR);
}
return result;
@@ -117,7 +110,7 @@ public class GCMap {
* Retrieved data.
* @return SearchResult. Never null.
*/
- public static SearchResult parseMapJSON(final String data, Tile tile, Bitmap bitmap, final Strategy strategy) {
+ public static SearchResult parseMapJSON(final String data, final Tile tile, final Bitmap bitmap, final LivemapStrategy strategy) {
final SearchResult searchResult = new SearchResult();
try {
@@ -125,7 +118,7 @@ public class GCMap {
final LeastRecentlyUsedMap<String, String> nameCache = new LeastRecentlyUsedMap.LruCache<>(2000); // JSON id, cache name
if (StringUtils.isEmpty(data)) {
- throw new JSONException("No page given");
+ throw new ParserException("No page given");
}
// Example JSON information
@@ -134,34 +127,33 @@ public class GCMap {
// "data":{"55_55":[{"i":"gEaR","n":"Spiel & Sport"}],"55_54":[{"i":"gEaR","n":"Spiel & Sport"}],"17_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"55_53":[{"i":"gEaR","n":"Spiel & Sport"}],"17_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"17_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"57_53":[{"i":"gEaR","n":"Spiel & Sport"}],"57_55":[{"i":"gEaR","n":"Spiel & Sport"}],"3_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"3_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"57_54":[{"i":"gEaR","n":"Spiel & Sport"}],"3_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"15_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"15_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"15_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"4_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"4_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"4_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"16_25":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"16_26":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"16_27":[{"i":"Rkzt","n":"EDSSW: Rathaus "}],"2_62":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"2_60":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"2_61":[{"i":"gOWz","n":"Baumarktserie - Wer Wo Was -"}],"56_53":[{"i":"gEaR","n":"Spiel & Sport"}],"56_54":[{"i":"gEaR","n":"Spiel & Sport"}],"56_55":[{"i":"gEaR","n":"Spiel & Sport"}]}
// }
- final JSONObject json = new JSONObject(data);
+ final ObjectNode json = (ObjectNode) JsonUtils.reader.readTree(data);
- final JSONArray grid = json.getJSONArray("grid");
- if (grid == null || grid.length() != (UTFGrid.GRID_MAXY + 1)) {
- throw new JSONException("No grid inside JSON");
+ final ArrayNode grid = (ArrayNode) json.get("grid");
+ if (grid == null || grid.size() != (UTFGrid.GRID_MAXY + 1)) {
+ throw new ParserException("No grid inside JSON");
}
- final JSONArray keys = json.getJSONArray("keys");
+ final ArrayNode keys = (ArrayNode) json.get("keys");
if (keys == null) {
- throw new JSONException("No keys inside JSON");
+ throw new ParserException("No keys inside JSON");
}
- final JSONObject dataObject = json.getJSONObject("data");
+ final ObjectNode dataObject = (ObjectNode) json.get("data");
if (dataObject == null) {
- throw new JSONException("No data inside JSON");
+ throw new ParserException("No data inside JSON");
}
// iterate over the data and construct all caches in this tile
- Map<String, List<UTFGridPosition>> positions = new HashMap<>(); // JSON id as key
- Map<String, List<UTFGridPosition>> singlePositions = new HashMap<>(); // JSON id as key
-
- for (int i = 1; i < keys.length(); i++) { // index 0 is empty
- String key = keys.getString(i);
- if (StringUtils.isNotBlank(key)) {
- UTFGridPosition pos = UTFGridPosition.fromString(key);
- JSONArray dataForKey = dataObject.getJSONArray(key);
- for (int j = 0; j < dataForKey.length(); j++) {
- JSONObject cacheInfo = dataForKey.getJSONObject(j);
- String id = cacheInfo.getString("i");
- nameCache.put(id, cacheInfo.getString("n"));
+ final Map<String, List<UTFGridPosition>> positions = new HashMap<>(); // JSON id as key
+ final Map<String, List<UTFGridPosition>> singlePositions = new HashMap<>(); // JSON id as key
+
+ for (final JsonNode rawKey: keys) {
+ final String key = rawKey.asText();
+ if (StringUtils.isNotBlank(key)) { // index 0 is empty
+ final UTFGridPosition pos = UTFGridPosition.fromString(key);
+ final ArrayNode dataForKey = (ArrayNode) dataObject.get(key);
+ for (final JsonNode cacheInfo: dataForKey) {
+ final String id = cacheInfo.get("i").asText();
+ nameCache.put(id, cacheInfo.get("n").asText());
List<UTFGridPosition> listOfPositions = positions.get(id);
List<UTFGridPosition> singleListOfPositions = singlePositions.get(id);
@@ -174,7 +166,7 @@ public class GCMap {
}
listOfPositions.add(pos);
- if (dataForKey.length() == 1) {
+ if (dataForKey.size() == 1) {
singleListOfPositions.add(pos);
}
@@ -183,18 +175,18 @@ public class GCMap {
}
final ArrayList<Geocache> caches = new ArrayList<>();
- for (Entry<String, List<UTFGridPosition>> entry : positions.entrySet()) {
- String id = entry.getKey();
- List<UTFGridPosition> pos = entry.getValue();
- UTFGridPosition xy = UTFGrid.getPositionInGrid(pos);
- Geocache cache = new Geocache();
+ for (final Entry<String, List<UTFGridPosition>> entry : positions.entrySet()) {
+ final String id = entry.getKey();
+ final List<UTFGridPosition> pos = entry.getValue();
+ final UTFGridPosition xy = UTFGrid.getPositionInGrid(pos);
+ final Geocache cache = new Geocache();
cache.setDetailed(false);
cache.setReliableLatLon(false);
cache.setGeocode(id);
cache.setName(nameCache.get(id));
cache.setCoords(tile.getCoord(xy), tile.getZoomLevel());
- if (strategy.flags.contains(StrategyFlag.PARSE_TILES) && bitmap != null) {
- for (UTFGridPosition singlePos : singlePositions.get(id)) {
+ if (strategy.flags.contains(LivemapStrategy.Flag.PARSE_TILES) && bitmap != null) {
+ for (final UTFGridPosition singlePos : singlePositions.get(id)) {
if (IconDecoder.parseMapPNG(cache, bitmap, singlePos, tile.getZoomLevel())) {
break; // cache parsed
}
@@ -220,9 +212,7 @@ public class GCMap {
searchResult.addAndPutInCache(caches);
Log.d("Retrieved " + searchResult.getCount() + " caches for tile " + tile.toString());
- } catch (RuntimeException e) {
- Log.e("GCMap.parseMapJSON", e);
- } catch (JSONException e) {
+ } catch (RuntimeException | ParserException | IOException e) {
Log.e("GCMap.parseMapJSON", e);
}
@@ -236,19 +226,19 @@ public class GCMap {
* Area to search
* @param tokens
* Live map tokens
- * @return
*/
+ @NonNull
public static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens) {
- int speed = (int) CgeoApplication.getInstance().currentGeo().getSpeed() * 60 * 60 / 1000; // in km/h
- Strategy strategy = Settings.getLiveMapStrategy();
- if (strategy == Strategy.AUTO) {
- strategy = speed >= 30 ? Strategy.FAST : Strategy.DETAILED;
+ final int speed = (int) Sensors.getInstance().currentGeo().getSpeed() * 60 * 60 / 1000; // in km/h
+ LivemapStrategy strategy = Settings.getLiveMapStrategy();
+ if (strategy == LivemapStrategy.AUTO) {
+ strategy = speed >= 30 ? LivemapStrategy.FAST : LivemapStrategy.DETAILED;
}
- SearchResult result = searchByViewport(viewport, tokens, strategy);
+ final SearchResult result = searchByViewport(viewport, tokens, strategy);
if (Settings.isDebug()) {
- StringBuilder text = new StringBuilder(Formatter.SEPARATOR).append(strategy.getL10n()).append(Formatter.SEPARATOR).append(Units.getSpeed(speed));
+ final StringBuilder text = new StringBuilder(Formatter.SEPARATOR).append(strategy.getL10n()).append(Formatter.SEPARATOR).append(Units.getSpeed(speed));
result.setUrl(result.getUrl() + text);
}
@@ -266,9 +256,9 @@ public class GCMap {
* Live map tokens
* @param strategy
* Strategy for data retrieval and parsing, @see Strategy
- * @return
*/
- private static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens, final Strategy strategy) {
+ @NonNull
+ private static SearchResult searchByViewport(final Viewport viewport, final MapTokens tokens, final LivemapStrategy strategy) {
Log.d("GCMap.searchByViewport" + viewport.toString());
final SearchResult searchResult = new SearchResult();
@@ -277,7 +267,7 @@ public class GCMap {
searchResult.setUrl(viewport.getCenter().format(Format.LAT_LON_DECMINUTE));
}
- if (strategy.flags.contains(StrategyFlag.LOAD_TILES)) {
+ if (strategy.flags.contains(LivemapStrategy.Flag.LOAD_TILES)) {
final Set<Tile> tiles = Tile.getTilesForViewport(viewport);
if (Settings.isDebug()) {
@@ -347,11 +337,11 @@ public class GCMap {
}
}
- if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isGCPremiumMember()) {
+ if (strategy.flags.contains(Flag.SEARCH_NEARBY) && Settings.isGCPremiumMember()) {
final Geopoint center = viewport.getCenter();
if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) {
//FIXME We don't have a RecaptchaReceiver!?
- SearchResult search = GCParser.searchByCoords(center, Settings.getCacheType(), false, null);
+ final SearchResult search = GCParser.searchByCoords(center, Settings.getCacheType(), false, null);
if (search != null && !search.isEmpty()) {
final Set<String> geocodes = search.getGeocodes();
lastSearchViewport = DataStore.getBounds(geocodes);
@@ -365,11 +355,10 @@ public class GCMap {
/**
* Creates a list of caches types to filter on the live map (exclusion string)
- *
+ *
* @param typeToDisplay
* - cache type to omit from exclusion list so it gets displayed
- * @return
- *
+ *
* cache types for live map filter:
* 2 = traditional, 9 = ape, 5 = letterbox
* 3 = multi
@@ -377,8 +366,8 @@ public class GCMap {
* 4 = virtual, 11 = webcam, 137 = earth
* 8 = mystery, 1858 = whereigo
*/
- private static String getCacheTypeFilter(CacheType typeToDisplay) {
- Set<String> filterTypes = new HashSet<>();
+ private static String getCacheTypeFilter(final CacheType typeToDisplay) {
+ final Set<String> filterTypes = new HashSet<>();
// Put all types in set, remove what should be visible in a second step
filterTypes.addAll(Arrays.asList("2", "9", "5", "3", "6", "453", "13", "1304", "4", "11", "137", "8", "1858"));
switch (typeToDisplay) {
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index c771049..7fef8b4 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -22,14 +22,15 @@ import cgeo.geocaching.enumerations.WaypointType;
import cgeo.geocaching.files.LocParser;
import cgeo.geocaching.gcvote.GCVote;
import cgeo.geocaching.gcvote.GCVoteRating;
-import cgeo.geocaching.geopoint.DistanceParser;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.DistanceParser;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.ui.DirectionImage;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.HtmlUtils;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.RxUtils;
@@ -38,15 +39,16 @@ import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import rx.Observable;
import rx.Observable.OnSubscribe;
@@ -54,11 +56,15 @@ import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func2;
+import rx.schedulers.Schedulers;
import android.net.Uri;
import android.text.Html;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.Collator;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -66,16 +72,22 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.EnumSet;
-import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
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
+ @NonNull
+ private final static SynchronizedDateFormat DATE_TB_IN_1 = new SynchronizedDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
+
+ @NonNull
+ private final static SynchronizedDateFormat DATE_TB_IN_2 = new SynchronizedDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
+ @NonNull
+ private final static ImmutablePair<StatusCode, Geocache> UNKNOWN_PARSE_ERROR = ImmutablePair.of(StatusCode.UNKNOWN_ERROR, null);
+
+ @Nullable
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");
@@ -125,12 +137,12 @@ public abstract class GCParser {
page = page.substring(startPos + 1, endPos - startPos + 1); // cut between <table> and </table>
- final String[] rows = page.split("<tr class=");
- final int rows_count = rows.length;
+ final String[] rows = StringUtils.splitByWholeSeparator(page, "<tr class=");
+ final int rowsCount = rows.length;
int excludedCaches = 0;
final ArrayList<Geocache> caches = new ArrayList<>();
- for (int z = 1; z < rows_count; z++) {
+ for (int z = 1; z < rowsCount; z++) {
final Geocache cache = new Geocache();
final String row = rows[z];
@@ -161,7 +173,7 @@ public abstract class GCParser {
}
} catch (final RuntimeException e) {
// failed to parse GUID and/or Disabled
- Log.w("GCParser.parseSearch: Failed to parse GUID and/or Disabled data");
+ Log.w("GCParser.parseSearch: Failed to parse GUID and/or Disabled data", e);
}
if (Settings.isExcludeDisabledCaches() && (cache.isDisabled() || cache.isArchived())) {
@@ -173,11 +185,11 @@ public abstract class GCParser {
cache.setGeocode(TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true));
// cache type
- cache.setType(CacheType.getByPattern(TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, true, 1, null, true)));
+ cache.setType(CacheType.getByPattern(TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, null)));
// cache direction - image
if (Settings.getLoadDirImg()) {
- final String direction = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 1, null, false);
+ final String direction = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, null);
if (direction != null) {
cache.setDirectionImg(direction);
}
@@ -187,7 +199,7 @@ public abstract class GCParser {
final String distance = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION_DISTANCE, false, 2, null, false);
if (distance != null) {
cache.setDistance(DistanceParser.parseDistance(distance,
- !Settings.isUseImperialUnits()));
+ !Settings.useImperialUnits()));
}
// difficulty/terrain
@@ -204,19 +216,19 @@ public abstract class GCParser {
}
// size
- final String container = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_CONTAINER, false, 1, null, false);
+ final String container = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_CONTAINER, false, null);
cache.setSize(CacheSize.getById(container));
// date hidden, makes sorting event caches easier
- final String dateHidden = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_HIDDEN_DATE, false, 1, null, false);
+ final String dateHidden = TextUtils.getMatch(row, GCConstants.PATTERN_SEARCH_HIDDEN_DATE, false, null);
if (StringUtils.isNotBlank(dateHidden)) {
try {
- Date date = GCLogin.parseGcCustomDate(dateHidden);
+ final Date date = GCLogin.parseGcCustomDate(dateHidden);
if (date != null) {
cache.setHidden(date);
}
- } catch (ParseException e) {
- Log.e("Error parsing event date from search");
+ } catch (final ParseException e) {
+ Log.e("Error parsing event date from search", e);
}
}
@@ -235,6 +247,7 @@ public abstract class GCParser {
}
if (StringUtils.isNotBlank(inventoryPre)) {
+ assert inventoryPre != null;
final MatcherWrapper matcherTbsInside = new MatcherWrapper(GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE, inventoryPre);
while (matcherTbsInside.find()) {
if (matcherTbsInside.groupCount() == 2 &&
@@ -266,7 +279,7 @@ public abstract class GCParser {
cache.setFavoritePoints(Integer.parseInt(result));
}
} catch (final NumberFormatException e) {
- Log.w("GCParser.parseSearch: Failed to parse favorite count");
+ Log.w("GCParser.parseSearch: Failed to parse favorite count", e);
}
caches.add(cache);
@@ -280,7 +293,7 @@ public abstract class GCParser {
searchResult.setTotalCountGC(Integer.parseInt(result) - excludedCaches);
}
} catch (final NumberFormatException e) {
- Log.w("GCParser.parseSearch: Failed to parse cache count");
+ Log.w("GCParser.parseSearch: Failed to parse cache count", e);
}
String recaptchaText = null;
@@ -291,6 +304,13 @@ public abstract class GCParser {
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");
+ final Observable<Set<Geocache>> storedCaches = Observable.defer(new Func0<Observable<Set<Geocache>>>() {
+ @Override
+ public Observable<Set<Geocache>> call() {
+ return Observable.just(DataStore.loadCaches(Geocache.getGeocodes(caches), LoadFlags.LOAD_CACHE_OR_DB));
+ }
+ }).subscribeOn(Schedulers.io()).cache();
+ storedCaches.subscribe(); // Force asynchronous start of database loading
try {
// get coordinates for parsed caches
@@ -306,41 +326,41 @@ public abstract class GCParser {
params.put("recaptcha_challenge_field", recaptchaReceiver.getChallenge());
params.put("recaptcha_response_field", recaptchaText);
}
- params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints");
+ params.put("Download", "Download Waypoints");
- final String coordinates = Network.getResponseData(Network.postRequest("http://www.geocaching.com/seek/nearest.aspx", params), false);
+ // retrieve target url
+ final String queryUrl = TextUtils.getMatch(pageContent, GCConstants.PATTERN_SEARCH_POST_ACTION, "");
- if (StringUtils.contains(coordinates, "You have not agreed to the license agreement. The license agreement is required before you can start downloading GPX or LOC files from Geocaching.com")) {
- Log.i("User has not agreed to the license agreement. Can\'t download .loc file.");
- searchResult.setError(StatusCode.UNAPPROVED_LICENSE);
- return searchResult;
- }
+ if (StringUtils.isEmpty(queryUrl)) {
+ Log.w("Loc download url not found");
+ } else {
- LocParser.parseLoc(searchResult, coordinates);
+ final String coordinates = Network.getResponseData(Network.postRequest("http://www.geocaching.com/seek/" + queryUrl, params), false);
- } catch (final RuntimeException e) {
- Log.e("GCParser.parseSearch.CIDs", e);
- }
- }
+ if (StringUtils.contains(coordinates, "You have not agreed to the license agreement. The license agreement is required before you can start downloading GPX or LOC files from Geocaching.com")) {
+ Log.i("User has not agreed to the license agreement. Can\'t download .loc file.");
+ searchResult.setError(StatusCode.UNAPPROVED_LICENSE);
+ return searchResult;
+ }
- // get direction images
- if (Settings.getLoadDirImg()) {
- final Set<Geocache> cachesReloaded = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB);
- for (final Geocache cache : cachesReloaded) {
- if (cache.getCoords() == null && StringUtils.isNotEmpty(cache.getDirectionImg())) {
- DirectionImage.getDrawable(cache.getDirectionImg());
+ LocParser.parseLoc(searchResult, coordinates, storedCaches.toBlocking().single());
}
+
+ } catch (final RuntimeException e) {
+ Log.e("GCParser.parseSearch.CIDs", e);
}
}
return searchResult;
}
+ @Nullable
private static Float parseStars(final String value) {
final float floatValue = Float.parseFloat(StringUtils.replaceChars(value, ',', '.'));
return floatValue >= 0.5 && floatValue <= 5.0 ? floatValue : null;
}
+ @Nullable
static SearchResult parseCache(final String page, final CancellableHandler handler) {
final ImmutablePair<StatusCode, Geocache> parsed = parseCacheFromText(page, handler);
// attention: parseCacheFromText already stores implicitly through searchResult.addCache
@@ -366,12 +386,13 @@ public abstract class GCParser {
return new SearchResult(cache);
}
+ @NonNull
static SearchResult parseAndSaveCacheFromText(final String page, @Nullable final CancellableHandler handler) {
final ImmutablePair<StatusCode, Geocache> parsed = parseCacheFromText(page, handler);
final SearchResult result = new SearchResult(parsed.left);
if (parsed.left == StatusCode.NO_ERROR) {
result.addAndPutInCache(Collections.singletonList(parsed.right));
- DataStore.saveLogsWithoutTransaction(parsed.right.getGeocode(), getLogs(page, Logs.ALL).toBlocking().toIterable());
+ DataStore.saveLogs(parsed.right.getGeocode(), getLogs(parseUserToken(page), Logs.ALL).toBlocking().toIterable());
}
return result;
}
@@ -380,17 +401,20 @@ public abstract class GCParser {
* Parse cache from text and return either an error code or a cache object in a pair. Note that inline logs are
* not parsed nor saved, while the cache itself is.
*
- * @param pageIn the page text to parse
- * @param handler the handler to send the progress notifications to
- * @return a pair, with a {@link StatusCode} on the left, and a non-nulll cache objet on the right
- * iff the status code is {@link StatusCode.NO_ERROR}.
+ * @param pageIn
+ * the page text to parse
+ * @param handler
+ * the handler to send the progress notifications to
+ * @return a pair, with a {@link StatusCode} on the left, and a non-null cache object on the right
+ * iff the status code is {@link cgeo.geocaching.enumerations.StatusCode#NO_ERROR}.
*/
+ @NonNull
static private ImmutablePair<StatusCode, Geocache> parseCacheFromText(final String pageIn, @Nullable final CancellableHandler handler) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details);
if (StringUtils.isBlank(pageIn)) {
Log.e("GCParser.parseCache: No page given");
- return null;
+ return UNKNOWN_PARSE_ERROR;
}
if (pageIn.contains(GCConstants.STRING_UNPUBLISHED_OTHER) || pageIn.contains(GCConstants.STRING_UNPUBLISHED_FROM_SEARCH)) {
@@ -403,12 +427,12 @@ public abstract class GCParser {
final String cacheName = Html.fromHtml(TextUtils.getMatch(pageIn, GCConstants.PATTERN_NAME, true, "")).toString();
if (GCConstants.STRING_UNKNOWN_ERROR.equalsIgnoreCase(cacheName)) {
- return ImmutablePair.of(StatusCode.UNKNOWN_ERROR, null);
+ return UNKNOWN_PARSE_ERROR;
}
// first handle the content with line breaks, then trim everything for easier matching and reduced memory consumption in parsed fields
String personalNoteWithLineBreaks = "";
- MatcherWrapper matcher = new MatcherWrapper(GCConstants.PATTERN_PERSONALNOTE, pageIn);
+ final MatcherWrapper matcher = new MatcherWrapper(GCConstants.PATTERN_PERSONALNOTE, pageIn);
if (matcher.find()) {
personalNoteWithLineBreaks = matcher.group(1).trim();
}
@@ -446,7 +470,7 @@ public abstract class GCParser {
final int pos = tableInside.indexOf(GCConstants.STRING_CACHEDETAILS);
if (pos == -1) {
Log.e("GCParser.parseCache: ID \"cacheDetails\" not found on page");
- return null;
+ return UNKNOWN_PARSE_ERROR;
}
tableInside = tableInside.substring(pos);
@@ -490,7 +514,7 @@ public abstract class GCParser {
}
} catch (final ParseException e) {
// failed to parse cache hidden date
- Log.w("GCParser.parseCache: Failed to parse cache hidden (event) date");
+ Log.w("GCParser.parseCache: Failed to parse cache hidden (event) date", e);
}
// favorite
@@ -547,17 +571,17 @@ public abstract class GCParser {
final String longDescription = TextUtils.getMatch(page, GCConstants.PATTERN_DESC, true, "");
String relatedWebPage = TextUtils.getMatch(page, GCConstants.PATTERN_RELATED_WEB_PAGE, true, "");
if (StringUtils.isNotEmpty(relatedWebPage)) {
- relatedWebPage = String.format("<a href=\"%s\"><b>%s</b></a><br/><br/>", relatedWebPage, relatedWebPage);
+ relatedWebPage = String.format("<br/><br/><a href=\"%s\"><b>%s</b></a>", relatedWebPage, relatedWebPage);
}
- cache.setDescription(relatedWebPage + longDescription);
+ cache.setDescription(longDescription + relatedWebPage);
// cache attributes
try {
+ final ArrayList<String> attributes = new ArrayList<>();
final String attributesPre = TextUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null);
- if (null != attributesPre) {
+ if (attributesPre != null) {
final MatcherWrapper matcherAttributesInside = new MatcherWrapper(GCConstants.PATTERN_ATTRIBUTESINSIDE, attributesPre);
- final ArrayList<String> attributes = new ArrayList<>();
while (matcherAttributesInside.find()) {
if (matcherAttributesInside.groupCount() > 1 && !matcherAttributesInside.group(2).equalsIgnoreCase("blank")) {
// by default, use the tooltip of the attribute
@@ -575,17 +599,17 @@ public abstract class GCParser {
attributes.add(attribute);
}
}
- cache.setAttributes(attributes);
}
+ cache.setAttributes(attributes);
} catch (final RuntimeException e) {
// failed to parse cache attributes
- Log.w("GCParser.parseCache: Failed to parse cache attributes");
+ Log.w("GCParser.parseCache: Failed to parse cache attributes", e);
}
// cache spoilers
try {
if (CancellableHandler.isCancelled(handler)) {
- return null;
+ return UNKNOWN_PARSE_ERROR;
}
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers);
@@ -608,7 +632,7 @@ public abstract class GCParser {
}
} catch (final RuntimeException e) {
// failed to parse cache spoilers
- Log.w("GCParser.parseCache: Failed to parse cache spoilers");
+ Log.w("GCParser.parseCache: Failed to parse cache spoilers", e);
}
// cache inventory
@@ -642,7 +666,7 @@ public abstract class GCParser {
}
} catch (final RuntimeException e) {
// failed to parse cache inventory
- Log.w("GCParser.parseCache: Failed to parse cache inventory (2)");
+ Log.w("GCParser.parseCache: Failed to parse cache inventory (2)", e);
}
// cache logs counts
@@ -664,7 +688,7 @@ public abstract class GCParser {
}
} catch (final NumberFormatException e) {
// failed to parse logs
- Log.w("GCParser.parseCache: Failed to parse cache log count");
+ Log.w("GCParser.parseCache: Failed to parse cache log count", e);
}
// waypoints - reset collection
@@ -680,13 +704,13 @@ public abstract class GCParser {
cache.addOrChangeWaypoint(waypoint, false);
cache.setUserModifiedCoords(true);
}
- } catch (final Geopoint.GeopointException e) {
+ } catch (final Geopoint.GeopointException ignored) {
}
int wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">");
if (wpBegin != -1) { // parse waypoints
if (CancellableHandler.isCancelled(handler)) {
- return null;
+ return UNKNOWN_PARSE_ERROR;
}
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints);
@@ -707,10 +731,15 @@ public abstract class GCParser {
wpList = wpList.substring(wpBegin + 7, wpEnd);
}
- final String[] wpItems = wpList.split("<tr");
+ final String[] wpItems = StringUtils.splitByWholeSeparator(wpList, "<tr");
- for (int j = 1; j < wpItems.length; j++) {
- String[] wp = wpItems[j].split("<td");
+ for (int j = 1; j < wpItems.length; j += 2) {
+ final String[] wp = StringUtils.splitByWholeSeparator(wpItems[j], "<td");
+ assert wp != null;
+ if (wp.length < 8) {
+ Log.e("GCParser.cacheParseFromText: not enough waypoint columns in table");
+ continue;
+ }
// waypoint name
// res is null during the unit tests
@@ -730,39 +759,42 @@ public abstract class GCParser {
// waypoint latitude and longitude
latlon = Html.fromHtml(TextUtils.getMatch(wp[7], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, false, 2, "", false)).toString().trim();
if (!StringUtils.startsWith(latlon, "???")) {
- waypoint.setLatlon(latlon);
waypoint.setCoords(new Geopoint(latlon));
}
- j++;
- if (wpItems.length > j) {
- wp = wpItems[j].split("<td");
- }
+ if (wpItems.length >= j) {
+ final String[] wpNote = StringUtils.splitByWholeSeparator(wpItems[j + 1], "<td");
+ assert wpNote != null;
+ if (wpNote.length < 4) {
+ Log.d("GCParser.cacheParseFromText: not enough waypoint columns in table to extract note");
+ continue;
+ }
- // waypoint note
- waypoint.setNote(TextUtils.getMatch(wp[3], GCConstants.PATTERN_WPNOTE, waypoint.getNote()));
+ // waypoint note
+ waypoint.setNote(TextUtils.getMatch(wpNote[3], GCConstants.PATTERN_WPNOTE, waypoint.getNote()));
+ }
cache.addOrChangeWaypoint(waypoint, false);
}
}
}
- cache.parseWaypointsFromNote();
-
// last check for necessary cache conditions
if (StringUtils.isBlank(cache.getGeocode())) {
- return ImmutablePair.of(StatusCode.UNKNOWN_ERROR, null);
+ return UNKNOWN_PARSE_ERROR;
}
cache.setDetailedUpdatedNow();
return ImmutablePair.of(StatusCode.NO_ERROR, cache);
}
+ @Nullable
private static String getNumberString(final String numberWithPunctuation) {
return StringUtils.replaceChars(numberWithPunctuation, ".,", "");
}
- public static SearchResult searchByNextPage(final SearchResult search, boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ @Nullable
+ public static SearchResult searchByNextPage(final SearchResult search, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (search == null) {
return null;
}
@@ -817,14 +849,12 @@ public abstract class GCParser {
/**
* Possibly hide caches found or hidden by user. This mutates its params argument when possible.
*
- * @param params
- * the parameters to mutate, or null to create a new Parameters if needed
- * @param my
- * @param addF
+ * @param params the parameters to mutate, or null to create a new Parameters if needed
+ * @param my {@code true} if the user's caches must be forcibly included regardless of their settings
* @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise
*/
- private static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) {
- if (!my && Settings.isExcludeMyCaches() && addF) {
+ private static Parameters addFToParams(final Parameters params, final boolean my) {
+ if (!my && Settings.isExcludeMyCaches()) {
if (params == null) {
return new Parameters("f", "1");
}
@@ -835,22 +865,14 @@ public abstract class GCParser {
return params;
}
- /**
- * @param cacheType
- * @param listId
- * @param showCaptcha
- * @param params
- * the parameters to add to the request URI
- * @param recaptchaReceiver
- * @return
- */
@Nullable
- private static SearchResult searchByAny(final CacheType cacheType, final boolean my, final boolean showCaptcha, final Parameters params, RecaptchaReceiver recaptchaReceiver) {
+ private static SearchResult searchByAny(@NonNull final CacheType cacheType, final boolean my, final boolean showCaptcha, final Parameters params, final RecaptchaReceiver recaptchaReceiver) {
insertCacheType(params, cacheType);
final String uri = "http://www.geocaching.com/seek/nearest.aspx";
- final String fullUri = uri + "?" + addFToParams(params, my, true);
- final String page = GCLogin.getInstance().getRequestLogged(uri, addFToParams(params, my, true));
+ final Parameters paramsWithF = addFToParams(params, my);
+ final String fullUri = uri + "?" + paramsWithF;
+ final String page = GCLogin.getInstance().getRequestLogged(uri, paramsWithF);
if (StringUtils.isBlank(page)) {
Log.e("GCParser.searchByAny: No data from server");
@@ -871,12 +893,12 @@ public abstract class GCParser {
return search;
}
- public static SearchResult searchByCoords(final @NonNull Geopoint coords, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByCoords(final @NonNull Geopoint coords, @NonNull final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
final Parameters params = new Parameters("lat", Double.toString(coords.getLatitude()), "lng", Double.toString(coords.getLongitude()));
return searchByAny(cacheType, false, showCaptcha, params, recaptchaReceiver);
}
- public static SearchResult searchByKeyword(final @NonNull String keyword, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByKeyword(final @NonNull String keyword, @NonNull final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(keyword)) {
Log.e("GCParser.searchByKeyword: No keyword given");
return null;
@@ -894,7 +916,7 @@ public abstract class GCParser {
return false;
}
- public static SearchResult searchByUsername(final String userName, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByUsername(final String userName, @NonNull final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(userName)) {
Log.e("GCParser.searchByUsername: No user name given");
return null;
@@ -905,7 +927,7 @@ public abstract class GCParser {
return searchByAny(cacheType, isSearchForMyCaches(userName), showCaptcha, params, recaptchaReceiver);
}
- public static SearchResult searchByPocketQuery(final String pocketGuid, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByPocketQuery(final String pocketGuid, @NonNull final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(pocketGuid)) {
Log.e("GCParser.searchByPocket: No guid name given");
return null;
@@ -916,7 +938,7 @@ public abstract class GCParser {
return searchByAny(cacheType, false, showCaptcha, params, recaptchaReceiver);
}
- public static SearchResult searchByOwner(final String userName, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
+ public static SearchResult searchByOwner(final String userName, @NonNull final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(userName)) {
Log.e("GCParser.searchByOwner: No user name given");
return null;
@@ -926,34 +948,6 @@ public abstract class GCParser {
return searchByAny(cacheType, isSearchForMyCaches(userName), showCaptcha, params, recaptchaReceiver);
}
- public static SearchResult searchByAddress(final String address, final CacheType cacheType, final boolean showCaptcha, RecaptchaReceiver recaptchaReceiver) {
- if (StringUtils.isBlank(address)) {
- Log.e("GCParser.searchByAddress: No address given");
- return null;
- }
- try {
- final JSONObject response = Network.requestJSON("http://www.geocaching.com/api/geocode", new Parameters("q", address));
- if (response == null) {
- return null;
- }
- if (!StringUtils.equalsIgnoreCase(response.getString("status"), "success")) {
- return null;
- }
- if (!response.has("data")) {
- return null;
- }
- final JSONObject data = response.getJSONObject("data");
- if (data == null) {
- return null;
- }
- return searchByCoords(new Geopoint(data.getDouble("lat"), data.getDouble("lng")), cacheType, showCaptcha, recaptchaReceiver);
- } catch (final JSONException e) {
- Log.w("GCParser.searchByAddress", e);
- }
-
- return null;
- }
-
@Nullable
public static Trackable searchTrackable(final String geocode, final String guid, final String id) {
if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) {
@@ -990,52 +984,59 @@ public abstract class GCParser {
return trackable;
}
- public static List<PocketQueryList> searchPocketQueryList() {
-
- final Parameters params = new Parameters();
+ /**
+ * Observable that fetches a list of pocket queries. Returns a single element (which may be an empty list).
+ * Executes on the network scheduler.
+ */
+ public static final Observable<List<PocketQueryList>> searchPocketQueryListObservable = Observable.defer(new Func0<Observable<List<PocketQueryList>>>() {
+ @Override
+ public Observable<List<PocketQueryList>> call() {
+ final Parameters params = new Parameters();
- final String page = GCLogin.getInstance().getRequestLogged("http://www.geocaching.com/pocket/default.aspx", params);
+ final String page = GCLogin.getInstance().getRequestLogged("http://www.geocaching.com/pocket/default.aspx", params);
- if (StringUtils.isBlank(page)) {
- Log.e("GCParser.searchPocketQueryList: No data from server");
- return null;
- }
+ if (StringUtils.isBlank(page)) {
+ Log.e("GCParser.searchPocketQueryList: No data from server");
+ return Observable.just(Collections.<PocketQueryList>emptyList());
+ }
- String subPage = StringUtils.substringAfter(page, "class=\"PocketQueryListTable");
- if (StringUtils.isEmpty(subPage)) {
- Log.e("GCParser.searchPocketQueryList: class \"PocketQueryListTable\" not found on page");
- return Collections.emptyList();
- }
+ final String subPage = StringUtils.substringAfter(page, "class=\"PocketQueryListTable");
+ if (StringUtils.isEmpty(subPage)) {
+ Log.e("GCParser.searchPocketQueryList: class \"PocketQueryListTable\" not found on page");
+ return Observable.just(Collections.<PocketQueryList>emptyList());
+ }
- List<PocketQueryList> list = new ArrayList<>();
+ final List<PocketQueryList> list = new ArrayList<>();
- final MatcherWrapper matcherPocket = new MatcherWrapper(GCConstants.PATTERN_LIST_PQ, subPage);
+ final MatcherWrapper matcherPocket = new MatcherWrapper(GCConstants.PATTERN_LIST_PQ, subPage);
- while (matcherPocket.find()) {
- int maxCaches;
- try {
- maxCaches = Integer.parseInt(matcherPocket.group(1));
- } catch (NumberFormatException e) {
- maxCaches = 0;
- Log.e("GCParser.searchPocketQueryList: Unable to parse max caches", e);
+ while (matcherPocket.find()) {
+ int maxCaches;
+ try {
+ maxCaches = Integer.parseInt(matcherPocket.group(1));
+ } catch (final NumberFormatException e) {
+ maxCaches = 0;
+ Log.e("GCParser.searchPocketQueryList: Unable to parse max caches", e);
+ }
+ final String guid = Html.fromHtml(matcherPocket.group(2)).toString();
+ final String name = Html.fromHtml(matcherPocket.group(3)).toString();
+ final PocketQueryList pqList = new PocketQueryList(guid, name, maxCaches);
+ list.add(pqList);
}
- final String guid = Html.fromHtml(matcherPocket.group(2)).toString();
- final String name = Html.fromHtml(matcherPocket.group(3)).toString();
- final PocketQueryList pqList = new PocketQueryList(guid, name, maxCaches);
- list.add(pqList);
- }
- // just in case, lets sort the resulting list
- Collections.sort(list, new Comparator<PocketQueryList>() {
+ // just in case, lets sort the resulting list
+ final Collator collator = TextUtils.getCollator();
+ Collections.sort(list, new Comparator<PocketQueryList>() {
- @Override
- public int compare(PocketQueryList left, PocketQueryList right) {
- return String.CASE_INSENSITIVE_ORDER.compare(left.getName(), right.getName());
- }
- });
+ @Override
+ public int compare(final PocketQueryList left, final PocketQueryList right) {
+ return collator.compare(left.getName(), right.getName());
+ }
+ });
- return list;
- }
+ return Observable.just(list);
+ }
+ }).subscribeOn(RxUtils.networkScheduler);
public static ImmutablePair<StatusCode, String> postLog(final String geocode, final String cacheid, final String[] viewstates,
final LogType logType, final int year, final int month, final int day,
@@ -1061,7 +1062,7 @@ public abstract class GCParser {
"__EVENTARGUMENT", "",
"__LASTFOCUS", "",
"ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
- "ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()),
+ "ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.formatGcCustomDate(year, month, day),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Month", Integer.toString(month),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Day", Integer.toString(day),
"ctl00$ContentBody$LogBookPanel1$uxDateVisited$Year", Integer.toString(year),
@@ -1147,6 +1148,11 @@ public abstract class GCParser {
Log.e("GCParser.postLog.confim", e);
}
+ if (page == null) {
+ Log.e("GCParser.postLog: didn't get response");
+ return new ImmutablePair<>(StatusCode.LOG_POST_ERROR, "");
+ }
+
try {
final MatcherWrapper matcherOk = new MatcherWrapper(GCConstants.PATTERN_OK1, page);
@@ -1160,7 +1166,7 @@ public abstract class GCParser {
gcLogin.getLoginStatus(page);
// the log-successful-page contains still the old value
if (gcLogin.getActualCachesFound() >= 0) {
- gcLogin.setActualCachesFound(gcLogin.getActualCachesFound() + 1);
+ gcLogin.setActualCachesFound(gcLogin.getActualCachesFound() + (logType.isFoundLog() ? 1 : 0));
}
final String logID = TextUtils.getMatch(page, GCConstants.PATTERN_LOG_IMAGE_UPLOAD, "");
@@ -1211,6 +1217,11 @@ public abstract class GCParser {
final File image = new File(imageUri.getPath());
final String response = Network.getResponseData(Network.postRequest(uri, uploadParams, "ctl00$ContentBody$ImageUploadControl1$uxFileUpload", "image/jpeg", image));
+ if (response == null) {
+ Log.e("GCParser.uploadLogIMage: didn't get response for image upload");
+ return ImmutablePair.of(StatusCode.LOGIMAGE_POST_ERROR, null);
+ }
+
final MatcherWrapper matcherUrl = new MatcherWrapper(GCConstants.PATTERN_IMAGE_UPLOAD_URL, response);
if (matcherUrl.find()) {
@@ -1257,7 +1268,7 @@ public abstract class GCParser {
params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", "");
} else {
params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", Integer.toString(month) + "/" + Integer.toString(day) + "/" + Integer.toString(year));
- params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.getCustomGcDateFormat().format(new GregorianCalendar(year, month - 1, day).getTime()));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxDateVisited", GCLogin.formatGcCustomDate(year, month, day));
}
params.put(
"ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day),
@@ -1417,7 +1428,10 @@ public abstract class GCParser {
}
private static String getUserToken(final Geocache cache) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n");
+ return parseUserToken(requestHtmlPage(cache.getGeocode(), null, "n"));
+ }
+
+ private static String parseUserToken(final String page) {
return TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
}
@@ -1483,7 +1497,7 @@ public abstract class GCParser {
}
} catch (final RuntimeException e) {
// failed to parse trackable owner name
- Log.w("GCParser.parseTrackable: Failed to parse trackable owner name");
+ Log.w("GCParser.parseTrackable: Failed to parse trackable owner name", e);
}
// trackable origin
@@ -1514,20 +1528,20 @@ public abstract class GCParser {
}
} catch (final RuntimeException e) {
// failed to parse trackable last known place
- Log.w("GCParser.parseTrackable: Failed to parse trackable last known place");
+ Log.w("GCParser.parseTrackable: Failed to parse trackable last known place", e);
}
// released date - can be missing on the page
final String releaseString = TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null);
if (releaseString != null) {
try {
- trackable.setReleased(dateTbIn1.parse(releaseString));
- } catch (ParseException e) {
+ trackable.setReleased(DATE_TB_IN_1.parse(releaseString));
+ } catch (final ParseException ignored) {
if (trackable.getReleased() == null) {
try {
- trackable.setReleased(dateTbIn2.parse(releaseString));
- } catch (ParseException e1) {
- Log.e("Could not parse trackable release " + releaseString);
+ trackable.setReleased(DATE_TB_IN_2.parse(releaseString));
+ } catch (final ParseException e) {
+ Log.e("Could not parse trackable release " + releaseString, e);
}
}
}
@@ -1538,14 +1552,14 @@ public abstract class GCParser {
if (null != distance) {
try {
trackable.setDistance(DistanceParser.parseDistance(distance,
- !Settings.isUseImperialUnits()));
+ !Settings.useImperialUnits()));
} catch (final NumberFormatException e) {
Log.e("GCParser.parseTrackable: Failed to parse distance", e);
}
}
// trackable goal
- trackable.setGoal(convertLinks(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal())));
+ trackable.setGoal(HtmlUtils.removeExtraParagraph(convertLinks(TextUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal()))));
// trackable details & image
try {
@@ -1558,12 +1572,12 @@ public abstract class GCParser {
trackable.setImage(StringUtils.replace(image, "/display/", "/large/"));
}
if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) {
- trackable.setDetails(convertLinks(details));
+ trackable.setDetails(HtmlUtils.removeExtraParagraph(convertLinks(details)));
}
}
} catch (final RuntimeException e) {
// failed to parse trackable details & image
- Log.w("GCParser.parseTrackable: Failed to parse trackable details & image");
+ Log.w("GCParser.parseTrackable: Failed to parse trackable details & image", e);
}
if (StringUtils.isEmpty(trackable.getDetails()) && page.contains(GCConstants.ERROR_TB_NOT_ACTIVATED)) {
trackable.setDetails(CgeoApplication.getInstance().getString(R.string.trackable_not_activated));
@@ -1585,7 +1599,7 @@ public abstract class GCParser {
long date = 0;
try {
date = GCLogin.parseGcCustomDate(matcherLogs.group(2)).getTime();
- } catch (final ParseException e) {
+ } catch (final ParseException ignored) {
}
final LogEntry logDone = new LogEntry(
@@ -1630,7 +1644,7 @@ public abstract class GCParser {
return trackable;
}
- private static String convertLinks(String input) {
+ private static String convertLinks(final String input) {
if (input == null) {
return null;
}
@@ -1656,23 +1670,19 @@ public abstract class GCParser {
/**
* Extract special logs (friends, own) through seperate request.
*
- * @param page
- * The page to extrat userToken from
- * @param logType
- * The logType to request
+ * @param userToken the user token extracted from the web page
+ * @param logType the logType to request
* @return Observable<LogEntry> The logs
*/
- private static Observable<LogEntry> getLogs(final String page, final Logs logType) {
+ private static Observable<LogEntry> getLogs(final String userToken, final Logs logType) {
+ if (userToken.isEmpty()) {
+ Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
+ return Observable.empty();
+ }
+
return Observable.defer(new Func0<Observable<LogEntry>>() {
@Override
public Observable<LogEntry> call() {
- final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page);
- if (!userTokenMatcher.find()) {
- Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
- return Observable.empty();
- }
-
- final String userToken = userTokenMatcher.group(1);
final Parameters params = new Parameters(
"tkn", userToken,
"idx", "1",
@@ -1691,77 +1701,67 @@ public abstract class GCParser {
Log.e("GCParser.loadLogsFromDetails: error " + statusCode + " when requesting log information");
return Observable.empty();
}
- String rawResponse = Network.getResponseData(response);
- if (rawResponse == null) {
+ final InputStream responseStream = Network.getResponseStream(response);
+ if (responseStream == null) {
Log.e("GCParser.loadLogsFromDetails: unable to read whole response");
return Observable.empty();
}
- return parseLogs(logType != Logs.ALL, rawResponse);
+ return parseLogs(logType != Logs.ALL, responseStream);
}
}).subscribeOn(RxUtils.networkScheduler);
}
- private static Observable<LogEntry> parseLogs(final boolean markAsFriendsLog, final String rawResponse) {
+ private static Observable<LogEntry> parseLogs(final boolean markAsFriendsLog, final InputStream responseStream) {
return Observable.create(new OnSubscribe<LogEntry>() {
@Override
public void call(final Subscriber<? super LogEntry> subscriber) {
- // for non logged in users the log book is not shown
- if (StringUtils.isBlank(rawResponse)) {
- subscriber.onCompleted();
- return;
- }
-
try {
- final JSONObject resp = new JSONObject(rawResponse);
- if (!resp.getString("status").equals("success")) {
- Log.e("GCParser.loadLogsFromDetails: status is " + resp.getString("status"));
+ final ObjectNode resp = (ObjectNode) JsonUtils.reader.readTree(responseStream);
+ if (!resp.path("status").asText().equals("success")) {
+ Log.e("GCParser.loadLogsFromDetails: status is " + resp.path("status").asText("[absent]"));
subscriber.onCompleted();
return;
}
- final JSONArray data = resp.getJSONArray("data");
-
- for (int index = 0; index < data.length(); index++) {
- final JSONObject entry = data.getJSONObject(index);
-
+ final ArrayNode data = (ArrayNode) resp.get("data");
+ for (final JsonNode entry: data) {
// FIXME: use the "LogType" field instead of the "LogTypeImage" one.
- final String logIconNameExt = entry.optString("LogTypeImage", ".gif");
+ final String logIconNameExt = entry.path("LogTypeImage").asText(".gif");
final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4);
- long date = 0;
+ final long date;
try {
- date = GCLogin.parseGcCustomDate(entry.getString("Visited")).getTime();
- } catch (final ParseException e) {
- Log.e("GCParser.loadLogsFromDetails: failed to parse log date.");
+ date = GCLogin.parseGcCustomDate(entry.get("Visited").asText()).getTime();
+ } catch (ParseException | NullPointerException e) {
+ Log.e("GCParser.loadLogsFromDetails: failed to parse log date", e);
+ continue;
}
// TODO: we should update our log data structure to be able to record
// proper coordinates, and make them clickable. In the meantime, it is
// better to integrate those coordinates into the text rather than not
// display them at all.
- final String latLon = entry.getString("LatLonString");
- final String logText = (StringUtils.isEmpty(latLon) ? "" : (latLon + "<br/><br/>")) + TextUtils.removeControlCharacters(entry.getString("LogText"));
+ final String latLon = entry.path("LatLonString").asText();
+ final String logText = (StringUtils.isEmpty(latLon) ? "" : (latLon + "<br/><br/>")) + TextUtils.removeControlCharacters(entry.path("LogText").asText());
final LogEntry logDone = new LogEntry(
- TextUtils.removeControlCharacters(entry.getString("UserName")),
+ TextUtils.removeControlCharacters(entry.path("UserName").asText()),
date,
LogType.getByIconName(logIconName),
logText);
- logDone.found = entry.getInt("GeocacheFindCount");
+ logDone.found = entry.path("GeocacheFindCount").asInt();
logDone.friend = markAsFriendsLog;
- final JSONArray images = entry.getJSONArray("Images");
- for (int i = 0; i < images.length(); i++) {
- final JSONObject image = images.getJSONObject(i);
- final String url = "http://imgcdn.geocaching.com/cache/log/large/" + image.getString("FileName");
- final String title = TextUtils.removeControlCharacters(image.getString("Name"));
+ final ArrayNode images = (ArrayNode) entry.get("Images");
+ for (final JsonNode image: images) {
+ final String url = "http://imgcdn.geocaching.com/cache/log/large/" + image.path("FileName").asText();
+ final String title = TextUtils.removeControlCharacters(image.path("Name").asText());
final Image logImage = new Image(url, title);
logDone.addLogImage(logImage);
}
subscriber.onNext(logDone);
}
- } catch (final JSONException e) {
- // failed to parse logs
+ } catch (final IOException e) {
Log.w("GCParser.loadLogsFromDetails: Failed to parse cache logs", e);
}
subscriber.onCompleted();
@@ -1770,7 +1770,7 @@ public abstract class GCParser {
}
@NonNull
- public static List<LogType> parseTypes(String page) {
+ public static List<LogType> parseTypes(final String page) {
if (StringUtils.isEmpty(page)) {
return Collections.emptyList();
}
@@ -1801,9 +1801,10 @@ public abstract class GCParser {
return types;
}
+ @NonNull
public static List<TrackableLog> parseTrackableLog(final String page) {
if (StringUtils.isEmpty(page)) {
- return null;
+ return Collections.emptyList();
}
String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>");
@@ -1816,7 +1817,7 @@ public abstract class GCParser {
table = StringUtils.substringBetween(table, "<tbody>", "</tbody>");
if (StringUtils.isBlank(table)) {
Log.e("GCParser.parseTrackableLog: tbody not found on page");
- return null;
+ return Collections.emptyList();
}
final List<TrackableLog> trackableLogs = new ArrayList<>();
@@ -1865,16 +1866,12 @@ public abstract class GCParser {
return;
}
- final Observable<LogEntry> logs = getLogs(page, Logs.ALL);
- Observable<LogEntry> specialLogs;
- if (Settings.isFriendLogsWanted()) {
- CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
- specialLogs = Observable.merge(getLogs(page, Logs.FRIENDS),
- getLogs(page, Logs.OWN));
- } else {
- CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
- specialLogs = Observable.empty();
- }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
+ final String userToken = parseUserToken(page);
+ final Observable<LogEntry> logs = getLogs(userToken, Logs.ALL);
+ final Observable<LogEntry> ownLogs = getLogs(userToken, Logs.OWN).cache();
+ final Observable<LogEntry> specialLogs = Settings.isFriendLogsWanted() ?
+ Observable.merge(getLogs(userToken, Logs.FRIENDS), ownLogs) : Observable.<LogEntry>empty();
final Observable<List<LogEntry>> mergedLogs = Observable.zip(logs.toList(), specialLogs.toList(),
new Func2<List<LogEntry>, List<LogEntry>, List<LogEntry>>() {
@Override
@@ -1886,9 +1883,19 @@ public abstract class GCParser {
mergedLogs.subscribe(new Action1<List<LogEntry>>() {
@Override
public void call(final List<LogEntry> logEntries) {
- DataStore.saveLogsWithoutTransaction(cache.getGeocode(), logEntries);
+ DataStore.saveLogs(cache.getGeocode(), logEntries);
}
});
+ if (cache.isFound() && cache.getVisitedDate() == 0) {
+ ownLogs.subscribe(new Action1<LogEntry>() {
+ @Override
+ public void call(final LogEntry logEntry) {
+ if (logEntry.type == LogType.FOUND_IT) {
+ cache.setVisitedDate(logEntry.date);
+ }
+ }
+ });
+ }
if (Settings.isRatingWanted() && !CancellableHandler.isCancelled(handler)) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote);
@@ -1901,7 +1908,7 @@ public abstract class GCParser {
}
// Wait for completion of logs parsing, retrieving and merging
- mergedLogs.toBlocking().last();
+ RxUtils.waitForCompletion(mergedLogs);
}
/**
@@ -1923,77 +1930,82 @@ public abstract class GCParser {
}
}
- public static boolean uploadModifiedCoordinates(Geocache cache, Geopoint wpt) {
+ public static boolean uploadModifiedCoordinates(final Geocache cache, final Geopoint wpt) {
return editModifiedCoordinates(cache, wpt);
}
- public static boolean deleteModifiedCoordinates(Geocache cache) {
+ public static boolean deleteModifiedCoordinates(final Geocache cache) {
return editModifiedCoordinates(cache, null);
}
- public static boolean editModifiedCoordinates(Geocache cache, Geopoint wpt) {
+ public static boolean editModifiedCoordinates(final Geocache cache, final Geopoint wpt) {
final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
- try {
- JSONObject jo;
- if (wpt != null) {
- jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken)
- .put("data", new JSONObject()
- .put("lat", wpt.getLatitudeE6() / 1E6)
- .put("lng", wpt.getLongitudeE6() / 1E6))));
- } else {
- jo = new JSONObject().put("dto", (new JSONObject().put("ut", userToken)));
- }
-
- final String uriSuffix = wpt != null ? "SetUserCoordinate" : "ResetUserCoordinate";
+ final ObjectNode jo = new ObjectNode(JsonUtils.factory);
+ final ObjectNode dto = jo.putObject("dto").put("ut", userToken);
+ if (wpt != null) {
+ dto.putObject("data").put("lat", wpt.getLatitudeE6() / 1E6).put("lng", wpt.getLongitudeE6() / 1E6);
+ }
- final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
- final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
- Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString());
+ final String uriSuffix = wpt != null ? "SetUserCoordinate" : "ResetUserCoordinate";
- if (response != null && response.getStatusLine().getStatusCode() == 200) {
- Log.i("GCParser.editModifiedCoordinates - edited on GC.com");
- return true;
- }
+ final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
+ final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
- } catch (final JSONException e) {
- Log.e("Unknown exception with json wrap code", e);
+ if (response != null && response.getStatusLine().getStatusCode() == 200) {
+ Log.i("GCParser.editModifiedCoordinates - edited on GC.com");
+ return true;
}
+
Log.e("GCParser.deleteModifiedCoordinates - cannot delete modified coords");
return false;
}
- public static boolean uploadPersonalNote(Geocache cache) {
+ public static boolean uploadPersonalNote(final Geocache cache) {
final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
- try {
- final JSONObject jo = new JSONObject()
- .put("dto", (new JSONObject()
- .put("et", StringUtils.defaultString(cache.getPersonalNote()))
- .put("ut", userToken)));
-
- final String uriSuffix = "SetUserCacheNote";
+ final ObjectNode jo = new ObjectNode(JsonUtils.factory);
+ jo.putObject("dto").put("et", StringUtils.defaultString(cache.getPersonalNote())).put("ut", userToken);
- final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
- final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
- Log.i("Sending to " + uriPrefix + uriSuffix + " :" + jo.toString());
+ final String uriSuffix = "SetUserCacheNote";
- if (response != null && response.getStatusLine().getStatusCode() == 200) {
- Log.i("GCParser.uploadPersonalNote - uploaded to GC.com");
- return true;
- }
+ final String uriPrefix = "http://www.geocaching.com/seek/cache_details.aspx/";
+ final HttpResponse response = Network.postJsonRequest(uriPrefix + uriSuffix, jo);
- } catch (final JSONException e) {
- Log.e("Unknown exception with json wrap code", e);
+ if (response != null && response.getStatusLine().getStatusCode() == 200) {
+ Log.i("GCParser.uploadPersonalNote - uploaded to GC.com");
+ return true;
}
+
Log.e("GCParser.uploadPersonalNote - cannot upload personal note");
return false;
}
+ public static boolean ignoreCache(@NonNull final Geocache cache) {
+ final String uri = "http://www.geocaching.com/bookmarks/ignore.aspx?guid=" + cache.getGuid() + "&WptTypeID=" + cache.getType().wptTypeId;
+ final String page = GCLogin.getInstance().postRequestLogged(uri, null);
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("GCParser.ignoreCache: No data from server");
+ return false;
+ }
+
+ final String[] viewstates = GCLogin.getViewstates(page);
+
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "",
+ "__EVENTARGUMENT", "",
+ "ctl00$ContentBody$btnYes", "Yes. Ignore it.");
+
+ GCLogin.putViewstates(params, viewstates);
+ final String response = Network.getResponseData(Network.postRequest(uri, params));
+
+ return StringUtils.contains(response, "<p class=\"Success\">");
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java b/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java
index eba9301..071c3b0 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCSmiliesProvider.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.connector.gc;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
public class GCSmiliesProvider {
public enum Smiley {
@@ -24,9 +26,10 @@ public class GCSmiliesProvider {
DISAPPROVE("V"),
QUESTION("?");
+ @NonNull
public final String text;
- Smiley(final String text) {
+ Smiley(@NonNull final String text) {
this.text = text;
}
@@ -35,12 +38,14 @@ public class GCSmiliesProvider {
}
}
+ @NonNull
public static Smiley[] getSmilies() {
return Smiley.values();
}
- public static Smiley getSmiley(int itemId) {
- for (Smiley smiley : getSmilies()) {
+ @Nullable
+ public static Smiley getSmiley(final int itemId) {
+ for (final Smiley smiley : getSmilies()) {
if (smiley.getItemId() == itemId) {
return smiley;
}
diff --git a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java
index c6a2afc..95bb77d 100644
--- a/main/src/cgeo/geocaching/connector/gc/IconDecoder.java
+++ b/main/src/cgeo/geocaching/connector/gc/IconDecoder.java
@@ -10,7 +10,7 @@ import android.graphics.Bitmap;
* icon decoder for cache icons
*
*/
-public abstract class IconDecoder {
+abstract class IconDecoder {
private static final int CT_TRADITIONAL = 0;
private static final int CT_MULTI = 1;
private static final int CT_MYSTERY = 2;
@@ -25,7 +25,7 @@ public abstract class IconDecoder {
private static final int CT_VIRTUAL = 11;
private static final int CT_LETTERBOX = 12;
- public static boolean parseMapPNG(final Geocache cache, Bitmap bitmap, UTFGridPosition xy, int zoomlevel) {
+ static boolean parseMapPNG(final Geocache cache, final Bitmap bitmap, final UTFGridPosition xy, final int zoomlevel) {
final int topX = xy.getX() * 4;
final int topY = xy.getY() * 4;
final int bitmapWidth = bitmap.getWidth();
@@ -43,24 +43,24 @@ public abstract class IconDecoder {
numberOfDetections = 13;
}
- int[] pngType = new int[numberOfDetections];
+ final int[] pngType = new int[numberOfDetections];
for (int x = topX; x < topX + 4; x++) {
for (int y = topY; y < topY + 4; y++) {
- int color = bitmap.getPixel(x, y);
+ final int color = bitmap.getPixel(x, y);
if ((color >>> 24) != 255) {
continue; //transparent pixels (or semi_transparent) are only shadows of border
}
- int r = (color & 0xFF0000) >> 16;
- int g = (color & 0xFF00) >> 8;
- int b = color & 0xFF;
+ final int r = (color & 0xFF0000) >> 16;
+ final int g = (color & 0xFF00) >> 8;
+ final int b = color & 0xFF;
if (isPixelDuplicated(r, g, b, zoomlevel)) {
continue;
}
- int type;
+ final int type;
if (zoomlevel < 12) {
type = getCacheTypeFromPixel11(r, g, b);
} else {
@@ -143,7 +143,7 @@ public abstract class IconDecoder {
* zoom level of map
* @return true if parsing should not be performed
*/
- private static boolean isPixelDuplicated(int r, int g, int b, int zoomlevel) {
+ private static boolean isPixelDuplicated(final int r, final int g, final int b, final int zoomlevel) {
if (zoomlevel < 12) {
if (((r == g) && (g == b)) || ((r == 233) && (g == 233) && (b == 234))) {
return true;
@@ -194,7 +194,7 @@ public abstract class IconDecoder {
* Blue component of pixel (from 0 - 255)
* @return Value from 0 to 6 representing detected type or state of the cache.
*/
- private static int getCacheTypeFromPixel13(int r, int g, int b) {
+ private static int getCacheTypeFromPixel13(final int r, final int g, final int b) {
if (b < 130) {
if (r < 41) {
return CT_MYSTERY;
@@ -256,7 +256,7 @@ public abstract class IconDecoder {
* Blue component of pixel (from 0 - 255)
* @return Value from 0 to 6 representing detected type or state of the cache.
*/
- private static int getCacheTypeFromPixel14(int r, int g, int b) {
+ private static int getCacheTypeFromPixel14(final int r, final int g, final int b) {
if (b < 128) {
if (r < 214) {
if (b < 37) {
@@ -489,7 +489,7 @@ public abstract class IconDecoder {
* Blue component of pixel (from 0 - 255)
* @return Value from 0 to 4 representing detected type or state of the cache.
*/
- private static int getCacheTypeFromPixel11(int r, int g, int b) {
+ private static int getCacheTypeFromPixel11(final int r, final int g, final int b) {
if (g < 136) {
if (r < 90) {
return g < 111 ? CT_MYSTERY : CT_TRADITIONAL;
diff --git a/main/src/cgeo/geocaching/connector/gc/MapTokens.java b/main/src/cgeo/geocaching/connector/gc/MapTokens.java
index 78ce4cb..b41533d 100644
--- a/main/src/cgeo/geocaching/connector/gc/MapTokens.java
+++ b/main/src/cgeo/geocaching/connector/gc/MapTokens.java
@@ -4,11 +4,11 @@ import android.util.Pair;
/**
* Wrapper type to make map tokens more type safe than with a String array.
- *
+ *
*/
public final class MapTokens extends Pair<String, String> {
- public MapTokens(String userSession, String sessionToken) {
+ MapTokens(final String userSession, final String sessionToken) {
super(userSession, sessionToken);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
index 5bcfd17..1258ddd 100644
--- a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
+++ b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
@@ -11,7 +11,7 @@ import cgeo.geocaching.utils.RxUtils;
import org.apache.commons.io.IOUtils;
import rx.Observable;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
import rx.functions.Func0;
@@ -42,9 +42,9 @@ public class RecaptchaHandler extends Handler {
}
private void loadChallenge(final ImageView imageView, final View reloadButton, final boolean needsFetch) {
- final Observable<Bitmap> captcha = Observable.defer(new Func0<Observable<? extends Bitmap>>() {
+ final Observable<Bitmap> captcha = Observable.defer(new Func0<Observable<Bitmap>>() {
@Override
- public Observable<? extends Bitmap> call() {
+ public Observable<Bitmap> call() {
if (needsFetch) {
recaptchaReceiver.fetchChallenge();
}
@@ -53,7 +53,7 @@ public class RecaptchaHandler extends Handler {
if (is != null) {
try {
final Bitmap img = BitmapFactory.decodeStream(is);
- return Observable.from(img);
+ return Observable.just(img);
} catch (final Exception e) {
Log.e("RecaptchaHandler.getCaptcha", e);
return Observable.error(e);
@@ -64,7 +64,7 @@ public class RecaptchaHandler extends Handler {
return Observable.empty();
}
});
- AndroidObservable.bindActivity(activity, captcha).subscribeOn(RxUtils.networkScheduler).subscribe(new Action1<Bitmap>() {
+ AppObservable.bindActivity(activity, captcha).subscribeOn(RxUtils.networkScheduler).subscribe(new Action1<Bitmap>() {
@Override
public void call(final Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
diff --git a/main/src/cgeo/geocaching/connector/gc/Tile.java b/main/src/cgeo/geocaching/connector/gc/Tile.java
index 18fe65c..dd6371b 100644
--- a/main/src/cgeo/geocaching/connector/gc/Tile.java
+++ b/main/src/cgeo/geocaching/connector/gc/Tile.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.connector.gc;
import cgeo.geocaching.ICoordinates;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.LeastRecentlyUsedSet;
@@ -15,7 +15,6 @@ import org.eclipse.jdt.annotation.NonNull;
import rx.Observable;
import rx.functions.Func0;
-import rx.util.async.Async;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -35,13 +34,13 @@ import java.util.Set;
*/
public class Tile {
- public static final int TILE_SIZE = 256;
- public static final int ZOOMLEVEL_MAX = 18;
+ static final int TILE_SIZE = 256;
+ static final int ZOOMLEVEL_MAX = 18;
public static final int ZOOMLEVEL_MIN = 0;
public static final int ZOOMLEVEL_MIN_PERSONALIZED = 12;
- static final int[] NUMBER_OF_TILES = new int[ZOOMLEVEL_MAX - ZOOMLEVEL_MIN + 1];
- static final int[] NUMBER_OF_PIXELS = new int[ZOOMLEVEL_MAX - ZOOMLEVEL_MIN + 1];
+ private static final int[] NUMBER_OF_TILES = new int[ZOOMLEVEL_MAX - ZOOMLEVEL_MIN + 1];
+ private static final int[] NUMBER_OF_PIXELS = new int[ZOOMLEVEL_MAX - ZOOMLEVEL_MIN + 1];
static {
for (int z = ZOOMLEVEL_MIN; z <= ZOOMLEVEL_MAX; z++) {
NUMBER_OF_TILES[z] = 1 << z;
@@ -56,11 +55,11 @@ public class Tile {
private final int zoomLevel;
private final Viewport viewPort;
- public Tile(Geopoint origin, int zoomlevel) {
+ public Tile(final Geopoint origin, final int zoomlevel) {
this(calcX(origin, clippedZoomlevel(zoomlevel)), calcY(origin, clippedZoomlevel(zoomlevel)), clippedZoomlevel(zoomlevel));
}
- private Tile(int tileX, int tileY, int zoomlevel) {
+ private Tile(final int tileX, final int tileY, final int zoomlevel) {
this.zoomLevel = clippedZoomlevel(zoomlevel);
@@ -74,7 +73,7 @@ public class Tile {
return zoomLevel;
}
- private static int clippedZoomlevel(int zoomlevel) {
+ private static int clippedZoomlevel(final int zoomlevel) {
return Math.max(Math.min(zoomlevel, ZOOMLEVEL_MAX), ZOOMLEVEL_MIN);
}
@@ -95,7 +94,7 @@ public class Tile {
*/
private static int calcY(final Geopoint origin, final int zoomlevel) {
// Optimization from Bing
- double sinLatRad = Math.sin(Math.toRadians(origin.getLatitude()));
+ final double sinLatRad = Math.sin(Math.toRadians(origin.getLatitude()));
// The cut of the fractional part instead of rounding to the nearest integer is intentional and part of the algorithm
return (int) ((0.5 - Math.log((1 + sinLatRad) / (1 - sinLatRad)) / (4 * Math.PI)) * NUMBER_OF_TILES[zoomlevel]);
}
@@ -115,13 +114,13 @@ public class Tile {
* href="http://developers.cloudmade.com/projects/tiles/examples/convert-coordinates-to-tile-numbers">Cloudmade</a>
*/
@NonNull
- public Geopoint getCoord(UTFGridPosition pos) {
+ Geopoint getCoord(final UTFGridPosition pos) {
- double pixX = tileX * TILE_SIZE + pos.x * 4;
- double pixY = tileY * TILE_SIZE + pos.y * 4;
+ final double pixX = tileX * TILE_SIZE + pos.x * 4;
+ final double pixY = tileY * TILE_SIZE + pos.y * 4;
- double lonDeg = ((360.0 * pixX) / NUMBER_OF_PIXELS[this.zoomLevel]) - 180.0;
- double latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * pixY / NUMBER_OF_PIXELS[this.zoomLevel])));
+ final double lonDeg = ((360.0 * pixX) / NUMBER_OF_PIXELS[this.zoomLevel]) - 180.0;
+ final double latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * pixY / NUMBER_OF_PIXELS[this.zoomLevel])));
return new Geopoint(Math.toDegrees(latRad), lonDeg);
}
@@ -144,17 +143,16 @@ public class Tile {
* First point
* @param right
* Second point
- * @return
*/
- public static int calcZoomLon(final Geopoint left, final Geopoint right, final int numberOfTiles) {
+ static int calcZoomLon(final Geopoint left, final Geopoint right, final int numberOfTiles) {
int zoom = (int) Math.floor(
Math.log(360.0 * numberOfTiles / (2.0 * Math.abs(left.getLongitude() - right.getLongitude())))
/ Math.log(2)
);
- Tile tileLeft = new Tile(left, zoom);
- Tile tileRight = new Tile(right, zoom);
+ final Tile tileLeft = new Tile(left, zoom);
+ final Tile tileRight = new Tile(right, zoom);
if (Math.abs(tileLeft.tileX - tileRight.tileX) < (numberOfTiles - 1)) {
zoom += 1;
@@ -177,9 +175,8 @@ public class Tile {
* First point
* @param top
* Second point
- * @return
*/
- public static int calcZoomLat(final Geopoint bottom, final Geopoint top, final int numberOfTiles) {
+ static int calcZoomLat(final Geopoint bottom, final Geopoint top, final int numberOfTiles) {
int zoom = (int) Math.ceil(
Math.log(2.0 * Math.PI * numberOfTiles / (
@@ -190,8 +187,8 @@ public class Tile {
) / Math.log(2)
);
- Tile tileBottom = new Tile(bottom, zoom);
- Tile tileTop = new Tile(top, zoom);
+ final Tile tileBottom = new Tile(bottom, zoom);
+ final Tile tileTop = new Tile(top, zoom);
if (Math.abs(tileBottom.tileY - tileTop.tileY) > (numberOfTiles - 1)) {
zoom -= 1;
@@ -200,7 +197,7 @@ public class Tile {
return Math.min(zoom, ZOOMLEVEL_MAX);
}
- private static double tanGrad(double angleGrad) {
+ private static double tanGrad(final double angleGrad) {
return Math.tan(angleGrad / 180.0 * Math.PI);
}
@@ -208,15 +205,13 @@ public class Tile {
* Calculates the inverted hyperbolic sine
* (after Bronstein, Semendjajew: Taschenbuch der Mathematik)
*
- * @param x
- * @return
*/
- private static double asinh(double x) {
+ private static double asinh(final double x) {
return Math.log(x + Math.sqrt(x * x + 1.0));
}
@Override
- public boolean equals(Object o) {
+ public boolean equals(final Object o) {
if (this == o) {
return true;
}
@@ -238,14 +233,15 @@ public class Tile {
*
* @return An observable with one element, which may be <tt>null</tt>.
*/
- public static Observable<String> requestMapInfo(final String url, final Parameters params, final String referer) {
+
+ static Observable<String> requestMapInfo(final String url, final Parameters params, final String referer) {
final HttpResponse response = Network.getRequest(url, params, new Parameters("Referer", referer));
- return Async.start(new Func0<String>() {
+ return Observable.defer(new Func0<Observable<String>>() {
@Override
- public String call() {
- return Network.getResponseData(response);
+ public Observable<String> call() {
+ return Observable.just(Network.getResponseData(response));
}
- }, RxUtils.networkScheduler);
+ }).subscribeOn(RxUtils.networkScheduler);
}
/** Request .png image for a tile. Return as soon as the request has been made, before the answer has been
@@ -253,19 +249,19 @@ public class Tile {
*
* @return An observable with one element, which may be <tt>null</tt>.
*/
- public static Observable<Bitmap> requestMapTile(final Parameters params) {
+ static Observable<Bitmap> requestMapTile(final Parameters params) {
final HttpResponse response = Network.getRequest(GCConstants.URL_MAP_TILE, params, new Parameters("Referer", GCConstants.URL_LIVE_MAP));
- return Async.start(new Func0<Bitmap>() {
+ return Observable.defer(new Func0<Observable<Bitmap>>() {
@Override
- public Bitmap call() {
+ public Observable<Bitmap> call() {
try {
- return response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null;
- } catch (IOException e) {
+ return Observable.just(response != null ? BitmapFactory.decodeStream(response.getEntity().getContent()) : null);
+ } catch (final IOException e) {
Log.e("Tile.requestMapTile() ", e);
- return null;
+ return Observable.just(null);
}
}
- }, RxUtils.computationScheduler);
+ }).subscribeOn(RxUtils.computationScheduler);
}
public boolean containsPoint(final @NonNull ICoordinates point) {
@@ -280,8 +276,6 @@ public class Tile {
* Calculate needed tiles for the given viewport to cover it with
* max 2x2 tiles
*
- * @param viewport
- * @return
*/
protected static Set<Tile> getTilesForViewport(final Viewport viewport) {
return getTilesForViewport(viewport, 2, Tile.ZOOMLEVEL_MIN);
@@ -292,26 +286,22 @@ public class Tile {
* You can define the minimum number of tiles on the longer axis
* and/or the minimum zoom level.
*
- * @param viewport
- * @param tilesOnAxis
- * @param minZoom
- * @return
*/
protected static Set<Tile> getTilesForViewport(final Viewport viewport, final int tilesOnAxis, final int minZoom) {
- Set<Tile> tiles = new HashSet<>();
- int zoom = Math.max(
+ final Set<Tile> tiles = new HashSet<>();
+ final int zoom = Math.max(
Math.min(Tile.calcZoomLon(viewport.bottomLeft, viewport.topRight, tilesOnAxis),
Tile.calcZoomLat(viewport.bottomLeft, viewport.topRight, tilesOnAxis)),
minZoom);
- Tile tileBottomLeft = new Tile(viewport.bottomLeft, zoom);
- Tile tileTopRight = new Tile(viewport.topRight, zoom);
+ final Tile tileBottomLeft = new Tile(viewport.bottomLeft, zoom);
+ final Tile tileTopRight = new Tile(viewport.topRight, zoom);
- int xLow = Math.min(tileBottomLeft.getX(), tileTopRight.getX());
- int xHigh = Math.max(tileBottomLeft.getX(), tileTopRight.getX());
+ final int xLow = Math.min(tileBottomLeft.getX(), tileTopRight.getX());
+ final int xHigh = Math.max(tileBottomLeft.getX(), tileTopRight.getX());
- int yLow = Math.min(tileBottomLeft.getY(), tileTopRight.getY());
- int yHigh = Math.max(tileBottomLeft.getY(), tileTopRight.getY());
+ final int yLow = Math.min(tileBottomLeft.getY(), tileTopRight.getY());
+ final int yHigh = Math.max(tileBottomLeft.getY(), tileTopRight.getY());
for (int xNum = xLow; xNum <= xHigh; xNum++) {
for (int yNum = yLow; yNum <= yHigh; yNum++) {
@@ -324,8 +314,6 @@ public class Tile {
public static class TileCache extends LeastRecentlyUsedSet<Tile> {
- private static final long serialVersionUID = -1942301031192719547L;
-
public TileCache() {
super(64);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
index 89a3de8..4db0519 100644
--- a/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
+++ b/main/src/cgeo/geocaching/connector/gc/UTFGrid.java
@@ -3,22 +3,22 @@ package cgeo.geocaching.connector.gc;
import java.util.List;
/**
- *
+ *
* @see <a href="https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md">Mapbox</a>
- *
+ *
*/
-public final class UTFGrid {
+final class UTFGrid {
- public static final int GRID_MAXX = 63;
- public static final int GRID_MAXY = 63;
+ static final int GRID_MAXX = 63;
+ static final int GRID_MAXY = 63;
/** Calculate from a list of positions (x/y) the coords */
- public static UTFGridPosition getPositionInGrid(List<UTFGridPosition> positions) {
+ static UTFGridPosition getPositionInGrid(final List<UTFGridPosition> positions) {
int minX = GRID_MAXX;
int maxX = 0;
int minY = GRID_MAXY;
int maxY = 0;
- for (UTFGridPosition pos : positions) {
+ for (final UTFGridPosition pos : positions) {
minX = Math.min(minX, pos.x);
maxX = Math.max(maxX, pos.x);
minY = Math.min(minY, pos.y);
diff --git a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
index eff193a..f5cd208 100644
--- a/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
+++ b/main/src/cgeo/geocaching/connector/gc/UTFGridPosition.java
@@ -8,13 +8,13 @@ import java.util.regex.Pattern;
/**
* Representation of a position inside an UTFGrid
*/
-public final class UTFGridPosition {
+final class UTFGridPosition {
- public final int x;
- public final int y;
+ final int x;
+ final int y;
private final static Pattern PATTERN_JSON_KEY = Pattern.compile("[^\\d]*" + "(\\d+),\\s*(\\d+)" + "[^\\d]*"); // (12, 34)
- public UTFGridPosition(final int x, final int y) {
+ UTFGridPosition(final int x, final int y) {
if (x < 0 || x > UTFGrid.GRID_MAXX) {
throw new IllegalArgumentException("x outside bounds");
}
@@ -36,9 +36,8 @@ public final class UTFGridPosition {
/**
* @param key
* Key in the format (xx, xx)
- * @return
*/
- static UTFGridPosition fromString(String key) {
+ static UTFGridPosition fromString(final String key) {
final MatcherWrapper matcher = new MatcherWrapper(UTFGridPosition.PATTERN_JSON_KEY, key);
try {
if (matcher.matches()) {
@@ -46,7 +45,7 @@ public final class UTFGridPosition {
final int y = Integer.parseInt(matcher.group(2));
return new UTFGridPosition(x, y);
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
}
return new UTFGridPosition(0, 0);
}
diff --git a/main/src/cgeo/geocaching/connector/gc/UncertainProperty.java b/main/src/cgeo/geocaching/connector/gc/UncertainProperty.java
index 71adcbd..204fc89 100644
--- a/main/src/cgeo/geocaching/connector/gc/UncertainProperty.java
+++ b/main/src/cgeo/geocaching/connector/gc/UncertainProperty.java
@@ -4,18 +4,17 @@ package cgeo.geocaching.connector.gc;
/**
* Property with certainty. When merging properties, the one with higher certainty wins.
*
- * @param <T>
*/
public class UncertainProperty<T> {
private final T value;
private final int certaintyLevel;
- public UncertainProperty(T value) {
+ public UncertainProperty(final T value) {
this(value, Tile.ZOOMLEVEL_MAX + 1);
}
- public UncertainProperty(T value, int certaintyLevel) {
+ public UncertainProperty(final T value, final int certaintyLevel) {
this.value = value;
this.certaintyLevel = certaintyLevel;
}
@@ -42,7 +41,7 @@ public class UncertainProperty<T> {
return this;
}
- public static <T> UncertainProperty<T> getMergedProperty(UncertainProperty<T> property, UncertainProperty<T> otherProperty) {
+ public static <T> UncertainProperty<T> getMergedProperty(final UncertainProperty<T> property, final UncertainProperty<T> otherProperty) {
if (null == property) {
return otherProperty;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/IOCAuthParams.java b/main/src/cgeo/geocaching/connector/oc/IOCAuthParams.java
index acf7b48..5e5151a 100644
--- a/main/src/cgeo/geocaching/connector/oc/IOCAuthParams.java
+++ b/main/src/cgeo/geocaching/connector/oc/IOCAuthParams.java
@@ -7,7 +7,6 @@ public interface IOCAuthParams {
/**
* The site name: 'www.opencaching...'
*
- * @return
*/
@NonNull
String getSite();
@@ -15,56 +14,48 @@ public interface IOCAuthParams {
/**
* ResId of the Consumer key
*
- * @return
*/
int getCKResId();
/**
* ResId of the Consumer secret
*
- * @return
*/
int getCSResId();
/**
* ResId of the Authorization title
*
- * @return
*/
int getAuthTitleResId();
/**
* Preference key of the public token
*
- * @return
*/
int getTokenPublicPrefKey();
/**
* Preference key of the secret token
*
- * @return
*/
int getTokenSecretPrefKey();
/**
* Preference key of the temporary public token (OAuth)
*
- * @return
*/
int getTempTokenPublicPrefKey();
/**
* Preference key of the temporary secret token (OAuth)
*
- * @return
*/
int getTempTokenSecretPrefKey();
/**
* The URI to use as a callback (OAuth)
*
- * @return
*/
@NonNull
String getCallbackUri();
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
index 284234e..a2322e0 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java
@@ -31,7 +31,7 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
private final ApiSupport apiSupport;
private final String licenseString;
- public OCApiConnector(String name, String host, String prefix, String cK, String licenseString, ApiSupport apiSupport) {
+ public OCApiConnector(final String name, final String host, final String prefix, final String cK, final String licenseString, final ApiSupport apiSupport) {
super(name, host, prefix);
this.cK = cK;
this.apiSupport = apiSupport;
@@ -39,10 +39,16 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
}
public void addAuthentication(final Parameters params) {
- params.put(CryptUtils.rot13("pbafhzre_xrl"), CryptUtils.rot13(cK));
+ final String rotCK = CryptUtils.rot13(cK);
+ // check that developers are not using the Ant defined properties without any values
+ if (StringUtils.startsWith(rotCK, "${")) {
+ throw new IllegalStateException("invalid OKAPI OAuth token " + rotCK);
+ }
+ params.put(CryptUtils.rot13("pbafhzre_xrl"), rotCK);
}
@Override
+ @NonNull
public String getLicenseText(final @NonNull Geocache cache) {
// NOT TO BE TRANSLATED
return "© " + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, " + licenseString;
@@ -93,13 +99,13 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode {
/**
* Checks if a search based on a user name targets the current user
- *
+ *
* @param username
* Name of the user the query is searching after
* @return True - search target and current is same, False - current user not known or not the same as username
*/
@SuppressWarnings("static-method")
- public boolean isSearchForMyCaches(String username) {
+ public boolean isSearchForMyCaches(final String username) {
return false;
}
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
index dd25c5e..2c783fb 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.LogCacheActivity;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.ILoggingManager;
@@ -15,9 +14,10 @@ import cgeo.geocaching.connector.capability.ISearchByOwner;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.oc.UserInfo.UserInfoStatus;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.CryptUtils;
@@ -50,7 +50,8 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public SearchResult searchByViewport(@NonNull final Viewport viewport, final MapTokens tokens) {
+ @NonNull
+ public SearchResult searchByViewport(@NonNull final Viewport viewport, @NonNull final MapTokens tokens) {
return new SearchResult(OkapiClient.getCachesBBox(viewport, this));
}
@@ -99,7 +100,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public boolean addToWatchlist(final Geocache cache) {
+ public boolean addToWatchlist(@NonNull final Geocache cache) {
final boolean added = OkapiClient.setWatchState(cache, true, this);
if (added) {
@@ -110,7 +111,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public boolean removeFromWatchlist(final Geocache cache) {
+ public boolean removeFromWatchlist(@NonNull final Geocache cache) {
final boolean removed = OkapiClient.setWatchState(cache, false, this);
if (removed) {
@@ -126,12 +127,13 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public ILoggingManager getLoggingManager(final LogCacheActivity activity, final Geocache cache) {
+ @NonNull
+ public ILoggingManager getLoggingManager(@NonNull final LogCacheActivity activity, @NonNull final Geocache cache) {
return new OkapiLoggingManager(activity, this, cache);
}
@Override
- public boolean canLog(final Geocache cache) {
+ public boolean canLog(@NonNull final Geocache cache) {
return true;
}
@@ -150,7 +152,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return StringUtils.isNotEmpty(getUserName()) && StringUtils.equals(cache.getOwnerDisplayName(), getUserName());
}
@@ -176,8 +178,7 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente
@Override
public SearchResult searchByKeyword(final @NonNull String name, final @NonNull RecaptchaReceiver recaptchaReceiver) {
- final Geopoint currentPos = CgeoApplication.getInstance().currentGeo().getCoords();
- return new SearchResult(OkapiClient.getCachesNamed(currentPos, name, this));
+ return new SearchResult(OkapiClient.getCachesNamed(Sensors.getInstance().currentGeo().getCoords(), name, this));
}
@Override
diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java b/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java
index a1030f0..21d10df 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
-import cgeo.geocaching.network.OAuthAuthorizationActivity.OAuthParameters;
+import cgeo.geocaching.activity.OAuthAuthorizationActivity.OAuthParameters;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java
index eb7e7a1..c15ca6c 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
+import cgeo.geocaching.activity.OAuthAuthorizationActivity;
import cgeo.geocaching.connector.oc.OkapiError.OkapiErrors;
-import cgeo.geocaching.network.OAuthAuthorizationActivity;
import cgeo.geocaching.settings.Settings;
import ch.boye.httpclientandroidlib.HttpResponse;
@@ -23,9 +23,9 @@ public class OCAuthorizationActivity extends OAuthAuthorizationActivity {
private int tempTokenSecretPrefKey;
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
- Bundle extras = getIntent().getExtras();
+ final Bundle extras = getIntent().getExtras();
if (extras != null) {
titleResId = extras.getInt(Intents.EXTRA_OAUTH_TITLE_RES_ID);
tokenPublicPrefKey = extras.getInt(Intents.EXTRA_OAUTH_TOKEN_PUBLIC_KEY);
@@ -68,8 +68,8 @@ public class OCAuthorizationActivity extends OAuthAuthorizationActivity {
* Return an extended error in case of an invalid time stamp
*/
@Override
- protected String getExtendedErrorMsg(HttpResponse response) {
- OkapiError error = OkapiClient.decodeErrorResponse(response);
+ protected String getExtendedErrorMsg(final HttpResponse response) {
+ final OkapiError error = OkapiClient.decodeErrorResponse(response);
if (error.getResult() == OkapiErrors.INVALID_TIMESTAMP) {
return res.getString(R.string.init_login_popup_invalid_timestamp);
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCCZConnector.java b/main/src/cgeo/geocaching/connector/oc/OCCZConnector.java
new file mode 100644
index 0000000..ee4330a
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/oc/OCCZConnector.java
@@ -0,0 +1,34 @@
+package cgeo.geocaching.connector.oc;
+
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+public class OCCZConnector extends OCConnector {
+
+ private static final String GEOCODE_PREFIX = "OZ";
+
+ public OCCZConnector() {
+ super("OpenCaching.CZ", "www.opencaching.cz", GEOCODE_PREFIX);
+ }
+
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ if (!StringUtils.containsIgnoreCase(url, "opencaching.cz")) {
+ return null;
+ }
+ final String id = StringUtils.substringAfter(url, "cacheid=");
+ try {
+ final String geocode = GEOCODE_PREFIX + StringUtils.leftPad(Integer.toHexString(Integer.parseInt(id)), 4, '0');
+ if (canHandle(geocode)) {
+ return geocode;
+ }
+ } catch (final NumberFormatException e) {
+ Log.e("Unexpected URL for opencaching.cz " + url);
+ }
+ return super.getGeocodeFromUrl(url);
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/oc/OCConnector.java b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
index 1ba88d5..6d7b23a 100644
--- a/main/src/cgeo/geocaching/connector/oc/OCConnector.java
+++ b/main/src/cgeo/geocaching/connector/oc/OCConnector.java
@@ -1,12 +1,13 @@
package cgeo.geocaching.connector.oc;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.R;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.enumerations.LogType;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
@@ -29,42 +30,46 @@ public class OCConnector extends AbstractConnector {
}
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return codePattern.matcher(geocode).matches();
}
@Override
+ @NonNull
public String getName() {
return name;
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getCacheUrl(@NonNull final Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@Override
+ @NonNull
public String getHost() {
return host;
}
@Override
- public boolean isZippedGPXFile(String fileName) {
+ public boolean isZippedGPXFile(@NonNull final String fileName) {
return GPX_ZIP_FILE_PATTERN.matcher(fileName).matches();
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return "http://" + host + "/viewcache.php?wp=";
}
@Override
- public int getCacheMapMarkerId(boolean disabled) {
+ public int getCacheMapMarkerId(final boolean disabled) {
if (disabled) {
return R.drawable.marker_disabled_oc;
}
@@ -72,11 +77,32 @@ public class OCConnector extends AbstractConnector {
}
@Override
- public final List<LogType> getPossibleLogTypes(Geocache cache) {
+ @NonNull
+ public final List<LogType> getPossibleLogTypes(@NonNull final Geocache cache) {
if (cache.isEventCache()) {
return EVENT_LOG_TYPES;
}
return STANDARD_LOG_TYPES;
}
+
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ // different opencaching installations have different supported URLs
+
+ // host.tld/geocode
+ final String shortHost = StringUtils.remove(getHost(), "www.");
+ String geocode = StringUtils.substringAfter(url, shortHost + "/");
+ if (canHandle(geocode)) {
+ return geocode;
+ }
+
+ // host.tld/viewcache.php?wp=geocode
+ geocode = StringUtils.substringAfter(url, shortHost + "/viewcache.php?wp=");
+ if (canHandle(geocode)) {
+ return geocode;
+ }
+ return super.getGeocodeFromUrl(url);
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index bd87042..e7d4e6f 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -22,44 +22,57 @@ import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.OAuth;
+import cgeo.geocaching.network.OAuthTokens;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.HtmlUtils;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.SynchronizedDateFormat;
import ch.boye.httpclientandroidlib.HttpResponse;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
import android.net.Uri;
+import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
-
+import java.util.regex.Pattern;
+
+/**
+ * Client for the OpenCaching API (Okapi).
+ *
+ * @see <a href="http://www.opencaching.de/okapi/introduction.html">Okapi overview</a>
+ *
+ */
final class OkapiClient {
+ private static final String PARAMETER_LOGCOUNT_VALUE = "all";
+ private static final String PARAMETER_LOGCOUNT_KEY = "lpc";
private static final char SEPARATOR = '|';
private static final String SEPARATOR_STRING = Character.toString(SEPARATOR);
private static final SynchronizedDateFormat LOG_DATE_FORMAT = new SynchronizedDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
@@ -132,6 +145,8 @@ final class OkapiClient {
private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest";
private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches";
+ private static final Pattern PATTERN_TIMEZONE = Pattern.compile("([+-][01][0-9]):([03])0");
+
public static Geocache getCache(final String geoCode) {
final Parameters params = new Parameters("cache_code", geoCode);
final IConnector connector = ConnectorFactory.getConnector(geoCode);
@@ -143,13 +158,14 @@ final class OkapiClient {
params.add("fields", getFullFields(ocapiConn));
params.add("attribution_append", "none");
+ params.add(PARAMETER_LOGCOUNT_KEY, PARAMETER_LOGCOUNT_VALUE);
final JSONResult result = request(ocapiConn, OkapiService.SERVICE_CACHE, params);
return result.isSuccess ? parseCache(result.data) : null;
}
- public static List<Geocache> getCachesAround(final Geopoint center, final OCApiConnector connector) {
+ public static List<Geocache> getCachesAround(final Geopoint center, @NonNull final OCApiConnector connector) {
final String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center);
final Parameters params = new Parameters("search_method", METHOD_SEARCH_NEAREST);
final Map<String, String> valueMap = new LinkedHashMap<>();
@@ -160,15 +176,15 @@ final class OkapiClient {
return requestCaches(connector, params, valueMap, false);
}
- public static List<Geocache> getCachesByOwner(final String username, final OCApiConnector connector) {
+ public static List<Geocache> getCachesByOwner(final String username, @NonNull final OCApiConnector connector) {
return getCachesByUser(username, connector, "owner_uuid");
}
- public static List<Geocache> getCachesByFinder(final String username, final OCApiConnector connector) {
+ public static List<Geocache> getCachesByFinder(final String username, @NonNull final OCApiConnector connector) {
return getCachesByUser(username, connector, "found_by");
}
- private static List<Geocache> getCachesByUser(final String username, final OCApiConnector connector, final String userRequestParam) {
+ private static List<Geocache> getCachesByUser(final String username, @NonNull final OCApiConnector connector, final String userRequestParam) {
final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
final Map<String, String> valueMap = new LinkedHashMap<>();
final @Nullable
@@ -181,7 +197,7 @@ final class OkapiClient {
return requestCaches(connector, params, valueMap, connector.isSearchForMyCaches(username));
}
- public static List<Geocache> getCachesNamed(final Geopoint center, final String namePart, final OCApiConnector connector) {
+ public static List<Geocache> getCachesNamed(final Geopoint center, final String namePart, @NonNull final OCApiConnector connector) {
final Map<String, String> valueMap = new LinkedHashMap<>();
final Parameters params;
@@ -202,17 +218,22 @@ final class OkapiClient {
return requestCaches(connector, params, valueMap, false);
}
- private static List<Geocache> requestCaches(final OCApiConnector connector, final Parameters params, final Map<String, String> valueMap, final boolean my) {
+ private static List<Geocache> requestCaches(@NonNull final OCApiConnector connector, final Parameters params, final Map<String, String> valueMap, final boolean my) {
// if a global type filter is set, and OKAPI does not know that type, then return an empty list instead of all caches
if (Settings.getCacheType() != CacheType.ALL && StringUtils.isBlank(getFilterFromType())) {
return Collections.emptyList();
}
addFilterParams(valueMap, connector, my);
- params.add("search_params", new JSONObject(valueMap).toString());
+ try {
+ params.add("search_params", JsonUtils.writer.writeValueAsString(valueMap));
+ } catch (final JsonProcessingException e) {
+ Log.e("requestCaches", e);
+ return Collections.emptyList();
+ }
addRetrieveParams(params, connector);
- final JSONObject data = request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params).data;
+ final ObjectNode data = request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params).data;
if (data == null) {
return Collections.emptyList();
@@ -224,7 +245,7 @@ final class OkapiClient {
/**
* Assumes level 3 OAuth.
*/
- public static List<Geocache> getCachesBBox(final Viewport viewport, final OCApiConnector connector) {
+ public static List<Geocache> getCachesBBox(final Viewport viewport, @NonNull final OCApiConnector connector) {
if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
return Collections.emptyList();
@@ -241,11 +262,11 @@ final class OkapiClient {
return requestCaches(connector, params, valueMap, false);
}
- public static boolean setWatchState(final Geocache cache, final boolean watched, final OCApiConnector connector) {
+ public static boolean setWatchState(final Geocache cache, final boolean watched, @NonNull final OCApiConnector connector) {
final Parameters params = new Parameters("cache_code", cache.getGeocode());
params.add("watched", watched ? "true" : "false");
- final JSONObject data = request(connector, OkapiService.SERVICE_MARK_CACHE, params).data;
+ final ObjectNode data = request(connector, OkapiService.SERVICE_MARK_CACHE, params).data;
if (data == null) {
return false;
@@ -256,7 +277,7 @@ final class OkapiClient {
return true;
}
- public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, final String logPassword, final OCApiConnector connector) {
+ public static LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, final String logPassword, @NonNull final OCApiConnector connector) {
final Parameters params = new Parameters("cache_code", cache.getGeocode());
params.add("logtype", logType.oc_type);
params.add("comment", log);
@@ -269,68 +290,58 @@ final class OkapiClient {
params.add("password", logPassword);
}
- final JSONObject data = request(connector, OkapiService.SERVICE_SUBMIT_LOG, params).data;
+ final ObjectNode data = request(connector, OkapiService.SERVICE_SUBMIT_LOG, params).data;
if (data == null) {
return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
try {
- if (data.getBoolean("success")) {
- return new LogResult(StatusCode.NO_ERROR, data.getString("log_uuid"));
+ if (data.get("success").asBoolean()) {
+ return new LogResult(StatusCode.NO_ERROR, data.get("log_uuid").asText());
}
return new LogResult(StatusCode.LOG_POST_ERROR, "");
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.postLog", e);
}
return new LogResult(StatusCode.LOG_POST_ERROR, "");
}
- private static List<Geocache> parseCaches(final JSONObject response) {
+ private static List<Geocache> parseCaches(final ObjectNode response) {
try {
// Check for empty result
- final String result = response.getString("results");
- if (StringUtils.isBlank(result) || StringUtils.equals(result, "[]")) {
+ final JsonNode results = response.path("results");
+ if (!results.isObject()) {
return Collections.emptyList();
}
// Get and iterate result list
- final JSONObject cachesResponse = response.getJSONObject("results");
- if (cachesResponse != null) {
- final List<Geocache> caches = new ArrayList<>(cachesResponse.length());
- final Iterator<?> keys = cachesResponse.keys();
- while (keys.hasNext()) {
- final Object next = keys.next();
- if (next instanceof String) {
- final String key = (String) next;
- final Geocache cache = parseSmallCache(cachesResponse.getJSONObject(key));
- caches.add(cache);
- }
- }
- return caches;
+ final List<Geocache> caches = new ArrayList<>(results.size());
+ for (final JsonNode cache: results) {
+ caches.add(parseSmallCache((ObjectNode) cache));
}
- } catch (final JSONException e) {
+ return caches;
+ } catch (ClassCastException | NullPointerException e) {
Log.e("OkapiClient.parseCachesResult", e);
}
return Collections.emptyList();
}
- private static Geocache parseSmallCache(final JSONObject response) {
+ private static Geocache parseSmallCache(final ObjectNode response) {
final Geocache cache = new Geocache();
cache.setReliableLatLon(true);
try {
-
parseCoreCache(response, cache);
-
DataStore.saveCache(cache, EnumSet.of(SaveFlag.CACHE));
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
+ // FIXME: here we may return a partially filled cache
Log.e("OkapiClient.parseSmallCache", e);
}
return cache;
}
- private static Geocache parseCache(final JSONObject response) {
+ private static Geocache parseCache(final ObjectNode response) {
final Geocache cache = new Geocache();
cache.setReliableLatLon(true);
try {
@@ -338,28 +349,27 @@ final class OkapiClient {
parseCoreCache(response, cache);
// not used: url
- final JSONObject ownerObject = response.getJSONObject(CACHE_OWNER);
- final String owner = parseUser(ownerObject);
+ final String owner = parseUser(response.get(CACHE_OWNER));
cache.setOwnerDisplayName(owner);
// OpenCaching has no distinction between user id and user display name. Set the ID anyway to simplify c:geo workflows.
cache.setOwnerUserId(owner);
- cache.getLogCounts().put(LogType.FOUND_IT, response.getInt(CACHE_FOUNDS));
- cache.getLogCounts().put(LogType.DIDNT_FIND_IT, response.getInt(CACHE_NOTFOUNDS));
+ cache.getLogCounts().put(LogType.FOUND_IT, response.get(CACHE_FOUNDS).asInt());
+ cache.getLogCounts().put(LogType.DIDNT_FIND_IT, response.get(CACHE_NOTFOUNDS).asInt());
// only current Api
- cache.getLogCounts().put(LogType.WILL_ATTEND, response.optInt(CACHE_WILLATTENDS));
+ cache.getLogCounts().put(LogType.WILL_ATTEND, response.path(CACHE_WILLATTENDS).asInt());
- if (!response.isNull(CACHE_RATING)) {
- cache.setRating((float) response.getDouble(CACHE_RATING));
+ if (response.has(CACHE_RATING)) {
+ cache.setRating((float) response.get(CACHE_RATING).asDouble());
}
- cache.setVotes(response.getInt(CACHE_VOTES));
+ cache.setVotes(response.get(CACHE_VOTES).asInt());
- cache.setFavoritePoints(response.getInt(CACHE_RECOMMENDATIONS));
+ cache.setFavoritePoints(response.get(CACHE_RECOMMENDATIONS).asInt());
// not used: req_password
// Prepend gc-link to description if available
final StringBuilder description = new StringBuilder(500);
- if (!response.isNull("gc_code")) {
- final String gccode = response.getString("gc_code");
+ if (response.hasNonNull("gc_code")) {
+ final String gccode = response.get("gc_code").asText();
description.append(CgeoApplication.getInstance().getResources()
.getString(R.string.cache_listed_on, GCConnector.getInstance().getName()))
.append(": <a href=\"http://coord.info/")
@@ -368,71 +378,69 @@ final class OkapiClient {
.append(gccode)
.append("</a><br /><br />");
}
- description.append(response.getString(CACHE_DESCRIPTION));
+ description.append(response.get(CACHE_DESCRIPTION).asText());
cache.setDescription(description.toString());
// currently the hint is delivered as HTML (contrary to OKAPI documentation), so we can store it directly
- cache.setHint(response.getString(CACHE_HINT));
+ cache.setHint(response.get(CACHE_HINT).asText());
// not used: hints
- final JSONArray images = response.getJSONArray(CACHE_IMAGES);
+ final ArrayNode images = (ArrayNode) response.get(CACHE_IMAGES);
if (images != null) {
- for (int i = 0; i < images.length(); i++) {
- final JSONObject imageResponse = images.getJSONObject(i);
- final String title = imageResponse.getString(CACHE_IMAGE_CAPTION);
- final String url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.getGeocode());
+ for (final JsonNode imageResponse: images) {
+ final String title = imageResponse.get(CACHE_IMAGE_CAPTION).asText();
+ final String url = absoluteUrl(imageResponse.get(CACHE_IMAGE_URL).asText(), cache.getGeocode());
// all images are added as spoiler images, although OKAPI has spoiler and non spoiler images
cache.addSpoiler(new Image(url, title));
}
}
- cache.setAttributes(parseAttributes(response.getJSONArray(CACHE_ATTRNAMES), response.optJSONArray(CACHE_ATTR_ACODES)));
+ cache.setAttributes(parseAttributes((ArrayNode) response.path(CACHE_ATTRNAMES), (ArrayNode) response.get(CACHE_ATTR_ACODES)));
//TODO: Store license per cache
//cache.setLicense(response.getString("attribution_note"));
- cache.setWaypoints(parseWaypoints(response.getJSONArray(CACHE_WPTS)), false);
+ cache.setWaypoints(parseWaypoints((ArrayNode) response.path(CACHE_WPTS)), false);
- cache.setInventory(parseTrackables(response.getJSONArray(CACHE_TRACKABLES)));
+ cache.setInventory(parseTrackables((ArrayNode) response.path(CACHE_TRACKABLES)));
- if (!response.isNull(CACHE_IS_WATCHED)) {
- cache.setOnWatchlist(response.getBoolean(CACHE_IS_WATCHED));
+ if (response.has(CACHE_IS_WATCHED)) {
+ cache.setOnWatchlist(response.get(CACHE_IS_WATCHED).asBoolean());
}
- if (!response.isNull(CACHE_MY_NOTES)) {
- cache.setPersonalNote(response.getString(CACHE_MY_NOTES));
- cache.parseWaypointsFromNote();
+ if (response.hasNonNull(CACHE_MY_NOTES)) {
+ cache.setPersonalNote(response.get(CACHE_MY_NOTES).asText());
}
- cache.setLogPasswordRequired(response.getBoolean(CACHE_REQ_PASSWORD));
+ cache.setLogPasswordRequired(response.get(CACHE_REQ_PASSWORD).asBoolean());
cache.setDetailedUpdatedNow();
// save full detailed caches
DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
- DataStore.saveLogsWithoutTransaction(cache.getGeocode(), parseLogs(response.getJSONArray(CACHE_LATEST_LOGS)));
- } catch (final JSONException e) {
+ DataStore.saveLogs(cache.getGeocode(), parseLogs((ArrayNode) response.path(CACHE_LATEST_LOGS)));
+ } catch (ClassCastException | NullPointerException e) {
Log.e("OkapiClient.parseCache", e);
}
return cache;
}
- private static void parseCoreCache(final JSONObject response, final Geocache cache) throws JSONException {
- cache.setGeocode(response.getString(CACHE_CODE));
- cache.setName(response.getString(CACHE_NAME));
+ private static void parseCoreCache(final ObjectNode response, final Geocache cache) {
+ cache.setGeocode(response.get(CACHE_CODE).asText());
+ cache.setName(response.get(CACHE_NAME).asText());
// not used: names
- setLocation(cache, response.getString(CACHE_LOCATION));
- cache.setType(getCacheType(response.getString(CACHE_TYPE)));
+ setLocation(cache, response.get(CACHE_LOCATION).asText());
+ cache.setType(getCacheType(response.get(CACHE_TYPE).asText()));
- final String status = response.getString(CACHE_STATUS);
+ final String status = response.get(CACHE_STATUS).asText();
cache.setDisabled(status.equalsIgnoreCase(CACHE_STATUS_DISABLED));
cache.setArchived(status.equalsIgnoreCase(CACHE_STATUS_ARCHIVED));
cache.setSize(getCacheSize(response));
- cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY));
- cache.setTerrain((float) response.getDouble(CACHE_TERRAIN));
+ cache.setDifficulty((float) response.get(CACHE_DIFFICULTY).asDouble());
+ cache.setTerrain((float) response.get(CACHE_TERRAIN).asDouble());
- cache.setInventoryItems(response.getInt(CACHE_TRACKABLES_COUNT));
+ cache.setInventoryItems(response.get(CACHE_TRACKABLES_COUNT).asInt());
- if (!response.isNull(CACHE_IS_FOUND)) {
- cache.setFound(response.getBoolean(CACHE_IS_FOUND));
+ if (response.has(CACHE_IS_FOUND)) {
+ cache.setFound(response.get(CACHE_IS_FOUND).asBoolean());
}
- cache.setHidden(parseDate(response.getString(CACHE_HIDDEN)));
+ cache.setHidden(parseDate(response.get(CACHE_HIDDEN).asText()));
}
private static String absoluteUrl(final String url, final String geocode) {
@@ -448,38 +456,36 @@ final class OkapiClient {
return url;
}
- private static String parseUser(final JSONObject user) throws JSONException {
- return user.getString(USER_USERNAME);
+ private static String parseUser(final JsonNode user) {
+ return user.get(USER_USERNAME).asText();
}
- private static List<LogEntry> parseLogs(final JSONArray logsJSON) {
+ private static List<LogEntry> parseLogs(final ArrayNode logsJSON) {
final List<LogEntry> result = new LinkedList<>();
- for (int i = 0; i < logsJSON.length(); i++) {
+ for (final JsonNode logResponse: logsJSON) {
try {
- final JSONObject logResponse = logsJSON.getJSONObject(i);
final LogEntry log = new LogEntry(
- parseUser(logResponse.getJSONObject(LOG_USER)),
- parseDate(logResponse.getString(LOG_DATE)).getTime(),
- parseLogType(logResponse.getString(LOG_TYPE)),
- logResponse.getString(LOG_COMMENT).trim());
+ parseUser(logResponse.get(LOG_USER)),
+ parseDate(logResponse.get(LOG_DATE).asText()).getTime(),
+ parseLogType(logResponse.get(LOG_TYPE).asText()),
+ HtmlUtils.removeExtraParagraph(logResponse.get(LOG_COMMENT).asText().trim()));
result.add(log);
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.parseLogs", e);
}
}
return result;
}
- private static List<Waypoint> parseWaypoints(final JSONArray wptsJson) {
+ private static List<Waypoint> parseWaypoints(final ArrayNode wptsJson) {
List<Waypoint> result = null;
- for (int i = 0; i < wptsJson.length(); i++) {
+ for (final JsonNode wptResponse: wptsJson) {
try {
- final JSONObject wptResponse = wptsJson.getJSONObject(i);
- final Waypoint wpt = new Waypoint(wptResponse.getString(WPT_NAME),
- parseWptType(wptResponse.getString(WPT_TYPE)),
+ final Waypoint wpt = new Waypoint(wptResponse.get(WPT_NAME).asText(),
+ parseWptType(wptResponse.get(WPT_TYPE).asText()),
false);
- wpt.setNote(wptResponse.getString(WPT_DESCRIPTION));
- final Geopoint pt = parseCoords(wptResponse.getString(WPT_LOCATION));
+ wpt.setNote(wptResponse.get(WPT_DESCRIPTION).asText());
+ final Geopoint pt = parseCoords(wptResponse.get(WPT_LOCATION).asText());
if (pt != null) {
wpt.setCoords(pt);
}
@@ -488,26 +494,25 @@ final class OkapiClient {
}
wpt.setPrefix(wpt.getName());
result.add(wpt);
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.parseWaypoints", e);
}
}
return result;
}
- private static List<Trackable> parseTrackables(final JSONArray trackablesJson) {
- if (trackablesJson.length() == 0) {
+ private static List<Trackable> parseTrackables(final ArrayNode trackablesJson) {
+ if (trackablesJson.size() == 0) {
return Collections.emptyList();
}
final List<Trackable> result = new ArrayList<>();
- for (int i = 0; i < trackablesJson.length(); i++) {
+ for (final JsonNode trackableResponse: trackablesJson) {
try {
- final JSONObject trackableResponse = trackablesJson.getJSONObject(i);
final Trackable trk = new Trackable();
- trk.setGeocode(trackableResponse.getString(TRK_GEOCODE));
- trk.setName(trackableResponse.getString(TRK_NAME));
+ trk.setGeocode(trackableResponse.get(TRK_GEOCODE).asText());
+ trk.setName(trackableResponse.get(TRK_NAME).asText());
result.add(trk);
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.parseWaypoints", e);
// Don't overwrite internal state with possibly partial result
return null;
@@ -576,7 +581,7 @@ final class OkapiClient {
}
private static Date parseDate(final String date) {
- final String strippedDate = date.replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
+ final String strippedDate = PATTERN_TIMEZONE.matcher(date).replaceAll("$1$20");
try {
return ISO8601DATEFORMAT.parse(strippedDate);
} catch (final ParseException e) {
@@ -595,14 +600,14 @@ final class OkapiClient {
return null;
}
- private static List<String> parseAttributes(final JSONArray nameList, final JSONArray acodeList) {
+ private static List<String> parseAttributes(final ArrayNode nameList, final ArrayNode acodeList) {
final List<String> result = new ArrayList<>();
- for (int i = 0; i < nameList.length(); i++) {
+ for (int i = 0; i < nameList.size(); i++) {
try {
- final String name = nameList.getString(i);
- final int acode = acodeList != null ? Integer.parseInt(acodeList.getString(i).substring(1)) : CacheAttribute.NO_ID;
+ final String name = nameList.get(i).asText();
+ final int acode = acodeList != null ? Integer.parseInt(acodeList.get(i).asText().substring(1)) : CacheAttribute.NO_ID;
final CacheAttribute attr = CacheAttribute.getByOcACode(acode);
if (attr != null) {
@@ -610,7 +615,7 @@ final class OkapiClient {
} else {
result.add(name);
}
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.parseAttributes", e);
}
}
@@ -624,27 +629,29 @@ final class OkapiClient {
cache.setCoords(new Geopoint(latitude, longitude));
}
- private static CacheSize getCacheSize(final JSONObject response) {
- if (response.isNull(CACHE_SIZE2)) {
+ @NonNull
+ private static CacheSize getCacheSize(final ObjectNode response) {
+ if (!response.has(CACHE_SIZE2)) {
return getCacheSizeDeprecated(response);
}
try {
- final String size = response.getString(CACHE_SIZE2);
+ final String size = response.get(CACHE_SIZE2).asText();
return CacheSize.getById(size);
- } catch (final JSONException e) {
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.getCacheSize", e);
return getCacheSizeDeprecated(response);
}
}
- private static CacheSize getCacheSizeDeprecated(final JSONObject response) {
- if (response.isNull(CACHE_SIZE_DEPRECATED)) {
+ @NonNull
+ private static CacheSize getCacheSizeDeprecated(final ObjectNode response) {
+ if (!response.has(CACHE_SIZE_DEPRECATED)) {
return CacheSize.NOT_CHOSEN;
}
double size = 0;
try {
- size = response.getDouble(CACHE_SIZE_DEPRECATED);
- } catch (final JSONException e) {
+ size = response.get(CACHE_SIZE_DEPRECATED).asDouble();
+ } catch (final NullPointerException e) {
Log.e("OkapiClient.getCacheSize", e);
}
switch ((int) Math.round(size)) {
@@ -692,12 +699,7 @@ final class OkapiClient {
return CacheType.UNKNOWN;
}
- private static String getCoreFields(final OCApiConnector connector) {
- if (connector == null) {
- Log.e("OkapiClient.getCoreFields called with invalid connector");
- return StringUtils.EMPTY;
- }
-
+ private static String getCoreFields(@NonNull final OCApiConnector connector) {
if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
return SERVICE_CACHE_CORE_FIELDS + SEPARATOR + SERVICE_CACHE_CORE_L3_FIELDS;
}
@@ -705,12 +707,7 @@ final class OkapiClient {
return SERVICE_CACHE_CORE_FIELDS;
}
- private static String getFullFields(final OCApiConnector connector) {
- if (connector == null) {
- Log.e("OkapiClient.getFullFields called with invalid connector");
- return StringUtils.EMPTY;
- }
-
+ private static String getFullFields(@NonNull final OCApiConnector connector) {
final StringBuilder res = new StringBuilder(500);
res.append(SERVICE_CACHE_CORE_FIELDS);
@@ -730,21 +727,20 @@ final class OkapiClient {
}
@NonNull
- private static JSONResult request(final OCApiConnector connector, final OkapiService service, final Parameters params) {
- if (connector == null) {
- return new JSONResult(null);
- }
-
+ private static JSONResult request(@NonNull final OCApiConnector connector, final OkapiService service, final Parameters params) {
final String host = connector.getHost();
if (StringUtils.isBlank(host)) {
- return new JSONResult(null);
+ return new JSONResult("unknown OKAPI connector host");
}
params.add("langpref", getPreferredLanguage());
if (connector.getSupportedAuthLevel() == OAuthLevel.Level3) {
- final ImmutablePair<String, String> tokens = Settings.getTokenPair(connector.getTokenPublicPrefKeyId(), connector.getTokenSecretPrefKeyId());
- OAuth.signOAuth(host, service.methodName, "GET", false, params, tokens.left, tokens.right, connector.getCK(), connector.getCS());
+ final OAuthTokens tokens = new OAuthTokens(connector);
+ if (!tokens.isValid()) {
+ return new JSONResult("invalid oauth tokens");
+ }
+ OAuth.signOAuth(host, service.methodName, "GET", false, params, tokens, connector.getCK(), connector.getCS());
} else {
connector.addAuthentication(params);
}
@@ -754,14 +750,14 @@ final class OkapiClient {
}
private static String getPreferredLanguage() {
- final String code = Locale.getDefault().getCountry();
+ final String code = Locale.getDefault().getLanguage();
if (StringUtils.isNotBlank(code)) {
return StringUtils.lowerCase(code) + "|en";
}
return "en";
}
- private static void addFilterParams(final Map<String, String> valueMap, final OCApiConnector connector, final boolean my) {
+ private static void addFilterParams(final Map<String, String> valueMap, @NonNull final OCApiConnector connector, final boolean my) {
if (!Settings.isExcludeDisabledCaches()) {
valueMap.put("status", "Available|Temporarily unavailable");
}
@@ -774,7 +770,7 @@ final class OkapiClient {
}
}
- private static void addRetrieveParams(final Parameters params, final OCApiConnector connector) {
+ private static void addRetrieveParams(final Parameters params, @NonNull final OCApiConnector connector) {
params.add("retr_method", METHOD_RETRIEVE_CACHES);
params.add("retr_params", "{\"fields\": \"" + getCoreFields(connector) + "\"}");
params.add("wrap", "true");
@@ -800,7 +796,7 @@ final class OkapiClient {
}
public static @Nullable
- String getUserUUID(final OCApiConnector connector, final String userName) {
+ String getUserUUID(@NonNull final OCApiConnector connector, final String userName) {
final Parameters params = new Parameters("fields", USER_UUID, USER_USERNAME, userName);
final JSONResult result = request(connector, OkapiService.SERVICE_USER_BY_USERNAME, params);
@@ -810,16 +806,7 @@ final class OkapiClient {
return null;
}
- final JSONObject data = result.data;
- if (!data.isNull(USER_UUID)) {
- try {
- return data.getString(USER_UUID);
- } catch (final JSONException e) {
- Log.e("OkapiClient.getUserUUID - uuid", e);
- }
- }
-
- return null;
+ return result.data.path(USER_UUID).asText(null);
}
public static UserInfo getUserInfo(final OCApiLiveConnector connector) {
@@ -833,31 +820,11 @@ final class OkapiClient {
return new UserInfo(StringUtils.EMPTY, 0, UserInfoStatus.getFromOkapiError(error.getResult()));
}
- final JSONObject data = result.data;
-
- String name = StringUtils.EMPTY;
- boolean successUserName = false;
-
- if (!data.isNull(USER_USERNAME)) {
- try {
- name = data.getString(USER_USERNAME);
- successUserName = true;
- } catch (final JSONException e) {
- Log.e("OkapiClient.getUserInfo - name", e);
- }
- }
-
- int finds = 0;
- boolean successFinds = false;
-
- if (!data.isNull(USER_CACHES_FOUND)) {
- try {
- finds = data.getInt(USER_CACHES_FOUND);
- successFinds = true;
- } catch (final JSONException e) {
- Log.e("OkapiClient.getUserInfo - finds", e);
- }
- }
+ final ObjectNode data = result.data;
+ final boolean successUserName = data.has(USER_USERNAME);
+ final String name = data.path(USER_USERNAME).asText();
+ final boolean successFinds = data.has(USER_CACHES_FOUND);
+ final int finds = data.path(USER_CACHES_FOUND).asInt();
return new UserInfo(name, finds, successUserName && successFinds ? UserInfoStatus.SUCCESSFUL : UserInfoStatus.FAILED);
}
@@ -874,7 +841,7 @@ final class OkapiClient {
if (!result.isSuccess) {
return new OkapiError(result.data);
}
- return new OkapiError(new JSONObject());
+ return new OkapiError(new ObjectNode(JsonUtils.factory));
}
/**
@@ -884,21 +851,27 @@ final class OkapiClient {
private static class JSONResult {
public final boolean isSuccess;
- public final JSONObject data;
+ public final ObjectNode data;
public JSONResult(final @Nullable HttpResponse response) {
- final boolean isSuccess = Network.isSuccess(response);
+ final boolean isRequestSuccessful = Network.isSuccess(response);
final String responseData = Network.getResponseDataAlways(response);
- JSONObject data = null;
+ ObjectNode tempData = null;
if (responseData != null) {
try {
- data = new JSONObject(responseData);
- } catch (final JSONException e) {
+ tempData = (ObjectNode) JsonUtils.reader.readTree(responseData);
+ } catch (IOException | ClassCastException e) {
Log.w("JSONResult", e);
}
}
- this.data = data;
- this.isSuccess = isSuccess && data != null;
+ data = tempData;
+ isSuccess = isRequestSuccessful && tempData != null;
+ }
+
+ public JSONResult(final @NonNull String errorMessage) {
+ isSuccess = false;
+ data = new ObjectNode(JsonUtils.factory);
+ data.putObject("error").put("developer_message", errorMessage);
}
}
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiError.java b/main/src/cgeo/geocaching/connector/oc/OkapiError.java
index 7faf2c7..f3234f8 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiError.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiError.java
@@ -2,11 +2,11 @@ package cgeo.geocaching.connector.oc;
import cgeo.geocaching.utils.Log;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.json.JSONException;
-import org.json.JSONObject;
/**
* Handles the JSON error response from OKAPI
@@ -26,7 +26,7 @@ public class OkapiError {
@NonNull private final OkapiErrors state;
@NonNull private final String message;
- public OkapiError(@Nullable JSONObject data) {
+ public OkapiError(@Nullable final ObjectNode data) {
// A null-response is by definition an error (some exception occurred somewhere in the flow)
if (data == null) {
@@ -39,10 +39,10 @@ public class OkapiError {
String localmessage = null;
OkapiErrors localstate = OkapiErrors.UNSPECIFIED;
try {
- JSONObject error = data.getJSONObject("error");
+ final ObjectNode error = (ObjectNode) data.get("error");
// Check reason_stack element to look for the specific oauth problems we want to report back
if (error.has("reason_stack")) {
- String reason = error.getString("reason_stack");
+ final String reason = error.get("reason_stack").asText();
if (StringUtils.contains(reason, "invalid_oauth_request")) {
if (StringUtils.contains(reason, "invalid_timestamp")) {
localstate = OkapiErrors.INVALID_TIMESTAMP;
@@ -53,10 +53,10 @@ public class OkapiError {
}
// Check if we can extract a message as well
if (error.has("developer_message")) {
- localmessage = error.getString("developer_message");
+ localmessage = error.get("developer_message").asText();
assert localmessage != null; // by virtue of defaultString
}
- } catch (JSONException ex) {
+ } catch (ClassCastException | NullPointerException ex) {
Log.d("OkapiError: Failed to parse JSON", ex);
localstate = OkapiErrors.UNSPECIFIED;
}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
index 51c8a7e..76e597c 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java
@@ -9,6 +9,9 @@ import cgeo.geocaching.connector.LogResult;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.StatusCode;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import android.net.Uri;
import java.util.Calendar;
@@ -19,7 +22,7 @@ public class OkapiLoggingManager extends AbstractLoggingManager {
private final OCApiLiveConnector connector;
private final Geocache cache;
- private LogCacheActivity activity;
+ private final LogCacheActivity activity;
private boolean hasLoaderError = true;
public OkapiLoggingManager(final LogCacheActivity activity, final OCApiLiveConnector connector, final Geocache cache) {
@@ -37,18 +40,21 @@ public class OkapiLoggingManager extends AbstractLoggingManager {
}
@Override
- public final LogResult postLog(final Geocache cache, final LogType logType, final Calendar date, final String log, final String logPassword, final List<TrackableLog> trackableLogs) {
+ @NonNull
+ public final LogResult postLog(@NonNull final LogType logType, @NonNull final Calendar date, @NonNull final String log, @Nullable final String logPassword, @NonNull final List<TrackableLog> trackableLogs) {
final LogResult result = OkapiClient.postLog(cache, logType, date, log, logPassword, connector);
connector.login(null, null);
return result;
}
@Override
+ @NonNull
public final ImageResult postLogImage(final String logId, final String imageCaption, final String imageDescription, final Uri imageUri) {
return new ImageResult(StatusCode.LOG_POST_ERROR, "");
}
@Override
+ @NonNull
public List<LogType> getPossibleLogTypes() {
if (hasLoaderError) {
return Collections.emptyList();
diff --git a/main/src/cgeo/geocaching/connector/oc/UserInfo.java b/main/src/cgeo/geocaching/connector/oc/UserInfo.java
index c8b37cd..42249b0 100644
--- a/main/src/cgeo/geocaching/connector/oc/UserInfo.java
+++ b/main/src/cgeo/geocaching/connector/oc/UserInfo.java
@@ -15,11 +15,11 @@ public class UserInfo {
public final int resId;
- UserInfoStatus(int resId) {
+ UserInfoStatus(final int resId) {
this.resId = resId;
}
- public static UserInfoStatus getFromOkapiError(OkapiErrors result) {
+ public static UserInfoStatus getFromOkapiError(final OkapiErrors result) {
switch (result) {
case NO_ERROR:
return SUCCESSFUL;
@@ -37,7 +37,7 @@ public class UserInfo {
private final int finds;
private final UserInfoStatus status;
- UserInfo(String name, int finds, UserInfoStatus status) {
+ UserInfo(final String name, final int finds, final UserInfoStatus status) {
this.name = name;
this.finds = finds;
this.status = status;
diff --git a/main/src/cgeo/geocaching/connector/ox/OXConnector.java b/main/src/cgeo/geocaching/connector/ox/OXConnector.java
index 7d4cf7f..d1db301 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXConnector.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXConnector.java
@@ -1,7 +1,6 @@
package cgeo.geocaching.connector.ox;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.ICache;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.capability.ISearchByCenter;
@@ -9,12 +8,13 @@ import cgeo.geocaching.connector.capability.ISearchByGeocode;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.connector.gc.MapTokens;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.CancellableHandler;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -30,33 +30,37 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
private static final Pattern PATTERN_GEOCODE = Pattern.compile("OX[A-Z0-9]+", Pattern.CASE_INSENSITIVE);
@Override
- public boolean canHandle(@NonNull String geocode) {
+ public boolean canHandle(@NonNull final String geocode) {
return PATTERN_GEOCODE.matcher(geocode).matches();
}
@Override
- public String getCacheUrl(@NonNull Geocache cache) {
+ @NonNull
+ public String getCacheUrl(@NonNull final Geocache cache) {
return getCacheUrlPrefix() + cache.getGeocode();
}
@Override
+ @NonNull
public String getName() {
return "OpenCaching.com";
}
@Override
+ @NonNull
public String getHost() {
return "www.opencaching.com";
}
@Override
- public String getLicenseText(@NonNull Geocache cache) {
+ @NonNull
+ public String getLicenseText(@NonNull final Geocache cache) {
// NOT TO BE TRANSLATED
return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons CC-BY-SA 3.0 License";
}
@Override
- public boolean isOwner(final ICache cache) {
+ public boolean isOwner(@NonNull final Geocache cache) {
return false;
}
@@ -74,17 +78,19 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
}
@Override
- public SearchResult searchByCenter(@NonNull Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
+ public SearchResult searchByCenter(@NonNull final Geopoint center, final @NonNull RecaptchaReceiver recaptchaReceiver) {
return createSearchResult(OpenCachingApi.searchByCenter(center));
}
@Override
+ @NonNull
protected String getCacheUrlPrefix() {
return "http://www.opencaching.com/#!geocache/";
}
@Override
- public SearchResult searchByViewport(@NonNull Viewport viewport, final MapTokens tokens) {
+ @NonNull
+ public SearchResult searchByViewport(@NonNull final Viewport viewport, @NonNull final MapTokens tokens) {
return createSearchResult(OpenCachingApi.searchByBoundingBox(viewport));
}
@@ -98,10 +104,20 @@ public class OXConnector extends AbstractConnector implements ISearchByCenter, I
return createSearchResult(OpenCachingApi.searchByKeyword(name));
}
- private static SearchResult createSearchResult(Collection<Geocache> caches) {
+ private static SearchResult createSearchResult(final Collection<Geocache> caches) {
if (caches == null) {
return null;
}
return new SearchResult(caches);
}
+
+ @Override
+ @Nullable
+ public String getGeocodeFromUrl(@NonNull final String url) {
+ final String geocode = StringUtils.substringAfter(url, "http://www.opencaching.com/de/#!geocache/");
+ if (canHandle(geocode)) {
+ return geocode;
+ }
+ return super.getGeocodeFromUrl(url);
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
index 7896826..25f66f4 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
@@ -29,7 +29,6 @@ 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. Additionally a space between type and (T/D/Awesomeness) is introduced.
*
- * @param cache
*/
private static void removeTitleFromShortDescription(final @NonNull Geocache cache) {
cache.setShortDescription(StringUtils.replace(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 b2afff5..a12a7fb 100644
--- a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
+++ b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
@@ -2,10 +2,10 @@ package cgeo.geocaching.connector.ox;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
@@ -39,19 +39,19 @@ public class OpenCachingApi {
return null;
}
- private static HttpResponse getRequest(String string, Parameters parameters) {
+ private static HttpResponse getRequest(final String uri, final Parameters parameters) {
parameters.add("Authorization", DEV_KEY);
- return Network.getRequest(string, parameters);
+ return Network.getRequest(uri, parameters);
}
private static Collection<Geocache> importCachesFromResponse(final HttpResponse response, final boolean isDetailed) {
if (response == null) {
return Collections.emptyList();
}
- Collection<Geocache> caches;
+ final Collection<Geocache> caches;
try {
- caches = new OXGPXParser(StoredList.TEMPORARY_LIST_ID, isDetailed).parse(response.getEntity().getContent(), null);
- } catch (Exception e) {
+ caches = new OXGPXParser(StoredList.TEMPORARY_LIST.id, isDetailed).parse(response.getEntity().getContent(), null);
+ } catch (final Exception e) {
Log.e("Error importing from OpenCaching.com", e);
return Collections.emptyList();
}
@@ -81,10 +81,10 @@ public class OpenCachingApi {
* Parameters to modify
* @return True - query possible, False - no query, all caches excluded
*/
- private static boolean addTypeFilter(Parameters queryParameters) {
+ private static boolean addTypeFilter(final Parameters queryParameters) {
boolean doQuery = true;
if (Settings.getCacheType() != CacheType.ALL) {
- String typeFilter;
+ final String typeFilter;
switch (Settings.getCacheType()) {
case TRADITIONAL:
typeFilter = "Traditional Cache";
diff --git a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
index fb554b9..03549d1 100644
--- a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.connector.trackable;
+import cgeo.geocaching.Trackable;
import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.UserAction;
@@ -16,14 +17,25 @@ public abstract class AbstractTrackableConnector implements TrackableConnector {
}
@Override
- public @Nullable
- String getTrackableCodeFromUrl(@NonNull String url) {
+ public boolean hasTrackableUrls() {
+ return true;
+ }
+
+ @Override
+ @Nullable
+ public String getTrackableCodeFromUrl(@NonNull final String url) {
return null;
}
@Override
- public @NonNull
- List<UserAction> getUserActions() {
+ @NonNull
+ public List<UserAction> getUserActions() {
return AbstractConnector.getDefaultUserActions();
}
+
+ @Override
+ @NonNull
+ public String getUrl(@NonNull final Trackable trackable) {
+ throw new IllegalStateException("this trackable does not have a corresponding URL");
+ }
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
index 03052f9..6f3749c 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
@@ -15,17 +15,19 @@ public class GeokretyConnector extends AbstractTrackableConnector {
private static final Pattern PATTERN_GK_CODE = Pattern.compile("GK[0-9A-F]{4,}");
@Override
- public boolean canHandleTrackable(String geocode) {
+ public boolean canHandleTrackable(final String geocode) {
return geocode != null && PATTERN_GK_CODE.matcher(geocode).matches();
}
@Override
- public String getUrl(Trackable trackable) {
+ @NonNull
+ public String getUrl(@NonNull final Trackable trackable) {
return "http://geokrety.org/konkret.php?id=" + getId(trackable.getGeocode());
}
@Override
- public Trackable searchTrackable(String geocode, String guid, String id) {
+ @Nullable
+ public Trackable searchTrackable(final String geocode, final String guid, final String id) {
final String page = Network.getResponseData(Network.getRequest("http://geokrety.org/export2.php?gkid=" + getId(geocode)));
if (page == null) {
return null;
@@ -33,32 +35,35 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return GeokretyParser.parse(page);
}
- protected static int getId(String geocode) {
+ protected static int getId(final String geocode) {
try {
final String hex = geocode.substring(2);
return Integer.parseInt(hex, 16);
} catch (final NumberFormatException e) {
- Log.e("Trackable.getUrl", e);
+ Log.e("Trackable.getId", e);
}
return -1;
}
@Override
public @Nullable
- String getTrackableCodeFromUrl(@NonNull String url) {
+ String getTrackableCodeFromUrl(@NonNull final 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));
}
+ // http://geokretymap.org/38545
+ id = StringUtils.substringAfterLast(url, "geokretymap.org/");
+ 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 0e64abd..a6e63ca 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -26,7 +26,7 @@ public class GeokretyParser {
geokret.setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String name) {
+ public void end(final String name) {
trackable.setName(name);
}
});
@@ -34,7 +34,7 @@ public class GeokretyParser {
geokret.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attributes) {
+ public void start(final Attributes attributes) {
try {
final String kretyId = attributes.getValue("id");
if (StringUtils.isNumeric(kretyId)) {
@@ -73,7 +73,7 @@ public class GeokretyParser {
return null;
}
- protected static String getType(int type) {
+ protected static String getType(final int type) {
switch (type) {
case 0:
return CgeoApplication.getInstance().getString(R.string.geokret_type_traditional);
diff --git a/main/src/cgeo/geocaching/connector/trackable/SwaggieConnector.java b/main/src/cgeo/geocaching/connector/trackable/SwaggieConnector.java
new file mode 100644
index 0000000..dcd618c
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/SwaggieConnector.java
@@ -0,0 +1,51 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.network.Network;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import java.util.regex.Pattern;
+
+public final class SwaggieConnector extends AbstractTrackableConnector {
+
+ private static final Pattern PATTERN_SW_CODE = Pattern.compile("SW[0-9]{4}");
+
+ @Override
+ public boolean canHandleTrackable(final String geocode) {
+ return geocode != null && PATTERN_SW_CODE.matcher(geocode).matches();
+ }
+
+ @Override
+ @NonNull
+ public String getUrl(@NonNull final Trackable trackable) {
+ return getUrl(trackable.getGeocode());
+ }
+
+ @Override
+ @Nullable
+ public Trackable searchTrackable(final String geocode, final String guid, final String id) {
+ final String page = Network.getResponseData(Network.getRequest(getUrl(geocode)));
+ if (page == null) {
+ return null;
+ }
+ return SwaggieParser.parse(page);
+ }
+
+ @Override
+ @Nullable
+ public String getTrackableCodeFromUrl(@NonNull final String url) {
+ final String geocode = StringUtils.upperCase(StringUtils.substringAfterLast(url, "swaggie/"));
+ if (canHandleTrackable(geocode)) {
+ return geocode;
+ }
+ return null;
+ }
+
+ private static String getUrl(final String geocode) {
+ return "http://geocaching.com.au/swaggie/" + geocode;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/SwaggieParser.java b/main/src/cgeo/geocaching/connector/trackable/SwaggieParser.java
new file mode 100644
index 0000000..1883056
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/trackable/SwaggieParser.java
@@ -0,0 +1,55 @@
+package cgeo.geocaching.connector.trackable;
+
+import cgeo.geocaching.Trackable;
+import cgeo.geocaching.utils.TextUtils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import java.util.regex.Pattern;
+
+final class SwaggieParser {
+
+ private SwaggieParser() {
+ // utility class
+ }
+
+ private static final Pattern PATTERN_NAME = Pattern.compile(Pattern.quote("<h1><a") + ".*?>(.*?)<");
+ private static final Pattern PATTERN_GEOCODE = Pattern.compile(Pattern.quote("'/swaggie/") + "(.*?)'");
+ private static final Pattern PATTERN_DESCRIPTION = Pattern.compile(Pattern.quote("'swaggie_description'>") + "(.*?)</div");
+ private static final Pattern PATTERN_OWNER = Pattern.compile(">([^<]*?)</a> released");
+
+ @Nullable
+ public static Trackable parse(@NonNull final String page) {
+ final Trackable trackable = new Trackable();
+ final String name = TextUtils.getMatch(page, PATTERN_NAME, null);
+ if (StringUtils.isEmpty(name)) {
+ return null;
+ }
+ trackable.setName(name);
+
+ final String geocode = TextUtils.getMatch(page, PATTERN_GEOCODE, null);
+ if (StringUtils.isEmpty(geocode)) {
+ return null;
+ }
+ trackable.setGeocode(geocode);
+
+ final String description = StringUtils.trim(TextUtils.getMatch(page, PATTERN_DESCRIPTION, StringUtils.EMPTY));
+ if (StringUtils.isEmpty(description)) {
+ return null;
+ }
+ trackable.setDetails(description);
+
+ final String owner = StringUtils.trim(TextUtils.getMatch(page, PATTERN_OWNER, StringUtils.EMPTY));
+ if (StringUtils.isEmpty(owner)) {
+ return null;
+ }
+ trackable.setOwner(owner);
+
+ trackable.setType("Swaggie");
+
+ return trackable;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
index 6071b5f..aea60e6 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
@@ -16,16 +16,33 @@ public interface TrackableConnector {
public boolean canHandleTrackable(final String geocode);
- public String getUrl(final Trackable trackable);
+ /**
+ * Check whether the connector has URLs corresponding the the trackable.
+ *
+ * @return <tt>true</tt> if the connector handles URLs, <tt>false</tt> otherwise
+ */
+ public boolean hasTrackableUrls();
+
+ /**
+ * Return the URL for a trackable. Might throw {@link IllegalStateException} if called
+ * on a connector which does not have URLs for trackables. This might be checked using
+ * {@link #hasTrackableUrls()}.
+ *
+ * @param trackable the trackable
+ * @return the URL corresponding to this trackable
+ */
+ @NonNull
+ public String getUrl(@NonNull final Trackable trackable);
public boolean isLoggable();
+ @Nullable
public Trackable searchTrackable(String geocode, String guid, String id);
- public @Nullable
- String getTrackableCodeFromUrl(final @NonNull String url);
+ @Nullable
+ public String getTrackableCodeFromUrl(final @NonNull String url);
- public @NonNull
- List<UserAction> getUserActions();
+ @NonNull
+ public List<UserAction> getUserActions();
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
index 77848d7..665ebea 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
@@ -20,12 +20,13 @@ public class TravelBugConnector extends AbstractTrackableConnector {
private final static Pattern PATTERN_TB_CODE = Pattern.compile("(TB[0-9A-Z]+)|([0-9A-Z]{6})", Pattern.CASE_INSENSITIVE);
@Override
- public boolean canHandleTrackable(String geocode) {
+ public boolean canHandleTrackable(final String geocode) {
return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches() && !StringUtils.startsWithIgnoreCase(geocode, "GC");
}
@Override
- public String getUrl(Trackable trackable) {
+ @NonNull
+ public String getUrl(@NonNull final Trackable trackable) {
return "http://www.geocaching.com//track/details.aspx?tracker=" + trackable.getGeocode();
}
@@ -35,7 +36,8 @@ public class TravelBugConnector extends AbstractTrackableConnector {
}
@Override
- public Trackable searchTrackable(String geocode, String guid, String id) {
+ @Nullable
+ public Trackable searchTrackable(final String geocode, final String guid, final String id) {
return GCParser.searchTrackable(geocode, guid, id);
}
@@ -56,15 +58,15 @@ public class TravelBugConnector extends AbstractTrackableConnector {
@Override
public @Nullable
- String getTrackableCodeFromUrl(@NonNull String url) {
+ String getTrackableCodeFromUrl(@NonNull final String url) {
// coord.info URLs
- String code = StringUtils.substringAfterLast(url, "coord.info/");
- if (code != null && canHandleTrackable(code)) {
- return code;
+ final String code1 = StringUtils.substringAfterLast(url, "coord.info/");
+ if (canHandleTrackable(code1)) {
+ return code1;
}
- code = StringUtils.substringAfterLast(url, "?tracker=");
- if (code != null && canHandleTrackable(code)) {
- return code;
+ final String code2 = StringUtils.substringAfterLast(url, "?tracker=");
+ if (canHandleTrackable(code2)) {
+ return code2;
}
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java
index 0295927..885df7e 100644
--- a/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/UnknownTrackableConnector.java
@@ -2,22 +2,23 @@ package cgeo.geocaching.connector.trackable;
import cgeo.geocaching.Trackable;
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
public class UnknownTrackableConnector extends AbstractTrackableConnector {
@Override
- public boolean canHandleTrackable(String geocode) {
+ public boolean canHandleTrackable(final String geocode) {
return false;
}
@Override
- public String getUrl(Trackable trackable) {
- return StringUtils.EMPTY;
+ public boolean hasTrackableUrls() {
+ return false;
}
@Override
- public Trackable searchTrackable(String geocode, String guid, String id) {
+ @Nullable
+ public Trackable searchTrackable(final String geocode, final String guid, final String id) {
return null;
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
index 1fdb0ac..770b63b 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheAttribute.java
@@ -4,10 +4,11 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import android.util.SparseArray;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -129,19 +130,22 @@ public enum CacheAttribute {
// THIS LIST IS GENERATED: don't change anything here but read
// project/attributes/readme.txt
+ @NonNull
private static final String INTERNAL_YES = "_yes";
+ @NonNull
private static final String INTERNAL_NO = "_no";
public static final int NO_ID = -1;
public final int gcid;
public final int ocacode;
+ @NonNull
public final String rawName;
public final int drawableId;
public final int stringIdYes;
public final int stringIdNo;
- CacheAttribute(final int gcid, final int ocacode, final String rawName,
+ CacheAttribute(final int gcid, final int ocacode, @NonNull final String rawName,
final int drawableId, final int stringIdYes, final int stringIdNo) {
this.gcid = gcid;
this.ocacode = ocacode;
@@ -158,44 +162,45 @@ public enum CacheAttribute {
* true: for positive text, false: for negative text
* @return the localized text
*/
+ @NonNull
public String getL10n(final boolean enabled) {
return CgeoApplication.getInstance().getResources().getString(
enabled ? stringIdYes : stringIdNo);
}
- private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME;
+ @NonNull
+ private final static Map<String, CacheAttribute> FIND_BY_GCRAWNAME = new HashMap<>();
+ @NonNull
private final static SparseArray<CacheAttribute> FIND_BY_OCACODE = new SparseArray<>();
static {
- final HashMap<String, CacheAttribute> mapGcRawNames = new HashMap<>();
- for (CacheAttribute attr : values()) {
- mapGcRawNames.put(attr.rawName, attr);
+ for (final CacheAttribute attr : values()) {
+ FIND_BY_GCRAWNAME.put(attr.rawName, attr);
if (attr.ocacode != NO_ID) {
FIND_BY_OCACODE.put(attr.ocacode, attr);
}
}
- FIND_BY_GCRAWNAME = Collections.unmodifiableMap(mapGcRawNames);
}
- public static CacheAttribute getByRawName(final String rawName) {
+ @Nullable
+ public static CacheAttribute getByRawName(@Nullable final String rawName) {
return rawName != null ? FIND_BY_GCRAWNAME.get(rawName) : null;
}
+ @Nullable
public static CacheAttribute getByOcACode(final int ocAcode) {
return FIND_BY_OCACODE.get(ocAcode);
}
- public static String trimAttributeName(String attributeName) {
+ @NonNull
+ public static String trimAttributeName(@Nullable final String attributeName) {
if (null == attributeName) {
return "";
}
return attributeName.replace(INTERNAL_YES, "").replace(INTERNAL_NO, "").trim();
}
- public static boolean isEnabled(final String attributeName) {
+ public static boolean isEnabled(@Nullable final String attributeName) {
return !StringUtils.endsWithIgnoreCase(attributeName, INTERNAL_NO);
}
- public String getAttributeName(final boolean yes) {
- return rawName + (yes ? INTERNAL_YES : INTERNAL_NO);
- }
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheListType.java b/main/src/cgeo/geocaching/enumerations/CacheListType.java
index 1fce282..297e1be 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheListType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheListType.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType;
+import org.eclipse.jdt.annotation.NonNull;
+
public enum CacheListType {
OFFLINE(true, CacheListLoaderType.OFFLINE),
POCKET(false, CacheListLoaderType.POCKET),
@@ -19,9 +21,9 @@ public enum CacheListType {
*/
public final boolean canSwitch;
- public final CacheListLoaderType loaderType;
+ @NonNull public final CacheListLoaderType loaderType;
- CacheListType(final boolean canSwitch, final CacheListLoaderType loaderType) {
+ CacheListType(final boolean canSwitch, @NonNull final CacheListLoaderType loaderType) {
this.canSwitch = canSwitch;
this.loaderType = loaderType;
}
diff --git a/main/src/cgeo/geocaching/enumerations/CacheSize.java b/main/src/cgeo/geocaching/enumerations/CacheSize.java
index c4e2831..10c8c9f 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheSize.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheSize.java
@@ -3,7 +3,9 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import java.util.Collections;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -23,6 +25,7 @@ public enum CacheSize {
OTHER("Other", 8, R.string.cache_size_other, "other"),
UNKNOWN("Unknown", -1, R.string.cache_size_unknown, ""); // CacheSize not init. yet
+ @NonNull
public final String id;
public final int comparable;
private final int stringId;
@@ -31,26 +34,26 @@ public enum CacheSize {
*/
private final String ocSize2;
- CacheSize(final String id, final int comparable, final int stringId, final String ocSize2) {
+ CacheSize(@NonNull 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;
+ @NonNull
+ final private static Map<String, CacheSize> FIND_BY_ID = new HashMap<>();
static {
- final HashMap<String, CacheSize> mapping = new HashMap<>();
for (final CacheSize cs : values()) {
- mapping.put(cs.id.toLowerCase(Locale.US), cs);
- mapping.put(cs.ocSize2.toLowerCase(Locale.US), cs);
+ FIND_BY_ID.put(cs.id.toLowerCase(Locale.US), cs);
+ FIND_BY_ID.put(cs.ocSize2.toLowerCase(Locale.US), cs);
}
// add medium as additional string for Regular
- mapping.put("medium", CacheSize.REGULAR);
- FIND_BY_ID = Collections.unmodifiableMap(mapping);
+ FIND_BY_ID.put("medium", CacheSize.REGULAR);
}
- public static CacheSize getById(final String id) {
+ @NonNull
+ public static CacheSize getById(@Nullable final String id) {
if (id == null) {
return UNKNOWN;
}
@@ -69,10 +72,8 @@ public enum CacheSize {
/**
* Bad GPX files can contain the container size encoded as number.
- *
- * @param id
- * @return
*/
+ @NonNull
private static CacheSize getByNumber(final String id) {
try {
final int numerical = Integer.parseInt(id);
@@ -83,12 +84,13 @@ public enum CacheSize {
}
}
}
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// ignore, as this might be a number or not
}
return UNKNOWN;
}
+ @NonNull
public final String getL10n() {
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 1d190e4..a6c32d9 100644
--- a/main/src/cgeo/geocaching/enumerations/CacheType.java
+++ b/main/src/cgeo/geocaching/enumerations/CacheType.java
@@ -1,10 +1,11 @@
package cgeo.geocaching.enumerations;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.ICache;
+import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import java.util.Collections;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -14,26 +15,26 @@ import java.util.Map;
*/
public enum CacheType {
- TRADITIONAL("traditional", "Traditional Cache", "32bc9333-5e52-4957-b0f6-5a2c8fc7b257", R.string.traditional, R.drawable.type_traditional),
- MULTI("multi", "Multi-cache", "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74", R.string.multi, R.drawable.type_multi),
- MYSTERY("mystery", "Unknown Cache", "40861821-1835-4e11-b666-8d41064d03fe", R.string.mystery, R.drawable.type_mystery),
- LETTERBOX("letterbox", "Letterbox hybrid", "4bdd8fb2-d7bc-453f-a9c5-968563b15d24", R.string.letterbox, R.drawable.type_letterbox),
- EVENT("event", "Event Cache", "69eb8534-b718-4b35-ae3c-a856a55b0874", R.string.event, R.drawable.type_event),
- MEGA_EVENT("mega", "Mega-Event Cache", "69eb8535-b718-4b35-ae3c-a856a55b0874", R.string.mega, R.drawable.type_mega),
- GIGA_EVENT("giga", "Giga-Event Cache", "51420629-5739-4945-8bdd-ccfd434c0ead", R.string.giga, R.drawable.type_giga),
- EARTH("earth", "Earthcache", "c66f5cf3-9523-4549-b8dd-759cd2f18db8", R.string.earth, R.drawable.type_earth),
- CITO("cito", "Cache in Trash out Event", "57150806-bc1a-42d6-9cf0-538d171a2d22", R.string.cito, R.drawable.type_cito),
- WEBCAM("webcam", "Webcam Cache", "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d", R.string.webcam, R.drawable.type_webcam),
- VIRTUAL("virtual", "Virtual Cache", "294d4360-ac86-4c83-84dd-8113ef678d7e", R.string.virtual, R.drawable.type_virtual),
- WHERIGO("wherigo", "Wherigo Cache", "0544fa55-772d-4e5c-96a9-36a51ebcf5c9", R.string.wherigo, R.drawable.type_wherigo),
- LOSTANDFOUND("lostfound", "Lost and Found Event Cache", "3ea6533d-bb52-42fe-b2d2-79a3424d4728", R.string.lostfound, R.drawable.type_event), // icon missing
- PROJECT_APE("ape", "Project Ape Cache", "2555690d-b2bc-4b55-b5ac-0cb704c0b768", R.string.ape, R.drawable.type_ape),
- GCHQ("gchq", "Groundspeak HQ", "416f2494-dc17-4b6a-9bab-1a29dd292d8c", R.string.gchq, R.drawable.type_hq),
- GPS_EXHIBIT("gps", "GPS Adventures Exhibit", "72e69af2-7986-4990-afd9-bc16cbbb4ce3", R.string.gps, R.drawable.type_event), // icon missing
- BLOCK_PARTY("block", "Groundspeak Block Party", "bc2f3df2-1aab-4601-b2ff-b5091f6c02e3", R.string.block, R.drawable.type_event), // icon missing
- UNKNOWN("unknown", "unknown", "", R.string.unknown, R.drawable.type_unknown),
+ TRADITIONAL("traditional", "Traditional Cache", "32bc9333-5e52-4957-b0f6-5a2c8fc7b257", R.string.traditional, R.drawable.type_traditional, "2"),
+ MULTI("multi", "Multi-cache", "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74", R.string.multi, R.drawable.type_multi, "3"),
+ MYSTERY("mystery", "Unknown Cache", "40861821-1835-4e11-b666-8d41064d03fe", R.string.mystery, R.drawable.type_mystery, "8"),
+ LETTERBOX("letterbox", "Letterbox hybrid", "4bdd8fb2-d7bc-453f-a9c5-968563b15d24", R.string.letterbox, R.drawable.type_letterbox, "5"),
+ EVENT("event", "Event Cache", "69eb8534-b718-4b35-ae3c-a856a55b0874", R.string.event, R.drawable.type_event, "6"),
+ MEGA_EVENT("mega", "Mega-Event Cache", "69eb8535-b718-4b35-ae3c-a856a55b0874", R.string.mega, R.drawable.type_mega, "453"),
+ GIGA_EVENT("giga", "Giga-Event Cache", "51420629-5739-4945-8bdd-ccfd434c0ead", R.string.giga, R.drawable.type_giga, "7005"),
+ EARTH("earth", "Earthcache", "c66f5cf3-9523-4549-b8dd-759cd2f18db8", R.string.earth, R.drawable.type_earth, "137"),
+ CITO("cito", "Cache in Trash out Event", "57150806-bc1a-42d6-9cf0-538d171a2d22", R.string.cito, R.drawable.type_cito, "13"),
+ WEBCAM("webcam", "Webcam Cache", "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d", R.string.webcam, R.drawable.type_webcam, "11"),
+ VIRTUAL("virtual", "Virtual Cache", "294d4360-ac86-4c83-84dd-8113ef678d7e", R.string.virtual, R.drawable.type_virtual, "4"),
+ WHERIGO("wherigo", "Wherigo Cache", "0544fa55-772d-4e5c-96a9-36a51ebcf5c9", R.string.wherigo, R.drawable.type_wherigo, "1858"),
+ LOSTANDFOUND("lostfound", "Lost and Found Event Cache", "3ea6533d-bb52-42fe-b2d2-79a3424d4728", R.string.lostfound, R.drawable.type_event, "3653"), // icon missing
+ PROJECT_APE("ape", "Project Ape Cache", "2555690d-b2bc-4b55-b5ac-0cb704c0b768", R.string.ape, R.drawable.type_ape, "2"),
+ GCHQ("gchq", "Groundspeak HQ", "416f2494-dc17-4b6a-9bab-1a29dd292d8c", R.string.gchq, R.drawable.type_hq, "3773"),
+ GPS_EXHIBIT("gps", "GPS Adventures Exhibit", "72e69af2-7986-4990-afd9-bc16cbbb4ce3", R.string.gps, R.drawable.type_event, "1304"), // icon missing
+ BLOCK_PARTY("block", "Groundspeak Block Party", "bc2f3df2-1aab-4601-b2ff-b5091f6c02e3", R.string.block, R.drawable.type_event, "4738"), // icon missing
+ UNKNOWN("unknown", "unknown", "", R.string.unknown, R.drawable.type_unknown, ""),
/** No real cache type -> filter */
- ALL("all", "display all caches", "9a79e6ce-3344-409c-bbe9-496530baf758", R.string.all_types, R.drawable.type_unknown);
+ ALL("all", "display all caches", "9a79e6ce-3344-409c-bbe9-496530baf758", R.string.all_types, R.drawable.type_unknown, "");
/**
* id field is used when for storing caches in the database.
@@ -47,37 +48,39 @@ public enum CacheType {
public final String guid;
private final int stringId;
public final int markerId;
+ @NonNull public final String wptTypeId;
- CacheType(String id, String pattern, String guid, int stringId, int markerId) {
+ CacheType(final String id, final String pattern, final String guid, final int stringId, final int markerId, @NonNull final String wptTypeId) {
this.id = id;
this.pattern = pattern;
this.guid = guid;
this.stringId = stringId;
this.markerId = markerId;
+ this.wptTypeId = wptTypeId;
}
- private final static Map<String, CacheType> FIND_BY_ID;
- private final static Map<String, CacheType> FIND_BY_PATTERN;
- private final static Map<String, CacheType> FIND_BY_GUID;
+ @NonNull
+ private final static Map<String, CacheType> FIND_BY_ID = new HashMap<>();
+ @NonNull
+ private final static Map<String, CacheType> FIND_BY_PATTERN = new HashMap<>();
+ @NonNull
+ private final static Map<String, CacheType> FIND_BY_GUID = new HashMap<>();
+
static {
- final HashMap<String, CacheType> mappingId = new HashMap<>();
- final HashMap<String, CacheType> mappingPattern = new HashMap<>();
- final HashMap<String, CacheType> mappingGuid = new HashMap<>();
- for (CacheType ct : values()) {
- mappingId.put(ct.id, ct);
- mappingPattern.put(ct.pattern.toLowerCase(Locale.US), ct);
- mappingGuid.put(ct.guid, ct);
+ for (final CacheType ct : values()) {
+ FIND_BY_ID.put(ct.id, ct);
+ FIND_BY_PATTERN.put(ct.pattern.toLowerCase(Locale.US), ct);
+ FIND_BY_GUID.put(ct.guid, ct);
}
// Add old mystery type for GPX file compatibility.
- mappingPattern.put("Mystery Cache".toLowerCase(Locale.US), MYSTERY);
+ FIND_BY_PATTERN.put("Mystery Cache".toLowerCase(Locale.US), MYSTERY);
// This pattern briefly appeared on gc.com in 2014-08.
- mappingPattern.put("Traditional Geocache".toLowerCase(Locale.US), TRADITIONAL);
-
- FIND_BY_ID = Collections.unmodifiableMap(mappingId);
- FIND_BY_PATTERN = Collections.unmodifiableMap(mappingPattern);
- FIND_BY_GUID = Collections.unmodifiableMap(mappingGuid);
+ FIND_BY_PATTERN.put("Traditional Geocache".toLowerCase(Locale.US), TRADITIONAL);
+ // map lab caches to the virtual type for the time being
+ FIND_BY_PATTERN.put("Lab Cache".toLowerCase(Locale.US), VIRTUAL);
}
+ @NonNull
public static CacheType getById(final String id) {
final CacheType result = (id != null) ? CacheType.FIND_BY_ID.get(id.toLowerCase(Locale.US).trim()) : null;
if (result == null) {
@@ -86,6 +89,7 @@ public enum CacheType {
return result;
}
+ @NonNull
public static CacheType getByPattern(final String pattern) {
final CacheType result = (pattern != null) ? CacheType.FIND_BY_PATTERN.get(pattern.toLowerCase(Locale.US).trim()) : null;
if (result == null) {
@@ -94,6 +98,7 @@ public enum CacheType {
return result;
}
+ @NonNull
public static CacheType getByGuid(final String id) {
final CacheType result = (id != null) ? CacheType.FIND_BY_GUID.get(id) : null;
if (result == null) {
@@ -102,6 +107,7 @@ public enum CacheType {
return result;
}
+ @NonNull
public final String getL10n() {
return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
}
@@ -118,10 +124,9 @@ public enum CacheType {
/**
* Whether this type contains the given cache.
*
- * @param cache
* @return true if this is the ALL type or if this type equals the type of the cache.
*/
- public boolean contains(ICache cache) {
+ public boolean contains(final Geocache cache) {
if (cache == null) {
return false;
}
diff --git a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java b/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
deleted file mode 100644
index 5bcaf4a..0000000
--- a/main/src/cgeo/geocaching/enumerations/LiveMapStrategy.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package cgeo.geocaching.enumerations;
-
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.R;
-
-import java.util.EnumSet;
-
-/**
- * Defines the strategy for the Live Map
- */
-public interface LiveMapStrategy {
-
- public enum StrategyFlag {
- LOAD_TILES, // 2x2 tiles filling the complete viewport
- PARSE_TILES, // parse PNG images
- SEARCH_NEARBY // searchByCoords()
- }
-
- public enum Strategy {
- FASTEST(1, EnumSet.of(StrategyFlag.LOAD_TILES), R.string.map_strategy_fastest),
- FAST(2, EnumSet.of(StrategyFlag.LOAD_TILES, StrategyFlag.PARSE_TILES), R.string.map_strategy_fast),
- AUTO(3, EnumSet.noneOf(StrategyFlag.class), R.string.map_strategy_auto),
- DETAILED(4, EnumSet.allOf(StrategyFlag.class), R.string.map_strategy_detailed);
-
- public final int id;
- public final EnumSet<StrategyFlag> flags;
- private final int stringId;
-
- Strategy(int id, EnumSet<StrategyFlag> flags, int stringId) {
- this.id = id;
- this.flags = flags;
- this.stringId = stringId;
- }
-
- public static Strategy getById(final int id) {
- for (Strategy strategy : Strategy.values()) {
- if (strategy.id == id) {
- return strategy;
- }
- }
- return AUTO;
- }
-
- public final String getL10n() {
- return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
- }
- }
-}
diff --git a/main/src/cgeo/geocaching/enumerations/LoadFlags.java b/main/src/cgeo/geocaching/enumerations/LoadFlags.java
index c781f4b..0f08690 100644
--- a/main/src/cgeo/geocaching/enumerations/LoadFlags.java
+++ b/main/src/cgeo/geocaching/enumerations/LoadFlags.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.enumerations;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.EnumSet;
/**
@@ -22,9 +24,9 @@ public interface LoadFlags {
/** Retrieve cache from CacheCache only. Do not load from DB */
public final static EnumSet<LoadFlag> LOAD_CACHE_ONLY = EnumSet.of(LoadFlag.CACHE_BEFORE);
/** Retrieve cache from CacheCache first. If not found load from DB */
- public final static EnumSet<LoadFlag> LOAD_CACHE_OR_DB = EnumSet.of(LoadFlag.CACHE_BEFORE, LoadFlag.DB_MINIMAL, LoadFlag.OFFLINE_LOG);
+ public final static EnumSet<LoadFlag> LOAD_CACHE_OR_DB = EnumSet.of(LoadFlag.CACHE_BEFORE, LoadFlag.DB_MINIMAL, LoadFlag.OFFLINE_LOG, LoadFlag.SPOILERS);
/** Retrieve cache (minimalistic information including waypoints) from DB first. If not found load from CacheCache */
- public final static EnumSet<LoadFlag> LOAD_WAYPOINTS = EnumSet.of(LoadFlag.CACHE_AFTER, LoadFlag.DB_MINIMAL, LoadFlag.WAYPOINTS, LoadFlag.OFFLINE_LOG);
+ public final static EnumSet<LoadFlag> LOAD_WAYPOINTS = EnumSet.of(LoadFlag.CACHE_AFTER, LoadFlag.DB_MINIMAL, LoadFlag.WAYPOINTS, LoadFlag.OFFLINE_LOG, LoadFlag.SPOILERS);
/** Retrieve cache (all stored informations) from DB only. Do not load from CacheCache */
public final static EnumSet<LoadFlag> LOAD_ALL_DB_ONLY = EnumSet.range(LoadFlag.DB_MINIMAL, LoadFlag.OFFLINE_LOG);
@@ -33,6 +35,7 @@ public interface LoadFlags {
DB // include saving to CacheCache
}
+ @NonNull
public final static EnumSet<SaveFlag> SAVE_ALL = EnumSet.allOf(SaveFlag.class);
public enum RemoveFlag {
@@ -41,6 +44,7 @@ public interface LoadFlags {
OWN_WAYPOINTS_ONLY_FOR_TESTING // only to be used in unit testing (as we never delete own waypoints)
}
+ @NonNull
public final static EnumSet<RemoveFlag> REMOVE_ALL = EnumSet.of(RemoveFlag.CACHE, RemoveFlag.DB);
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java
index 84ab7b9..bf0d66c 100644
--- a/main/src/cgeo/geocaching/enumerations/LogType.java
+++ b/main/src/cgeo/geocaching/enumerations/LogType.java
@@ -3,7 +3,9 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import java.util.Collections;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -46,13 +48,16 @@ public enum LogType {
UNKNOWN(0, "unknown", "", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet
public final int id;
+ @Nullable
public final String iconName;
+ @NonNull
public final String type;
+ @NonNull
public final String oc_type;
private final int stringId;
public final int markerId;
- LogType(int id, String iconName, String type, String oc_type, int stringId, int markerId) {
+ LogType(final int id, @Nullable final String iconName, @NonNull final String type, @NonNull final String oc_type, final int stringId, final int markerId) {
this.id = id;
this.iconName = iconName;
this.type = type;
@@ -61,27 +66,24 @@ public enum LogType {
this.markerId = markerId;
}
- LogType(int id, String iconName, String type, String oc_type, int stringId) {
+ LogType(final int id, final String iconName, final String type, final String oc_type, final int stringId) {
this(id, iconName, type, oc_type, stringId, R.drawable.mark_gray);
}
- private final static Map<String, LogType> FIND_BY_ICONNAME;
- private final static Map<String, LogType> FIND_BY_TYPE;
+ private final static Map<String, LogType> FIND_BY_ICONNAME = new HashMap<>();
+ private final static Map<String, LogType> FIND_BY_TYPE = new HashMap<>();
static {
- final HashMap<String, LogType> mappingPattern = new HashMap<>();
- final HashMap<String, LogType> mappingType = new HashMap<>();
- for (LogType lt : values()) {
+ for (final LogType lt : values()) {
if (lt.iconName != null) {
- mappingPattern.put(lt.iconName, lt);
+ FIND_BY_ICONNAME.put(lt.iconName, lt);
}
- mappingType.put(lt.type, lt);
+ FIND_BY_TYPE.put(lt.type, lt);
}
- FIND_BY_ICONNAME = Collections.unmodifiableMap(mappingPattern);
- FIND_BY_TYPE = Collections.unmodifiableMap(mappingType);
}
+ @NonNull
public static LogType getById(final int id) {
- for (LogType logType : values()) {
+ for (final LogType logType : values()) {
if (logType.id == id) {
return logType;
}
@@ -89,6 +91,7 @@ public enum LogType {
return UNKNOWN;
}
+ @NonNull
public static LogType getByIconName(final String imageType) {
// Special case for post reviewer note, which appears sometimes as 18.png (in individual entries) or as 68.png
// (in logs counts).
@@ -102,6 +105,7 @@ public enum LogType {
return result;
}
+ @NonNull
public static LogType getByType(final String type) {
final LogType result = type != null ? LogType.FIND_BY_TYPE.get(type.toLowerCase(Locale.US).trim()) : null;
if (result == null) {
@@ -110,7 +114,16 @@ public enum LogType {
return result;
}
+ @NonNull
public final String getL10n() {
return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
}
+
+ public final boolean isFoundLog() {
+ return this == LogType.FOUND_IT || this == LogType.ATTENDED || this == LogType.WEBCAM_PHOTO_TAKEN;
+ }
+
+ public boolean mustConfirmLog() {
+ return this == ARCHIVE || this == NEEDS_ARCHIVE;
+ }
}
diff --git a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
index e008294..05ce6fd 100644
--- a/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
+++ b/main/src/cgeo/geocaching/enumerations/LogTypeTrackable.java
@@ -3,19 +3,22 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
public enum LogTypeTrackable {
DO_NOTHING("", R.string.log_tb_nothing),
VISITED("_Visited", R.string.log_tb_visit),
DROPPED_OFF("_DroppedOff", R.string.log_tb_drop);
- final public String action;
+ @NonNull final public String action;
final private int resourceId;
- LogTypeTrackable(String action, int resourceId) {
+ LogTypeTrackable(@NonNull final String action, final int resourceId) {
this.action = action;
this.resourceId = resourceId;
}
+ @NonNull
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 8bda371..37d027f 100644
--- a/main/src/cgeo/geocaching/enumerations/StatusCode.java
+++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.content.res.Resources;
public enum StatusCode {
@@ -21,14 +23,13 @@ public enum StatusCode {
PREMIUM_ONLY(R.string.err_premium_only),
MAINTENANCE(R.string.err_maintenance),
LOG_POST_ERROR(R.string.err_log_post_failed),
- LOG_POST_ERROR_EC(R.string.err_log_post_failed_ec),
NO_LOG_TEXT(R.string.warn_log_text_fill),
NOT_LOGGED_IN(R.string.init_login_popup_failed),
LOGIMAGE_POST_ERROR(R.string.err_logimage_post_failed);
final private int error_string;
- StatusCode(int error_string) {
+ StatusCode(final int error_string) {
this.error_string = error_string;
}
@@ -36,6 +37,7 @@ public enum StatusCode {
return error_string;
}
+ @NonNull
public String getErrorString(final Resources res) {
return res.getString(error_string);
}
diff --git a/main/src/cgeo/geocaching/enumerations/WaypointType.java b/main/src/cgeo/geocaching/enumerations/WaypointType.java
index 1805635..d2281ef 100644
--- a/main/src/cgeo/geocaching/enumerations/WaypointType.java
+++ b/main/src/cgeo/geocaching/enumerations/WaypointType.java
@@ -3,6 +3,8 @@ package cgeo.geocaching.enumerations;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -22,11 +24,12 @@ public enum WaypointType {
WAYPOINT("waypoint", R.string.wp_waypoint, R.drawable.waypoint_waypoint),
ORIGINAL("original", R.string.wp_original, R.drawable.waypoint_waypoint);
+ @NonNull
public final String id;
public final int stringId;
public final int markerId;
- WaypointType(String id, int stringId, int markerId) {
+ WaypointType(@NonNull final String id, final int stringId, final int markerId) {
this.id = id;
this.stringId = stringId;
this.markerId = markerId;
@@ -36,34 +39,36 @@ public enum WaypointType {
* inverse lookup of waypoint IDs<br/>
* non public so that <code>null</code> handling can be handled centrally in the enum type itself
*/
- private static final Map<String, WaypointType> FIND_BY_ID;
- public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL = new HashSet<>();
+ private static final Map<String, WaypointType> FIND_BY_ID = new HashMap<>();
+ private static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL_TMP = new HashSet<>();
static {
- final HashMap<String, WaypointType> mapping = new HashMap<>();
- for (WaypointType wt : values()) {
- mapping.put(wt.id, wt);
+ for (final WaypointType wt : values()) {
+ FIND_BY_ID.put(wt.id, wt);
if (wt != WaypointType.OWN && wt != WaypointType.ORIGINAL) {
- ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL.add(wt);
+ ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL_TMP.add(wt);
}
}
- FIND_BY_ID = Collections.unmodifiableMap(mapping);
}
+ @NonNull
+ public static final Set<WaypointType> ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL = Collections.unmodifiableSet(ALL_TYPES_EXCEPT_OWN_AND_ORIGINAL_TMP);
/**
* inverse lookup of waypoint IDs<br/>
* here the <code>null</code> handling shall be done
*/
+ @NonNull
public static WaypointType findById(final String id) {
if (null == id) {
return WAYPOINT;
}
- WaypointType waypointType = FIND_BY_ID.get(id);
+ final WaypointType waypointType = FIND_BY_ID.get(id);
if (null == waypointType) {
return WAYPOINT;
}
return waypointType;
}
+ @NonNull
public final String getL10n() {
return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
}
diff --git a/main/src/cgeo/geocaching/export/AbstractExport.java b/main/src/cgeo/geocaching/export/AbstractExport.java
index 5d15ecb..94d0506 100644
--- a/main/src/cgeo/geocaching/export/AbstractExport.java
+++ b/main/src/cgeo/geocaching/export/AbstractExport.java
@@ -22,7 +22,7 @@ abstract class AbstractExport implements Export {
* the resource id of the string
* @return localized string
*/
- protected static String getString(int resourceId) {
+ protected static String getString(final int resourceId) {
return CgeoApplication.getInstance().getString(resourceId);
}
@@ -35,7 +35,7 @@ abstract class AbstractExport implements Export {
* The parameter
* @return localized string
*/
- protected static String getString(int resourceId, Object... params) {
+ protected static String getString(final int resourceId, final Object... params) {
return CgeoApplication.getInstance().getString(resourceId, params);
}
diff --git a/main/src/cgeo/geocaching/export/FieldNotes.java b/main/src/cgeo/geocaching/export/FieldNotes.java
index 11d725a..fdc6210 100644
--- a/main/src/cgeo/geocaching/export/FieldNotes.java
+++ b/main/src/cgeo/geocaching/export/FieldNotes.java
@@ -41,7 +41,7 @@ class FieldNotes {
return buffer.toString();
}
- File writeToDirectory(File exportLocation) {
+ File writeToDirectory(final File exportLocation) {
if (!LocalStorage.isExternalStorageAvailable()) {
return null;
}
diff --git a/main/src/cgeo/geocaching/export/FieldnoteExport.java b/main/src/cgeo/geocaching/export/FieldnoteExport.java
index c03b848..c4a6adc 100644
--- a/main/src/cgeo/geocaching/export/FieldnoteExport.java
+++ b/main/src/cgeo/geocaching/export/FieldnoteExport.java
@@ -59,10 +59,11 @@ public class FieldnoteExport extends AbstractExport {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final Context themedContext;
- if (Settings.isLightSkin() && VERSION.SDK_INT < VERSION_CODES.HONEYCOMB)
+ if (Settings.isLightSkin() && VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) {
themedContext = new ContextThemeWrapper(activity, R.style.dark);
- else
+ } else {
themedContext = activity;
+ }
final View layout = View.inflate(themedContext, R.layout.fieldnote_export_dialog, null);
builder.setView(layout);
@@ -135,8 +136,10 @@ public class FieldnoteExport extends AbstractExport {
for (final Geocache cache : caches) {
if (ConnectorFactory.getConnector(cache).equals(connector) && cache.isLogOffline()) {
final LogEntry log = DataStore.loadLogOffline(cache.getGeocode());
- if (!onlyNew || log.date > Settings.getFieldnoteExportDate()) {
- fieldNotes.add(cache, log);
+ if (log != null) {
+ if (!onlyNew || log.date > Settings.getFieldnoteExportDate()) {
+ fieldNotes.add(cache, log);
+ }
}
}
publishProgress(++i);
diff --git a/main/src/cgeo/geocaching/export/GpxExport.java b/main/src/cgeo/geocaching/export/GpxExport.java
index 61d03bc..af564da 100644
--- a/main/src/cgeo/geocaching/export/GpxExport.java
+++ b/main/src/cgeo/geocaching/export/GpxExport.java
@@ -98,11 +98,7 @@ public class GpxExport extends AbstractExport {
}
private static String[] getGeocodes(final List<Geocache> caches) {
- final ArrayList<String> allGeocodes = new ArrayList<>(caches.size());
- for (final Geocache geocache : caches) {
- allGeocodes.add(geocache.getGeocode());
- }
- return allGeocodes.toArray(new String[allGeocodes.size()]);
+ return Geocache.getGeocodes(caches).toArray(new String[caches.size()]);
}
protected class ExportTask extends AsyncTaskWithProgress<String, File> {
@@ -121,8 +117,7 @@ public class GpxExport extends AbstractExport {
private File getExportFile() {
final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
- final Date now = new Date();
- return FileUtils.getUniqueNamedFile(Settings.getGpxExportDir() + File.separatorChar + "export_" + fileNameDateFormat.format(now) + ".gpx");
+ return FileUtils.getUniqueNamedFile(new File(Settings.getGpxExportDir(), "export_" + fileNameDateFormat.format(new Date()) + ".gpx"));
}
@Override
@@ -156,7 +151,7 @@ public class GpxExport extends AbstractExport {
if (writer != null) {
try {
writer.close();
- } catch (final IOException e1) {
+ } catch (final IOException ignored) {
// Ignore double error
}
}
diff --git a/main/src/cgeo/geocaching/export/GpxSerializer.java b/main/src/cgeo/geocaching/export/GpxSerializer.java
index b24eb4c..8139c76 100644
--- a/main/src/cgeo/geocaching/export/GpxSerializer.java
+++ b/main/src/cgeo/geocaching/export/GpxSerializer.java
@@ -7,7 +7,7 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.enumerations.CacheAttribute;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.SynchronizedDateFormat;
import cgeo.geocaching.utils.TextUtils;
@@ -55,7 +55,7 @@ public final class GpxSerializer {
}
- public void writeGPX(List<String> allGeocodesIn, Writer writer, final ProgressListener progressListener) throws IOException {
+ public void writeGPX(final List<String> allGeocodesIn, final Writer writer, final ProgressListener progressListener) throws IOException {
// create a copy of the geocode list, as we need to modify it, but it might be immutable
final ArrayList<String> allGeocodes = new ArrayList<>(allGeocodesIn);
@@ -88,7 +88,7 @@ public final class GpxSerializer {
gpx.endDocument();
}
- private void exportBatch(final XmlSerializer gpx, Collection<String> geocodesOfBatch) throws IOException {
+ private void exportBatch(final XmlSerializer gpx, final Collection<String> geocodesOfBatch) throws IOException {
final Set<Geocache> caches = DataStore.loadCaches(geocodesOfBatch, LoadFlags.LOAD_ALL_DB_ONLY);
for (final Geocache cache : caches) {
if (cache == null) {
@@ -174,11 +174,10 @@ public final class GpxSerializer {
}
/**
- * @param boolFlag
* @return XML schema compliant boolean representation of the boolean flag. This must be either true, false, 0 or 1,
* but no other value (also not upper case True/False).
*/
- private static String gpxBoolean(boolean boolFlag) {
+ private static String gpxBoolean(final boolean boolFlag) {
return boolFlag ? "true" : "false";
}
@@ -195,7 +194,7 @@ public final class GpxSerializer {
try {
final int numericPrefix = Integer.parseInt(prefix);
maxPrefix = Math.max(numericPrefix, maxPrefix);
- } catch (final NumberFormatException ex) {
+ } catch (final NumberFormatException ignored) {
// ignore non numeric prefix, as it should be unique in the list of non-own waypoints already
}
}
@@ -220,12 +219,6 @@ public final class GpxSerializer {
/**
* Writes one waypoint entry for cache waypoint.
- *
- * @param cache
- * The
- * @param wp
- * @param prefix
- * @throws IOException
*/
private void writeCacheWaypoint(final Waypoint wp) throws IOException {
final Geopoint coords = wp.getCoords();
@@ -261,7 +254,7 @@ public final class GpxSerializer {
}
private void writeLogs(final Geocache cache) throws IOException {
- List<LogEntry> logs = cache.getLogs();
+ final List<LogEntry> logs = cache.getLogs();
if (logs.isEmpty()) {
return;
}
@@ -297,7 +290,7 @@ public final class GpxSerializer {
}
private void writeTravelBugs(final Geocache cache) throws IOException {
- List<Trackable> inventory = cache.getInventory();
+ final List<Trackable> inventory = cache.getInventory();
if (CollectionUtils.isEmpty(inventory)) {
return;
}
@@ -344,7 +337,7 @@ public final class GpxSerializer {
return getLocationPart(cache, 0);
}
- private static String getLocationPart(final Geocache cache, int partIndex) {
+ private static String getLocationPart(final Geocache cache, final int partIndex) {
final String location = cache.getLocation();
if (StringUtils.contains(location, ", ")) {
final String[] parts = StringUtils.split(location, ',');
@@ -356,7 +349,7 @@ public final class GpxSerializer {
}
public static String getCountry(final Geocache cache) {
- String country = getLocationPart(cache, 1);
+ final String country = getLocationPart(cache, 1);
if (StringUtils.isNotEmpty(country)) {
return country;
}
diff --git a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
index 2a05cbc..3ec9849 100644
--- a/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
+++ b/main/src/cgeo/geocaching/files/AbstractFileListActivity.java
@@ -9,6 +9,7 @@ import cgeo.geocaching.utils.Log;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.app.ProgressDialog;
import android.content.DialogInterface;
@@ -38,7 +39,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
private String searchInfo;
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
if (msg.obj != null && waitDialog != null) {
if (searchInfo == null) {
searchInfo = res.getString(R.string.file_searching_in) + " ";
@@ -52,7 +53,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
private String getDefaultFolders() {
final ArrayList<String> names = new ArrayList<>();
- for (File dir : getExistingBaseFolders()) {
+ for (final File dir : getExistingBaseFolders()) {
names.add(dir.getPath());
}
return StringUtils.join(names, '\n');
@@ -62,7 +63,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
final private Handler loadFilesHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
if (waitDialog != null) {
waitDialog.dismiss();
}
@@ -76,17 +77,17 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
};
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme();
setContentView(R.layout.gpx);
- Bundle extras = getIntent().getExtras();
+ final Bundle extras = getIntent().getExtras();
if (extras != null) {
listId = extras.getInt(Intents.EXTRA_LIST_ID);
}
- if (listId <= StoredList.TEMPORARY_LIST_ID) {
+ if (listId <= StoredList.TEMPORARY_LIST.id) {
listId = StoredList.STANDARD_LIST_ID;
}
@@ -100,7 +101,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
true,
new DialogInterface.OnCancelListener() {
@Override
- public void onCancel(DialogInterface arg0) {
+ public void onCancel(final DialogInterface arg0) {
if (searchingThread != null && searchingThread.isAlive()) {
searchingThread.notifyEnd();
}
@@ -171,7 +172,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
} else {
Log.w("No external media mounted.");
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("AbstractFileListActivity.loadFiles.run", e);
}
@@ -181,7 +182,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
Collections.sort(files, new Comparator<File>() {
@Override
- public int compare(File lhs, File rhs) {
+ public int compare(final File lhs, final File rhs) {
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
});
@@ -189,7 +190,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
loadFilesHandler.sendMessage(Message.obtain(loadFilesHandler));
}
- private void listDirs(List<File> list, List<File> directories, FileListSelector selector, Handler feedbackHandler) {
+ private void listDirs(final List<File> list, final List<File> directories, final FileListSelector selector, final Handler feedbackHandler) {
for (final File dir : directories) {
FileUtils.listDir(list, dir, selector, feedbackHandler);
}
@@ -200,11 +201,10 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
* Check if a filename belongs to the AbstractFileListActivity. This implementation checks for file extensions.
* Subclasses may override this method to filter out specific files.
*
- * @param filename
* @return <code>true</code> if the filename belongs to the list
*/
- protected boolean filenameBelongsToList(final String filename) {
- for (String ext : extensions) {
+ protected boolean filenameBelongsToList(@NonNull final String filename) {
+ for (final String ext : extensions) {
if (StringUtils.endsWithIgnoreCase(filename, ext)) {
return true;
}
@@ -213,7 +213,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
}
protected List<File> getExistingBaseFolders() {
- ArrayList<File> result = new ArrayList<>();
+ final ArrayList<File> result = new ArrayList<>();
for (final File dir : getBaseFolders()) {
if (dir.exists() && dir.isDirectory()) {
result.add(dir);
@@ -245,7 +245,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
boolean shouldEnd = false;
@Override
- public boolean isSelected(File file) {
+ public boolean isSelected(final File file) {
return filenameBelongsToList(file.getName());
}
@@ -254,7 +254,7 @@ public abstract class AbstractFileListActivity<T extends ArrayAdapter<File>> ext
return shouldEnd;
}
- public synchronized void setShouldEnd(boolean shouldEnd) {
+ public synchronized void setShouldEnd(final boolean shouldEnd) {
this.shouldEnd = shouldEnd;
}
}
diff --git a/main/src/cgeo/geocaching/files/FileParser.java b/main/src/cgeo/geocaching/files/FileParser.java
index 973e65f..9c70a0d 100644
--- a/main/src/cgeo/geocaching/files/FileParser.java
+++ b/main/src/cgeo/geocaching/files/FileParser.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.utils.CancellableHandler;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.CharEncoding;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -15,7 +16,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
-import java.util.Date;
import java.util.concurrent.CancellationException;
public abstract class FileParser {
@@ -23,27 +23,24 @@ public abstract class FileParser {
* Parses caches from input stream.
*
* @param stream
+ * the input stream
* @param progressHandler
- * for reporting parsing progress (in bytes read from input stream)
+ * for reporting parsing progress (in bytes read from input stream)
* @return collection of caches
* @throws IOException
- * if the input stream can't be read
+ * if the input stream can't be read
* @throws ParserException
- * if the input stream contains data not matching the file format of the parser
+ * if the input stream contains data not matching the file format of the parser
*/
+ @NonNull
public abstract Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException;
/**
* Convenience method for parsing a file.
- *
- * @param file
- * @param progressHandler
- * @return
- * @throws IOException
- * @throws ParserException
*/
+ @NonNull
public Collection<Geocache> parse(final File file, final CancellableHandler progressHandler) throws IOException, ParserException {
- BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));
+ final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));
try {
return parse(stream, progressHandler);
} finally {
@@ -51,10 +48,11 @@ public abstract class FileParser {
}
}
+ @NonNull
protected static StringBuilder readStream(@NonNull final InputStream is, @Nullable final CancellableHandler progressHandler) throws IOException {
final StringBuilder buffer = new StringBuilder();
- ProgressInputStream progressInputStream = new ProgressInputStream(is);
- final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream, "UTF-8"));
+ final ProgressInputStream progressInputStream = new ProgressInputStream(is);
+ final BufferedReader input = new BufferedReader(new InputStreamReader(progressInputStream, CharEncoding.UTF_8));
try {
String line;
@@ -77,13 +75,13 @@ public abstract class FileParser {
}
}
- protected static void fixCache(Geocache cache) {
+ protected static void fixCache(final Geocache cache) {
if (cache.getInventory() != null) {
cache.setInventoryItems(cache.getInventory().size());
} else {
cache.setInventoryItems(0);
}
- final long time = new Date().getTime();
+ final long time = System.currentTimeMillis();
cache.setUpdated(time);
cache.setDetailedUpdate(time);
}
diff --git a/main/src/cgeo/geocaching/files/FileTypeDetector.java b/main/src/cgeo/geocaching/files/FileTypeDetector.java
index 389b83a..d1a1892 100644
--- a/main/src/cgeo/geocaching/files/FileTypeDetector.java
+++ b/main/src/cgeo/geocaching/files/FileTypeDetector.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.files;
import cgeo.geocaching.utils.Log;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
@@ -10,7 +11,6 @@ import android.content.ContentResolver;
import android.net.Uri;
import java.io.BufferedReader;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -20,7 +20,7 @@ public class FileTypeDetector {
private final ContentResolver contentResolver;
private final Uri uri;
- public FileTypeDetector(Uri uri, ContentResolver contentResolver) {
+ public FileTypeDetector(final Uri uri, final ContentResolver contentResolver) {
this.uri = uri;
this.contentResolver = contentResolver;
}
@@ -34,12 +34,10 @@ public class FileTypeDetector {
if (is == null) {
return FileType.UNKNOWN;
}
- reader = new BufferedReader(new InputStreamReader(is));
+ reader = new BufferedReader(new InputStreamReader(is, CharEncoding.UTF_8));
type = detectHeader(reader);
reader.close();
- } catch (FileNotFoundException e) {
- Log.e("FileTypeDetector", e);
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("FileTypeDetector", e);
} finally {
IOUtils.closeQuietly(reader);
@@ -48,7 +46,7 @@ public class FileTypeDetector {
return type;
}
- private static FileType detectHeader(BufferedReader reader)
+ private static FileType detectHeader(final BufferedReader reader)
throws IOException {
String line = reader.readLine();
if (isZip(line)) {
@@ -68,7 +66,7 @@ public class FileTypeDetector {
return FileType.UNKNOWN;
}
- private static boolean isZip(String line) {
+ private static boolean isZip(final String line) {
return StringUtils.length(line) >= 4
&& StringUtils.startsWith(line, "PK") && line.charAt(2) == 3
&& line.charAt(3) == 4;
diff --git a/main/src/cgeo/geocaching/files/GPX10Parser.java b/main/src/cgeo/geocaching/files/GPX10Parser.java
index 0ca2606..815d577 100644
--- a/main/src/cgeo/geocaching/files/GPX10Parser.java
+++ b/main/src/cgeo/geocaching/files/GPX10Parser.java
@@ -4,12 +4,12 @@ import android.sax.Element;
public class GPX10Parser extends GPXParser {
- public GPX10Parser(int listIdIn) {
+ public GPX10Parser(final int listIdIn) {
super(listIdIn, "http://www.topografix.com/GPX/1/0", "1.0");
}
@Override
- protected Element getCacheParent(Element waypoint) {
+ protected Element getCacheParent(final Element waypoint) {
return waypoint;
}
diff --git a/main/src/cgeo/geocaching/files/GPX11Parser.java b/main/src/cgeo/geocaching/files/GPX11Parser.java
index 52a6ae3..6ac152c 100644
--- a/main/src/cgeo/geocaching/files/GPX11Parser.java
+++ b/main/src/cgeo/geocaching/files/GPX11Parser.java
@@ -4,12 +4,12 @@ import android.sax.Element;
public final class GPX11Parser extends GPXParser {
- public GPX11Parser(int listIdIn) {
+ public GPX11Parser(final int listIdIn) {
super(listIdIn, "http://www.topografix.com/GPX/1/1", "1.1");
}
@Override
- protected Element getCacheParent(Element waypoint) {
+ protected Element getCacheParent(final Element waypoint) {
return waypoint.getChild(namespace, "extensions");
}
diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java
index 52f68e1..5699ebe 100644
--- a/main/src/cgeo/geocaching/files/GPXImporter.java
+++ b/main/src/cgeo/geocaching/files/GPXImporter.java
@@ -95,8 +95,6 @@ public class GPXImporter {
*
* @param uri
* URI of the file to import
- * @param mimeType
- * @param pathName
*/
public void importGPX(final Uri uri, final @Nullable String mimeType, final @Nullable String pathName) {
final ContentResolver contentResolver = fromActivity.getContentResolver();
@@ -113,7 +111,7 @@ public class GPXImporter {
fileType = getFileTypeFromMimeType(mimeType);
}
- ImportThread importer = getImporterFromFileType(uri, contentResolver,
+ final ImportThread importer = getImporterFromFileType(uri, contentResolver,
fileType);
if (importer != null) {
@@ -139,14 +137,15 @@ public class GPXImporter {
final String mimeType) {
if (GPX_MIME_TYPES.contains(mimeType)) {
return FileType.GPX;
- } else if (ZIP_MIME_TYPES.contains(mimeType)) {
+ }
+ if (ZIP_MIME_TYPES.contains(mimeType)) {
return FileType.ZIP;
}
- return FileType.UNKNOWN;
+ return FileType.UNKNOWN;
}
- private ImportThread getImporterFromFileType(Uri uri,
- ContentResolver contentResolver, FileType fileType) {
+ private ImportThread getImporterFromFileType(final Uri uri,
+ final ContentResolver contentResolver, final FileType fileType) {
switch (fileType) {
case ZIP:
return new ImportGpxZipAttachmentThread(uri, contentResolver,
@@ -178,7 +177,7 @@ public class GPXImporter {
final Handler importStepHandler;
final CancellableHandler progressHandler;
- protected ImportThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportThread(final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
this.listId = listId;
this.importStepHandler = importStepHandler;
this.progressHandler = progressHandler;
@@ -210,7 +209,7 @@ public class GPXImporter {
} catch (final ParserException e) {
Log.i("Importing caches failed - data format error", e);
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_FINISHED_WITH_ERROR, R.string.gpx_import_error_parser, 0, e.getLocalizedMessage()));
- } catch (final CancellationException e) {
+ } catch (final CancellationException ignored) {
Log.i("Importing caches canceled");
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_CANCELED));
} catch (final Exception e) {
@@ -244,7 +243,7 @@ public class GPXImporter {
static class ImportLocFileThread extends ImportThread {
private final File file;
- public ImportLocFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportLocFileThread(final File file, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.file = file;
}
@@ -262,7 +261,7 @@ public class GPXImporter {
private final Uri uri;
private final ContentResolver contentResolver;
- public ImportLocAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportLocAttachmentThread(final Uri uri, final ContentResolver contentResolver, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.uri = uri;
this.contentResolver = contentResolver;
@@ -284,7 +283,7 @@ public class GPXImporter {
static abstract class ImportGpxThread extends ImportThread {
- protected ImportGpxThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportGpxThread(final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
}
@@ -293,7 +292,7 @@ public class GPXImporter {
try {
// try to parse cache file as GPX 10
return doImport(new GPX10Parser(listId));
- } catch (final ParserException pe) {
+ } catch (final ParserException ignored) {
// didn't work -> lets try GPX11
return doImport(new GPX11Parser(listId));
}
@@ -305,13 +304,13 @@ public class GPXImporter {
static class ImportGpxFileThread extends ImportGpxThread {
private final File cacheFile;
- public ImportGpxFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportGpxFileThread(final File file, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.cacheFile = file;
}
@Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ protected Collection<Geocache> doImport(final GPXParser parser) throws IOException, ParserException {
Log.i("Import GPX file: " + cacheFile.getAbsolutePath());
importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, (int) cacheFile.length()));
Collection<Geocache> caches = parser.parse(cacheFile, progressHandler);
@@ -333,17 +332,21 @@ public class GPXImporter {
private final Uri uri;
private final ContentResolver contentResolver;
- public ImportGpxAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportGpxAttachmentThread(final Uri uri, final ContentResolver contentResolver, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.uri = uri;
this.contentResolver = contentResolver;
}
@Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ protected Collection<Geocache> doImport(final GPXParser parser) throws IOException, ParserException {
Log.i("Import GPX from uri: " + uri);
- importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, -1));
final InputStream is = contentResolver.openInputStream(uri);
+ int streamSize = is.available();
+ if (streamSize == 0) {
+ streamSize = -1;
+ }
+ importStepHandler.sendMessage(importStepHandler.obtainMessage(IMPORT_STEP_READ_FILE, R.string.gpx_import_loading_caches, streamSize));
try {
return parser.parse(is, progressHandler);
} finally {
@@ -354,12 +357,12 @@ public class GPXImporter {
static abstract class ImportGpxZipThread extends ImportGpxThread {
- protected ImportGpxZipThread(int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ protected ImportGpxZipThread(final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
}
@Override
- protected Collection<Geocache> doImport(GPXParser parser) throws IOException, ParserException {
+ protected Collection<Geocache> doImport(final GPXParser parser) throws IOException, ParserException {
Collection<Geocache> caches = Collections.emptySet();
// can't assume that GPX file comes before waypoint file in zip -> so we need two passes
// 1. parse GPX files
@@ -403,7 +406,7 @@ public class GPXImporter {
static class ImportGpxZipFileThread extends ImportGpxZipThread {
private final File cacheFile;
- public ImportGpxZipFileThread(final File file, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportGpxZipFileThread(final File file, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.cacheFile = file;
Log.i("Import zipped GPX: " + file);
@@ -419,7 +422,7 @@ public class GPXImporter {
private final Uri uri;
private final ContentResolver contentResolver;
- public ImportGpxZipAttachmentThread(Uri uri, ContentResolver contentResolver, int listId, Handler importStepHandler, CancellableHandler progressHandler) {
+ public ImportGpxZipAttachmentThread(final Uri uri, final ContentResolver contentResolver, final int listId, final Handler importStepHandler, final CancellableHandler progressHandler) {
super(listId, importStepHandler, progressHandler);
this.uri = uri;
this.contentResolver = contentResolver;
@@ -434,14 +437,14 @@ public class GPXImporter {
final private CancellableHandler progressHandler = new CancellableHandler() {
@Override
- public void handleRegularMessage(Message msg) {
+ public void handleRegularMessage(final Message msg) {
progress.setProgress(msg.arg1);
}
};
final private Handler importStepHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
+ public void handleMessage(final Message msg) {
switch (msg.what) {
case IMPORT_STEP_START:
final Message cancelMessage = importStepHandler.obtainMessage(IMPORT_STEP_CANCEL);
diff --git a/main/src/cgeo/geocaching/files/GPXParser.java b/main/src/cgeo/geocaching/files/GPXParser.java
index 89ee887..aed82e6 100644
--- a/main/src/cgeo/geocaching/files/GPXParser.java
+++ b/main/src/cgeo/geocaching/files/GPXParser.java
@@ -8,6 +8,8 @@ import cgeo.geocaching.R;
import cgeo.geocaching.Trackable;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.connector.ConnectorFactory;
+import cgeo.geocaching.connector.IConnector;
+import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
@@ -16,8 +18,8 @@ import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag;
import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MatcherWrapper;
@@ -120,12 +122,12 @@ public abstract class GPXParser extends FileParser {
private final class UserDataListener implements EndTextElementListener {
private final int index;
- public UserDataListener(int index) {
+ public UserDataListener(final int index) {
this.index = index;
}
@Override
- public void end(String user) {
+ public void end(final String user) {
userData[index] = validate(user);
}
}
@@ -223,10 +225,10 @@ public abstract class GPXParser extends FileParser {
return null; // id not found
}
// get text for string
- String stringName;
+ final String stringName;
try {
stringName = CgeoApplication.getInstance().getResources().getResourceName(stringId);
- } catch (final NullPointerException e) {
+ } catch (final NullPointerException ignored) {
return null;
}
if (stringName == null) {
@@ -250,13 +252,13 @@ public abstract class GPXParser extends FileParser {
}
}
- protected GPXParser(int listIdIn, String namespaceIn, String versionIn) {
+ protected GPXParser(final int listIdIn, final String namespaceIn, final String versionIn) {
listId = listIdIn;
namespace = namespaceIn;
version = versionIn;
}
- static Date parseDate(String inputUntrimmed) throws ParseException {
+ static Date parseDate(final String inputUntrimmed) throws ParseException {
String input = inputUntrimmed.trim();
// remove milliseconds to reduce number of needed patterns
final MatcherWrapper matcher = new MatcherWrapper(PATTERN_MILLISECONDS, input);
@@ -272,6 +274,7 @@ public abstract class GPXParser extends FileParser {
}
@Override
+ @NonNull
public Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException {
resetCache();
final RootElement root = new RootElement(namespace, "gpx");
@@ -280,7 +283,7 @@ public abstract class GPXParser extends FileParser {
root.getChild(namespace, "url").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
scriptUrl = body;
}
});
@@ -289,7 +292,7 @@ public abstract class GPXParser extends FileParser {
waypoint.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attrs) {
+ public void start(final Attributes attrs) {
try {
if (attrs.getIndex("lat") > -1 && attrs.getIndex("lon") > -1) {
final String latitude = attrs.getValue("lat");
@@ -301,7 +304,7 @@ public abstract class GPXParser extends FileParser {
}
}
} catch (final NumberFormatException e) {
- Log.w("Failed to parse waypoint's latitude and/or longitude.");
+ Log.w("Failed to parse waypoint's latitude and/or longitude", e);
}
}
});
@@ -341,7 +344,7 @@ public abstract class GPXParser extends FileParser {
// finally store the cache in the database
result.add(geocode);
DataStore.saveCache(cache, EnumSet.of(SaveFlag.DB));
- DataStore.saveLogsWithoutTransaction(cache.getGeocode(), logs);
+ DataStore.saveLogs(cache.getGeocode(), logs);
// avoid the cachecache using lots of memory for caches which the user did not actually look at
DataStore.removeCache(geocode, EnumSet.of(RemoveFlag.CACHE));
@@ -399,7 +402,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "time").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
try {
cache.setHidden(parseDate(body));
} catch (final Exception e) {
@@ -412,7 +415,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "name").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
name = body;
String content = body.trim();
@@ -431,7 +434,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "desc").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
desc = body;
cache.setShortDescription(validate(body));
@@ -442,7 +445,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "cmt").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
cmt = body;
cache.setDescription(validate(body));
@@ -453,8 +456,8 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "type").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
- final String[] content = body.split("\\|");
+ public void end(final String body) {
+ final String[] content = StringUtils.split(body, '|');
if (content.length > 0) {
type = content[0].toLowerCase(Locale.US).trim();
}
@@ -477,7 +480,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "url").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String url) {
+ public void end(final String url) {
final MatcherWrapper matcher = new MatcherWrapper(PATTERN_GUID, url);
if (matcher.matches()) {
final String guid = matcher.group(1);
@@ -497,7 +500,7 @@ public abstract class GPXParser extends FileParser {
waypoint.getChild(namespace, "urlname").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String urlName) {
+ public void end(final String urlName) {
if (cache.getName().equals(cache.getGeocode()) && StringUtils.startsWith(cache.getGeocode(), "WM")) {
cache.setName(StringUtils.trim(urlName));
}
@@ -520,7 +523,7 @@ public abstract class GPXParser extends FileParser {
gcCache.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attrs) {
+ public void start(final Attributes attrs) {
try {
if (attrs.getIndex("id") > -1) {
cache.setCacheId(attrs.getValue("id"));
@@ -532,7 +535,7 @@ public abstract class GPXParser extends FileParser {
cache.setDisabled(!attrs.getValue("available").equalsIgnoreCase("true"));
}
} catch (final RuntimeException e) {
- Log.w("Failed to parse cache attributes.");
+ Log.w("Failed to parse cache attributes", e);
}
}
});
@@ -541,7 +544,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String cacheName) {
+ public void end(final String cacheName) {
cache.setName(validate(cacheName));
}
});
@@ -550,7 +553,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "owner").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String ownerUserId) {
+ public void end(final String ownerUserId) {
cache.setOwnerUserId(validate(ownerUserId));
}
});
@@ -559,7 +562,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "placed_by").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String ownerDisplayName) {
+ public void end(final String ownerDisplayName) {
cache.setOwnerDisplayName(validate(ownerDisplayName));
}
});
@@ -568,8 +571,13 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
- cache.setType(CacheType.getByPattern(validate(body)));
+ public void end(final String bodyIn) {
+ String body = validate(bodyIn);
+ // lab caches wrongly contain a prefix in the type
+ if (body.startsWith("Geocache|")) {
+ body = StringUtils.substringAfter(body, "Geocache|").trim();
+ }
+ cache.setType(CacheType.getByPattern(body));
}
});
@@ -577,7 +585,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "container").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
cache.setSize(CacheSize.getById(validate(body)));
}
});
@@ -597,7 +605,7 @@ public abstract class GPXParser extends FileParser {
gcAttribute.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attrs) {
+ public void start(final Attributes attrs) {
try {
if (attrs.getIndex("id") > -1 && attrs.getIndex("inc") > -1) {
final int attributeId = Integer.parseInt(attrs.getValue("id"));
@@ -607,7 +615,7 @@ public abstract class GPXParser extends FileParser {
cache.getAttributes().add(internalId);
}
}
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// nothing
}
}
@@ -617,7 +625,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "difficulty").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
try {
cache.setDifficulty(Float.parseFloat(body));
} catch (final NumberFormatException e) {
@@ -630,7 +638,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "terrain").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
try {
cache.setTerrain(Float.parseFloat(body));
} catch (final NumberFormatException e) {
@@ -643,7 +651,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "country").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String country) {
+ public void end(final String country) {
if (StringUtils.isBlank(cache.getLocation())) {
cache.setLocation(validate(country));
} else {
@@ -656,7 +664,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "state").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String state) {
+ public void end(final String state) {
final String trimmedState = state.trim();
if (StringUtils.isNotEmpty(trimmedState)) { // state can be completely empty
if (StringUtils.isBlank(cache.getLocation())) {
@@ -672,7 +680,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "encoded_hints").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String encoded) {
+ public void end(final String encoded) {
cache.setHint(validate(encoded));
}
});
@@ -680,7 +688,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "short_description").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String shortDesc) {
+ public void end(final String shortDesc) {
cache.setShortDescription(validate(shortDesc));
}
});
@@ -688,7 +696,7 @@ public abstract class GPXParser extends FileParser {
gcCache.getChild(nsGC, "long_description").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String desc) {
+ public void end(final String desc) {
cache.setDescription(validate(desc));
}
});
@@ -703,14 +711,14 @@ public abstract class GPXParser extends FileParser {
gcTB.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attrs) {
+ public void start(final Attributes attrs) {
trackable = new Trackable();
try {
if (attrs.getIndex("ref") > -1) {
trackable.setGeocode(attrs.getValue("ref"));
}
- } catch (final RuntimeException e) {
+ } catch (final RuntimeException ignored) {
// nothing
}
}
@@ -733,7 +741,7 @@ public abstract class GPXParser extends FileParser {
gcTB.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String tbName) {
+ public void end(final String tbName) {
trackable.setName(validate(tbName));
}
});
@@ -747,14 +755,14 @@ public abstract class GPXParser extends FileParser {
gcLog.setStartElementListener(new StartElementListener() {
@Override
- public void start(Attributes attrs) {
+ public void start(final Attributes attrs) {
log = new LogEntry("", 0, LogType.UNKNOWN, "");
try {
if (attrs.getIndex("id") > -1) {
log.id = Integer.parseInt(attrs.getValue("id"));
}
- } catch (final NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// nothing
}
}
@@ -765,6 +773,13 @@ public abstract class GPXParser extends FileParser {
@Override
public void end() {
if (log.type != LogType.UNKNOWN) {
+ if (log.type.isFoundLog() && StringUtils.isNotBlank(log.author)) {
+ final IConnector connector = ConnectorFactory.getConnector(cache);
+ if (connector instanceof ILogin && StringUtils.equals(log.author, ((ILogin) connector).getUserName())) {
+ cache.setFound(true);
+ cache.setVisitedDate(log.date);
+ }
+ }
logs.add(log);
}
}
@@ -774,7 +789,7 @@ public abstract class GPXParser extends FileParser {
gcLog.getChild(nsGC, "date").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
try {
log.date = parseDate(body).getTime();
} catch (final Exception e) {
@@ -787,7 +802,7 @@ public abstract class GPXParser extends FileParser {
gcLog.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
final String logType = validate(body);
log.type = LogType.getByType(logType);
}
@@ -797,7 +812,7 @@ public abstract class GPXParser extends FileParser {
gcLog.getChild(nsGC, "finder").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String finderName) {
+ public void end(final String finderName) {
log.author = validate(finderName);
}
});
@@ -806,7 +821,7 @@ public abstract class GPXParser extends FileParser {
gcLog.getChild(nsGC, "text").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String logText) {
+ public void end(final String logText) {
log.log = validate(logText);
}
});
@@ -814,7 +829,7 @@ public abstract class GPXParser extends FileParser {
try {
progressStream = new ProgressInputStream(stream);
- BufferedReader reader = new BufferedReader(new InputStreamReader(progressStream, CharEncoding.UTF_8));
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(progressStream, CharEncoding.UTF_8));
Xml.parse(new InvalidXMLCharacterFilterReader(reader), root.getContentHandler());
return DataStore.loadCaches(result, EnumSet.of(LoadFlag.DB_MINIMAL));
} catch (final SAXException e) {
@@ -825,7 +840,6 @@ public abstract class GPXParser extends FileParser {
/**
* Add listeners for GSAK extensions
*
- * @param cacheParent
*/
private void registerGsakExtensions(final Element cacheParent) {
for (final String gsakNamespace : GSAK_NS) {
@@ -833,7 +847,7 @@ public abstract class GPXParser extends FileParser {
gsak.getChild(gsakNamespace, "Watch").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String watchList) {
+ public void end(final String watchList) {
cache.setOnWatchlist(Boolean.valueOf(watchList.trim()));
}
});
@@ -847,7 +861,7 @@ public abstract class GPXParser extends FileParser {
gsak.getChild(gsakNamespace, "Parent").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String body) {
+ public void end(final String body) {
parentCacheCode = body;
}
});
@@ -855,7 +869,7 @@ public abstract class GPXParser extends FileParser {
gsak.getChild(gsakNamespace, "FavPoints").setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String favoritePoints) {
+ public void end(final String favoritePoints) {
try {
cache.setFavoritePoints(Integer.parseInt(favoritePoints));
}
@@ -886,7 +900,6 @@ public abstract class GPXParser extends FileParser {
/**
* Add listeners for c:geo extensions
*
- * @param cacheParent
*/
private void registerCgeoExtensions(final Element cacheParent) {
final Element cgeoVisited = cacheParent.getChild(CGEO_NS, "visited");
@@ -894,7 +907,7 @@ public abstract class GPXParser extends FileParser {
cgeoVisited.setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String visited) {
+ public void end(final String visited) {
wptVisited = Boolean.valueOf(visited.trim());
}
});
@@ -904,7 +917,7 @@ public abstract class GPXParser extends FileParser {
cgeoUserDefined.setEndTextElementListener(new EndTextElementListener() {
@Override
- public void end(String userDefined) {
+ public void end(final String userDefined) {
wptUserDefined = Boolean.valueOf(userDefined.trim());
}
});
@@ -917,7 +930,7 @@ public abstract class GPXParser extends FileParser {
* @param cache
* currently imported cache
*/
- protected void afterParsing(Geocache cache) {
+ protected void afterParsing(final Geocache cache) {
// can be overridden by sub classes
}
@@ -925,12 +938,10 @@ public abstract class GPXParser extends FileParser {
* GPX 1.0 and 1.1 use different XML elements to put the cache into, therefore needs to be overwritten in the
* version specific subclasses
*
- * @param waypoint
- * @return
*/
protected abstract Element getCacheParent(Element waypoint);
- protected static String validate(String input) {
+ protected static String validate(final String input) {
if ("nil".equalsIgnoreCase(input)) {
return "";
}
diff --git a/main/src/cgeo/geocaching/files/IFileSelectionView.java b/main/src/cgeo/geocaching/files/IFileSelectionView.java
index 5bbc1b2..0407ee4 100644
--- a/main/src/cgeo/geocaching/files/IFileSelectionView.java
+++ b/main/src/cgeo/geocaching/files/IFileSelectionView.java
@@ -8,7 +8,7 @@ public interface IFileSelectionView {
String getCurrentFile();
- void setCurrentFile(String string);
+ void setCurrentFile(final String name);
void close();
diff --git a/main/src/cgeo/geocaching/files/InvalidXMLCharacterFilterReader.java b/main/src/cgeo/geocaching/files/InvalidXMLCharacterFilterReader.java
index a7a3e1b..eea14c3 100644
--- a/main/src/cgeo/geocaching/files/InvalidXMLCharacterFilterReader.java
+++ b/main/src/cgeo/geocaching/files/InvalidXMLCharacterFilterReader.java
@@ -1,98 +1,89 @@
-package cgeo.geocaching.files;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.FilterReader;
-import java.io.IOException;
-import java.io.Reader;
-
-/**
- * Filter reader which can filter out invalid XML characters and character references.
- *
- */
-public class InvalidXMLCharacterFilterReader extends FilterReader
-{
-
- public InvalidXMLCharacterFilterReader(Reader in) {
- super(in);
- }
-
- /**
- * Every overload of {@link Reader#read()} method delegates to this one so
- * it is enough to override only this one. <br />
- * To skip invalid characters this method shifts only valid chars to left
- * and returns decreased value of the original read method. So after last
- * valid character there will be some unused chars in the buffer.
- *
- * @return Number of read valid characters or <code>-1</code> if end of the
- * underling reader was reached.
- */
- @Override
- public int read(char[] cbuf, int off, int len) throws IOException {
- int read = super.read(cbuf, off, len);
- // check for end
- if (read == -1) {
- return -1;
- }
- // target position
- int pos = off - 1;
-
- int entityStart = -1;
- for (int readPos = off; readPos < off + read; readPos++) {
- boolean useChar = true;
- switch (cbuf[readPos]) {
- case '&':
- pos++;
- entityStart = readPos;
- break;
- case ';':
- pos++;
- if (entityStart >= 0) {
- int entityLength = readPos - entityStart + 1;
- if (entityLength <= 5) {
- String entity = new String(cbuf, entityStart, entityLength);
- if (StringUtils.startsWith(entity, "&#")) {
- String numberString = StringUtils.substringBetween(entity, "&#", ";");
- final int value;
- if (StringUtils.startsWith(numberString, "x")) {
- value = Integer.parseInt(numberString.substring(1), 16);
- }
- else {
- value = Integer.parseInt(numberString);
- }
- if (!isValidXMLChar((char) value)) {
- pos -= entityLength;
- useChar = false;
- }
- }
- }
- }
- break;
- default:
- if (isValidXMLChar(cbuf[readPos])) {
- pos++;
- } else {
- continue;
- }
- }
- // copy, and skip unwanted characters
- if (pos < readPos && useChar) {
- cbuf[pos] = cbuf[readPos];
- }
- }
- return pos - off + 1;
- }
-
- private static boolean isValidXMLChar(char c) {
- if ((c == 0x9) ||
- (c == 0xA) ||
- (c == 0xD) ||
- ((c >= 0x20) && (c <= 0xD7FF)) ||
- ((c >= 0xE000) && (c <= 0xFFFD)) ||
- ((c >= 0x10000) && (c <= 0x10FFFF)))
- {
- return true;
- }
- return false;
- }
+package cgeo.geocaching.files;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Filter reader which can filter out invalid XML characters and character references.
+ *
+ */
+public class InvalidXMLCharacterFilterReader extends FilterReader
+{
+
+ public InvalidXMLCharacterFilterReader(final Reader in) {
+ super(in);
+ }
+
+ /**
+ * Every overload of {@link Reader#read()} method delegates to this one so
+ * it is enough to override only this one. <br />
+ * To skip invalid characters this method shifts only valid chars to left
+ * and returns decreased value of the original read method. So after last
+ * valid character there will be some unused chars in the buffer.
+ *
+ * @return Number of read valid characters or <code>-1</code> if end of the
+ * underling reader was reached.
+ */
+ @Override
+ public int read(final char[] cbuf, final int off, final int len) throws IOException {
+ final int read = super.read(cbuf, off, len);
+ // check for end
+ if (read == -1) {
+ return -1;
+ }
+ // target position
+ int pos = off - 1;
+
+ int entityStart = -1;
+ for (int readPos = off; readPos < off + read; readPos++) {
+ boolean useChar = true;
+ switch (cbuf[readPos]) {
+ case '&':
+ pos++;
+ entityStart = readPos;
+ break;
+ case ';':
+ pos++;
+ if (entityStart >= 0) {
+ final int entityLength = readPos - entityStart + 1;
+ if (entityLength <= 5) {
+ final String entity = new String(cbuf, entityStart, entityLength);
+ if (StringUtils.startsWith(entity, "&#")) {
+ final String numberString = StringUtils.substringBetween(entity, "&#", ";");
+ final int value;
+ if (StringUtils.startsWith(numberString, "x")) {
+ value = Integer.parseInt(numberString.substring(1), 16);
+ }
+ else {
+ value = Integer.parseInt(numberString);
+ }
+ if (!isValidXMLChar((char) value)) {
+ pos -= entityLength;
+ useChar = false;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ if (isValidXMLChar(cbuf[readPos])) {
+ pos++;
+ } else {
+ continue;
+ }
+ }
+ // copy, and skip unwanted characters
+ if (pos < readPos && useChar) {
+ cbuf[pos] = cbuf[readPos];
+ }
+ }
+ return pos - off + 1;
+ }
+
+ private static boolean isValidXMLChar(final char c) {
+ return c == 0x9 || c == 0xA || c == 0xD || (c >= 0x20 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD);
+ }
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/files/LocParser.java b/main/src/cgeo/geocaching/files/LocParser.java
index 2871d77..a3d9b8a 100644
--- a/main/src/cgeo/geocaching/files/LocParser.java
+++ b/main/src/cgeo/geocaching/files/LocParser.java
@@ -1,43 +1,40 @@
package cgeo.geocaching.files;
-import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MatcherWrapper;
+import org.apache.commons.io.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.regex.Pattern;
public final class LocParser extends FileParser {
+ @NonNull
private static final String NAME_OWNER_SEPARATOR = " by ";
- private static final Pattern patternGeocode = Pattern
- .compile("name id=\"([^\"]+)\"");
- private static final Pattern patternLat = Pattern
- .compile("lat=\"([^\"]+)\"");
- private static final Pattern patternLon = Pattern
- .compile("lon=\"([^\"]+)\"");
- private static final Pattern patternName = Pattern.compile("CDATA\\[([^\\]]+)\\]");
+ @NonNull
private static final CacheSize[] SIZES = {
CacheSize.NOT_CHOSEN, // 1
CacheSize.MICRO, // 2
@@ -49,22 +46,95 @@ public final class LocParser extends FileParser {
CacheSize.SMALL, // 8
};
- private int listId;
+ // Used so that the initial value of the geocache is not null. Never filled.
+ @NonNull
+ private static final Geocache DUMMY_GEOCACHE = new Geocache();
- public static void parseLoc(final SearchResult searchResult, final String fileContent) {
- final Map<String, Geocache> cidCoords = parseCoordinates(fileContent);
+ private final int listId;
+
+ public static void parseLoc(final SearchResult searchResult, final String fileContent, final Set<Geocache> caches) {
+ final Map<String, Geocache> cidCoords = parseLoc(fileContent);
// save found cache coordinates
final HashSet<String> contained = new HashSet<>();
- for (String geocode : searchResult.getGeocodes()) {
+ for (final String geocode : searchResult.getGeocodes()) {
if (cidCoords.containsKey(geocode)) {
contained.add(geocode);
}
}
- Set<Geocache> caches = DataStore.loadCaches(contained, LoadFlags.LOAD_CACHE_OR_DB);
- for (Geocache cache : caches) {
- Geocache coord = cidCoords.get(cache.getGeocode());
- copyCoordToCache(coord, cache);
+ for (final Geocache cache : caches) {
+ if (!cache.isReliableLatLon()) {
+ final Geocache coord = cidCoords.get(cache.getGeocode());
+ // Archived caches will not have any coordinates
+ if (coord != null) {
+ copyCoordToCache(coord, cache);
+ }
+ }
+ }
+ }
+
+ @NonNull
+ private static Map<String, Geocache> parseLoc(final String content) {
+ return parseLoc(new ByteArrayInputStream(content.getBytes(Charsets.UTF_8)));
+ }
+
+ @NonNull
+ private static Map<String, Geocache> parseLoc(final InputStream content) {
+ try {
+ final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ final XmlPullParser xpp = factory.newPullParser();
+ xpp.setInput(content, Charsets.UTF_8.name());
+ final Map<String, Geocache> caches = new HashMap<>();
+ int eventType = xpp.getEventType();
+ Geocache currentCache = DUMMY_GEOCACHE;
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ switch (xpp.getName()) {
+ case "waypoint":
+ currentCache = new Geocache();
+ currentCache.setType(CacheType.UNKNOWN); // Type not present in .loc file
+ break;
+ case "name":
+ currentCache.setGeocode(xpp.getAttributeValue(null, "id"));
+ if (xpp.next() == XmlPullParser.TEXT) {
+ final String nameOwner = xpp.getText();
+ currentCache.setName(StringUtils.trim(StringUtils.substringBeforeLast(nameOwner, NAME_OWNER_SEPARATOR)));
+ currentCache.setOwnerUserId(StringUtils.trim(StringUtils.substringAfterLast(nameOwner, NAME_OWNER_SEPARATOR)));
+ }
+ break;
+ case "coord":
+ currentCache.setCoords(new Geopoint(Double.valueOf(xpp.getAttributeValue(null, "lat")),
+ Double.valueOf(xpp.getAttributeValue(null, "lon"))));
+ currentCache.setReliableLatLon(true);
+ break;
+ case "container":
+ if (xpp.next() == XmlPullParser.TEXT) {
+ currentCache.setSize(SIZES[Integer.parseInt(xpp.getText()) - 1]);
+ }
+ break;
+ case "difficulty":
+ if (xpp.next() == XmlPullParser.TEXT) {
+ currentCache.setDifficulty(Float.valueOf(xpp.getText()));
+ }
+ break;
+ case "terrain":
+ if (xpp.next() == XmlPullParser.TEXT) {
+ currentCache.setTerrain(Float.valueOf(xpp.getText()));
+ }
+ break;
+ default:
+ // Ignore
+ }
+ } else if (eventType == XmlPullParser.END_TAG && xpp.getName().equals("waypoint") && StringUtils.isNotBlank(currentCache.getGeocode())) {
+ caches.put(currentCache.getGeocode(), currentCache);
+ }
+ eventType = xpp.next();
+ }
+ Log.d("Coordinates found in .loc content: " + caches.size());
+ return caches;
+ } catch (XmlPullParserException | IOException e) {
+ Log.e("unable to parse .loc content", e);
+ return Collections.emptyMap();
}
}
@@ -81,56 +151,33 @@ public final class LocParser extends FileParser {
cache.setOwnerUserId(coord.getOwnerUserId());
}
- static Map<String, Geocache> parseCoordinates(final String fileContent) {
- final Map<String, Geocache> coords = new HashMap<>();
- if (StringUtils.isBlank(fileContent)) {
- return coords;
- }
- // >> premium only
-
- final String[] points = fileContent.split("<waypoint>");
-
- // parse coordinates
- for (String pointString : points) {
- final Geocache pointCoord = parseCache(pointString);
- if (StringUtils.isNotBlank(pointCoord.getGeocode())) {
- coords.put(pointCoord.getGeocode(), pointCoord);
- }
- }
-
- Log.i("Coordinates found in .loc file: " + coords.size());
- return coords;
- }
-
+ @NonNull
public static Geopoint parsePoint(final String latitude, final String longitude) {
// the loc file contains the coordinates as plain floating point values, therefore avoid using the GeopointParser
try {
return new Geopoint(Double.valueOf(latitude), Double.valueOf(longitude));
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException e) {
Log.e("LOC format has changed", e);
}
// fall back to parser, just in case the format changes
return new Geopoint(latitude, longitude);
}
- public LocParser(int listId) {
+ public LocParser(final int listId) {
this.listId = listId;
}
@Override
+ @NonNull
public Collection<Geocache> parse(@NonNull final InputStream stream, @Nullable final CancellableHandler progressHandler) throws IOException, ParserException {
- final String streamContent = readStream(stream, null).toString();
- final int maxSize = streamContent.length();
- final Map<String, Geocache> coords = parseCoordinates(streamContent);
+ final int maxSize = stream.available();
+ final Map<String, Geocache> coords = parseLoc(stream);
final List<Geocache> caches = new ArrayList<>();
- for (Entry<String, Geocache> entry : coords.entrySet()) {
- Geocache coord = entry.getValue();
- if (StringUtils.isBlank(coord.getGeocode()) || StringUtils.isBlank(coord.getName())) {
+ for (final Entry<String, Geocache> entry : coords.entrySet()) {
+ final Geocache cache = entry.getValue();
+ if (StringUtils.isBlank(cache.getGeocode()) || StringUtils.isBlank(cache.getName())) {
continue;
}
- Geocache cache = new Geocache();
- cache.setReliableLatLon(true);
- copyCoordToCache(coord, cache);
caches.add(cache);
fixCache(cache);
@@ -146,53 +193,4 @@ public final class LocParser extends FileParser {
return caches;
}
- public static Geocache parseCache(final String pointString) {
- final Geocache cache = new Geocache();
- final MatcherWrapper matcherGeocode = new MatcherWrapper(patternGeocode, pointString);
- if (matcherGeocode.find()) {
- cache.setGeocode(matcherGeocode.group(1).trim());
- }
-
- final MatcherWrapper matcherName = new MatcherWrapper(patternName, pointString);
- if (matcherName.find()) {
- final String name = matcherName.group(1).trim();
- String ownerName = StringUtils.trim(StringUtils.substringAfterLast(name, NAME_OWNER_SEPARATOR));
- if (StringUtils.isEmpty(cache.getOwnerUserId()) && StringUtils.isNotEmpty(ownerName)) {
- cache.setOwnerUserId(ownerName);
- }
- cache.setName(StringUtils.substringBeforeLast(name, NAME_OWNER_SEPARATOR).trim());
- } else {
- cache.setName(cache.getGeocode());
- }
-
- final MatcherWrapper matcherLat = new MatcherWrapper(patternLat, pointString);
- final MatcherWrapper matcherLon = new MatcherWrapper(patternLon, pointString);
- if (matcherLat.find() && matcherLon.find()) {
- cache.setCoords(parsePoint(matcherLat.group(1).trim(), matcherLon.group(1).trim()));
- }
-
- final String difficulty = StringUtils.substringBetween(pointString, "<difficulty>", "</difficulty>");
- final String terrain = StringUtils.substringBetween(pointString, "<terrain>", "</terrain>");
- final String container = StringUtils.substringBetween(pointString, "<container>", "</container");
- try {
- if (StringUtils.isNotBlank(difficulty)) {
- cache.setDifficulty(Float.parseFloat(difficulty.trim()));
- }
-
- if (StringUtils.isNotBlank(terrain)) {
- cache.setTerrain(Float.parseFloat(terrain.trim()));
- }
-
- if (StringUtils.isNotBlank(container)) {
- final int size = Integer.parseInt(container.trim());
- if (size >= 1 && size <= 8) {
- cache.setSize(SIZES[size - 1]);
- }
- }
- } catch (NumberFormatException e) {
- Log.e("LocParser.parseCache", e);
- }
-
- return cache;
- }
}
diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java
index 63a1844..cfeac9a 100644
--- a/main/src/cgeo/geocaching/files/LocalStorage.java
+++ b/main/src/cgeo/geocaching/files/LocalStorage.java
@@ -7,7 +7,9 @@ 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.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -43,7 +45,7 @@ public final class LocalStorage {
public static final String HEADER_ETAG = "etag";
/** Name of the local private directory used to hold cached information */
- public final static String cache = ".cgeo";
+ public final static String CACHE_DIRNAME = ".cgeo";
private static File internalStorageBase;
@@ -69,10 +71,10 @@ public final class LocalStorage {
return getStorageSpecific(true);
}
- private static File getStorageSpecific(boolean secondary) {
+ private static File getStorageSpecific(final boolean secondary) {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ^ secondary ?
getExternalStorageBase() :
- new File(getInternalStorageBase(), LocalStorage.cache);
+ new File(getInternalStorageBase(), LocalStorage.CACHE_DIRNAME);
}
public static File getExternalDbDirectory() {
@@ -84,7 +86,7 @@ public final class LocalStorage {
}
private static File getExternalStorageBase() {
- return new File(Environment.getExternalStorageDirectory(), LocalStorage.cache);
+ return new File(Environment.getExternalStorageDirectory(), LocalStorage.CACHE_DIRNAME);
}
private static File getInternalStorageBase() {
@@ -103,7 +105,7 @@ public final class LocalStorage {
* @return the file extension, including the leading dot, or the empty string if none could be determined
*/
static String getExtension(final String url) {
- String urlExt;
+ final String urlExt;
if (url.startsWith("data:")) {
// "data:image/png;base64,i53…" -> ".png"
urlExt = StringUtils.substringAfter(StringUtils.substringBefore(url, ";"), "/");
@@ -122,7 +124,7 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- public static File getStorageDir(@Nullable final String geocode) {
+ public static File getStorageDir(@NonNull final String geocode) {
return storageDir(getStorage(), geocode);
}
@@ -134,12 +136,12 @@ public final class LocalStorage {
* the geocode
* @return the cache directory
*/
- private static File getStorageSecDir(@Nullable final String geocode) {
+ private static File getStorageSecDir(@NonNull final String geocode) {
return storageDir(getStorageSec(), geocode);
}
- private static File storageDir(final File base, @Nullable final String geocode) {
- return new File(base, StringUtils.defaultIfEmpty(geocode, "_others"));
+ private static File storageDir(final File base, @NonNull final String geocode) {
+ return new File(base, geocode);
}
/**
@@ -155,7 +157,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(@Nullable final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
+ public static File getStorageFile(@NonNull final String geocode, final String fileNameOrUrl, final boolean isUrl, final boolean createDirs) {
return buildFile(getStorageDir(geocode), fileNameOrUrl, isUrl, createDirs);
}
@@ -202,7 +204,7 @@ public final class LocalStorage {
saveHeader(HEADER_ETAG, saved ? response : null, targetFile);
saveHeader(HEADER_LAST_MODIFIED, saved ? response : null, targetFile);
return saved;
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("LocalStorage.saveEntityToFile", e);
}
@@ -242,16 +244,16 @@ public final class LocalStorage {
public static String getSavedHeader(final File baseFile, final String name) {
try {
final File file = filenameForHeader(baseFile, name);
- final Reader f = new InputStreamReader(new FileInputStream(file), "UTF-8");
+ final Reader reader = new InputStreamReader(new FileInputStream(file), CharEncoding.UTF_8);
try {
// No header will be more than 256 bytes
final char[] value = new char[256];
- final int count = f.read(value);
+ final int count = reader.read(value);
return new String(value, 0, count);
} finally {
- f.close();
+ reader.close();
}
- } catch (final FileNotFoundException e) {
+ } catch (final FileNotFoundException ignored) {
// Do nothing, the file does not exist
} catch (final Exception e) {
Log.w("could not read saved header " + name + " for " + baseFile, e);
@@ -291,7 +293,7 @@ public final class LocalStorage {
} finally {
IOUtils.closeQuietly(inputStream);
}
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("LocalStorage.saveToFile", e);
FileUtils.deleteIgnoringFailure(targetFile);
}
@@ -321,10 +323,10 @@ public final class LocalStorage {
// close here already to catch any issue with closing
input.close();
output.close();
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException e) {
Log.e("LocalStorage.copy: could not copy file", e);
return false;
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("LocalStorage.copy: could not copy file", e);
return false;
} finally {
@@ -345,7 +347,7 @@ public final class LocalStorage {
}
// Flushing is only necessary if the stream is not immediately closed afterwards.
// We rely on all callers to do that correctly outside of this method
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("LocalStorage.copy: error when copying data", e);
return false;
}
@@ -362,24 +364,6 @@ public final class LocalStorage {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
- public static boolean deleteDirectory(@NonNull final File dir) {
- final File[] files = dir.listFiles();
-
- // Although we are called on an existing directory, it might have been removed concurrently
- // in the meantime, for example by the user or by another cleanup task.
- if (files != null) {
- for (final File file : files) {
- if (file.isDirectory()) {
- deleteDirectory(file);
- } else {
- FileUtils.delete(file);
- }
- }
- }
-
- return FileUtils.delete(dir);
- }
-
/**
* Deletes all files from directory geocode with the given prefix.
*
@@ -398,7 +382,7 @@ public final class LocalStorage {
if (!FileUtils.delete(file)) {
Log.w("LocalStorage.deleteFilesPrefix: Can't delete file " + file.getName());
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("LocalStorage.deleteFilesPrefix", e);
}
}
@@ -417,7 +401,7 @@ public final class LocalStorage {
public static File[] getFilesWithPrefix(final String geocode, final String filenamePrefix) {
final FilenameFilter filter = new FilenameFilter() {
@Override
- public boolean accept(File dir, String filename) {
+ public boolean accept(final File dir, final String filename) {
return filename.startsWith(filenamePrefix);
}
};
@@ -430,35 +414,35 @@ public final class LocalStorage {
*/
public static List<File> getStorages() {
- String extStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
- List<File> storages = new ArrayList<>();
+ final String extStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
+ final List<File> storages = new ArrayList<>();
storages.add(new File(extStorage));
- File file = new File(FILE_SYSTEM_TABLE_PATH);
+ final File file = new File(FILE_SYSTEM_TABLE_PATH);
if (file.canRead()) {
Reader fr = null;
BufferedReader br = null;
try {
- fr = new InputStreamReader(new FileInputStream(file), "UTF-8");
+ fr = new InputStreamReader(new FileInputStream(file), CharEncoding.UTF_8);
br = new BufferedReader(fr);
- String s = br.readLine();
- while (s != null) {
- if (s.startsWith("dev_mount")) {
- String[] tokens = StringUtils.split(s);
+ String str = br.readLine();
+ while (str != null) {
+ if (str.startsWith("dev_mount")) {
+ final String[] tokens = StringUtils.split(str);
if (tokens.length >= 3) {
- String path = tokens[2]; // mountpoint
+ final String path = tokens[2]; // mountpoint
if (!extStorage.equals(path)) {
- File directory = new File(path);
+ final File directory = new File(path);
if (directory.exists() && directory.isDirectory()) {
storages.add(directory);
}
}
}
}
- s = br.readLine();
+ str = br.readLine();
}
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("Could not get additional mount points for user content. " +
- "Proceeding with external storage only (" + extStorage + ")");
+ "Proceeding with external storage only (" + extStorage + ")", e);
} finally {
IOUtils.closeQuietly(fr);
IOUtils.closeQuietly(br);
diff --git a/main/src/cgeo/geocaching/files/NoCloseInputStream.java b/main/src/cgeo/geocaching/files/NoCloseInputStream.java
index 5a72607..493f6ca 100644
--- a/main/src/cgeo/geocaching/files/NoCloseInputStream.java
+++ b/main/src/cgeo/geocaching/files/NoCloseInputStream.java
@@ -9,9 +9,9 @@ import java.io.InputStream;
* one input stream (e.g. ZipInputStream) because SAX parser closes stream.
*/
public class NoCloseInputStream extends FilterInputStream {
- private static ClosedInputStream closedInputStream = new ClosedInputStream();
+ private static final ClosedInputStream closedInputStream = new ClosedInputStream();
- public NoCloseInputStream(InputStream in) {
+ public NoCloseInputStream(final InputStream in) {
super(in);
}
diff --git a/main/src/cgeo/geocaching/files/ParserException.java b/main/src/cgeo/geocaching/files/ParserException.java
index c0076cc..6c8cfda 100644
--- a/main/src/cgeo/geocaching/files/ParserException.java
+++ b/main/src/cgeo/geocaching/files/ParserException.java
@@ -9,11 +9,11 @@ public class ParserException extends Exception {
public ParserException() {
}
- public ParserException(String detailMessage) {
+ public ParserException(final String detailMessage) {
super(detailMessage);
}
- public ParserException(String detailMessage, Throwable throwable) {
+ public ParserException(final String detailMessage, final Throwable throwable) {
super(detailMessage, throwable);
}
diff --git a/main/src/cgeo/geocaching/files/ProgressInputStream.java b/main/src/cgeo/geocaching/files/ProgressInputStream.java
index 552aee0..3b249a1 100644
--- a/main/src/cgeo/geocaching/files/ProgressInputStream.java
+++ b/main/src/cgeo/geocaching/files/ProgressInputStream.java
@@ -16,12 +16,12 @@ public class ProgressInputStream extends FilterInputStream {
private int progress = 0;
- protected ProgressInputStream(InputStream in) {
+ protected ProgressInputStream(final InputStream in) {
super(in);
}
@Override
- public int read() throws IOException {
+ public int read() throws IOException { // NO_UCD This method is called from the framework
final int read = super.read();
if (read >= 0) {
progress++;
@@ -30,7 +30,7 @@ public class ProgressInputStream extends FilterInputStream {
}
@Override
- public int read(byte[] buffer, int offset, int count) throws IOException {
+ public int read(final byte[] buffer, final int offset, final int count) throws IOException {
final int read = super.read(buffer, offset, count);
progress += read;
return read;
diff --git a/main/src/cgeo/geocaching/files/SimpleDirChooser.java b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
index 2aadf16..687aaa0 100644
--- a/main/src/cgeo/geocaching/files/SimpleDirChooser.java
+++ b/main/src/cgeo/geocaching/files/SimpleDirChooser.java
@@ -142,7 +142,7 @@ public class SimpleDirChooser extends AbstractListActivity {
for (final File currentDir : dirs) {
listDirs.add(new Option(currentDir.getName(), currentDir.getAbsolutePath(), currentDir.canWrite()));
}
- } catch (final RuntimeException e) {
+ } catch (final RuntimeException ignored) {
}
Collections.sort(listDirs, Option.NAME_COMPARATOR);
if (dir.getParent() != null) {
@@ -263,7 +263,7 @@ public class SimpleDirChooser extends AbstractListActivity {
private boolean checked = false;
private boolean writeable = false;
- private static Comparator<Option> NAME_COMPARATOR = new Comparator<SimpleDirChooser.Option>() {
+ private final static Comparator<Option> NAME_COMPARATOR = new Comparator<SimpleDirChooser.Option>() {
@Override
public int compare(final Option lhs, final Option rhs) {
diff --git a/main/src/cgeo/geocaching/filter/AbstractFilter.java b/main/src/cgeo/geocaching/filter/AbstractFilter.java
index e602b0f..4d521c5 100644
--- a/main/src/cgeo/geocaching/filter/AbstractFilter.java
+++ b/main/src/cgeo/geocaching/filter/AbstractFilter.java
@@ -1,21 +1,30 @@
package cgeo.geocaching.filter;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
abstract class AbstractFilter implements IFilter {
+ @NonNull
private final String name;
- protected AbstractFilter(final String name) {
+ protected AbstractFilter(final int nameResourceId) {
+ this(CgeoApplication.getInstance().getString(nameResourceId));
+ }
+
+ protected AbstractFilter(@NonNull final String name) {
this.name = name;
}
+
@Override
- public void filter(final List<Geocache> list) {
+ public void filter(@NonNull final List<Geocache> list) {
final List<Geocache> itemsToRemove = new ArrayList<>();
- for (Geocache item : list) {
+ for (final Geocache item : list) {
if (!accepts(item)) {
itemsToRemove.add(item);
}
@@ -24,6 +33,7 @@ abstract class AbstractFilter implements IFilter {
}
@Override
+ @NonNull
public String getName() {
return name;
}
@@ -37,4 +47,9 @@ abstract class AbstractFilter implements IFilter {
public String toString() {
return getName();
}
+
+ @Override
+ public int getImageId() {
+ return 0;
+ }
}
diff --git a/main/src/cgeo/geocaching/filter/AttributeFilter.java b/main/src/cgeo/geocaching/filter/AttributeFilter.java
index b59ab29..6ed4a8f 100644
--- a/main/src/cgeo/geocaching/filter/AttributeFilter.java
+++ b/main/src/cgeo/geocaching/filter/AttributeFilter.java
@@ -4,6 +4,8 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import android.content.res.Resources;
import java.util.LinkedList;
@@ -13,7 +15,7 @@ class AttributeFilter extends AbstractFilter {
private final String attribute;
- public AttributeFilter(final String name, final String attribute) {
+ public AttributeFilter(@NonNull final String name, final String attribute) {
super(name);
this.attribute = attribute;
}
@@ -25,13 +27,14 @@ class AttributeFilter extends AbstractFilter {
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return cache.getAttributes().contains(attribute);
}
public static class Factory implements IFilterFactory {
@Override
+ @NonNull
public List<IFilter> getFilters() {
final String packageName = CgeoApplication.getInstance().getBaseContext().getPackageName();
final Resources res = CgeoApplication.getInstance().getResources();
diff --git a/main/src/cgeo/geocaching/filter/DifficultyFilter.java b/main/src/cgeo/geocaching/filter/DifficultyFilter.java
index 175ad75..7989560 100644
--- a/main/src/cgeo/geocaching/filter/DifficultyFilter.java
+++ b/main/src/cgeo/geocaching/filter/DifficultyFilter.java
@@ -3,6 +3,8 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -13,7 +15,7 @@ class DifficultyFilter extends AbstractRangeFilter {
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
final float difficulty = cache.getDifficulty();
return rangeMin <= difficulty && difficulty < rangeMax;
}
@@ -24,6 +26,7 @@ class DifficultyFilter extends AbstractRangeFilter {
private static final int DIFFICULTY_MAX = 5;
@Override
+ @NonNull
public List<IFilter> getFilters() {
final ArrayList<IFilter> filters = new ArrayList<>(DIFFICULTY_MAX);
for (int difficulty = DIFFICULTY_MIN; difficulty <= DIFFICULTY_MAX; difficulty++) {
diff --git a/main/src/cgeo/geocaching/filter/DistanceFilter.java b/main/src/cgeo/geocaching/filter/DistanceFilter.java
index 3328c72..b352f5d 100644
--- a/main/src/cgeo/geocaching/filter/DistanceFilter.java
+++ b/main/src/cgeo/geocaching/filter/DistanceFilter.java
@@ -2,28 +2,31 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.sensors.GeoData;
+import cgeo.geocaching.sensors.Sensors;
+
+import org.eclipse.jdt.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
class DistanceFilter extends AbstractFilter {
- private final IGeoData geo;
+ private final GeoData geo;
private final int minDistance;
private final int maxDistance;
- public DistanceFilter(String name, final int minDistance, final int maxDistance) {
+ public DistanceFilter(@NonNull final String name, final int minDistance, final int maxDistance) {
super(name);
this.minDistance = minDistance;
this.maxDistance = maxDistance;
- geo = CgeoApplication.getInstance().currentGeo();
+ geo = Sensors.getInstance().currentGeo();
}
@Override
- public boolean accepts(final Geocache cache) {
- final Geopoint currentPos = new Geopoint(geo.getLocation());
+ public boolean accepts(@NonNull final Geocache cache) {
+ final Geopoint currentPos = new Geopoint(geo);
final Geopoint coords = cache.getCoords();
if (coords == null) {
// If a cache has no coordinates, consider it to be out of range. It will
@@ -39,6 +42,7 @@ class DistanceFilter extends AbstractFilter {
private static final int[] KILOMETERS = { 0, 2, 5, 10, 20, 50 };
@Override
+ @NonNull
public List<IFilter> getFilters() {
final List<IFilter> filters = new ArrayList<>(KILOMETERS.length);
for (int i = 0; i < KILOMETERS.length; i++) {
diff --git a/main/src/cgeo/geocaching/filter/FilterActivity.java b/main/src/cgeo/geocaching/filter/FilterActivity.java
new file mode 100644
index 0000000..13a2263
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/FilterActivity.java
@@ -0,0 +1,154 @@
+package cgeo.geocaching.filter;
+
+import butterknife.ButterKnife;
+import butterknife.InjectView;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.activity.AbstractActionBarActivity;
+import cgeo.geocaching.filter.FilterRegistry.FactoryEntry;
+import cgeo.geocaching.utils.Log;
+
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.OptionsItem;
+import org.androidannotations.annotations.OptionsMenu;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.OnChildClickListener;
+import android.widget.LinearLayout;
+import android.widget.SimpleExpandableListAdapter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Show a filter selection using an {@code ExpandableListView}.
+ */
+@OptionsMenu(R.menu.filter_options)
+@EActivity
+public class FilterActivity extends AbstractActionBarActivity {
+
+ public static final String EXTRA_FILTER_RESULT = null;
+ public static final int REQUEST_SELECT_FILTER = 1234;
+
+ private static final String KEY_FILTER_NAME = "filterName";
+ private static final String KEY_FILTER_GROUP_NAME = "filterGroupName";
+
+ @InjectView(R.id.filterList) protected ExpandableListView filterList;
+ @InjectView(R.id.filters) protected LinearLayout filtersContainer;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState, R.layout.filter_activity);
+ ButterKnife.inject(this);
+
+ createListAdapter();
+ }
+
+ private void createListAdapter() {
+ final SimpleExpandableListAdapter adapter =
+ new SimpleExpandableListAdapter(
+ this,
+ // top level entries in the next 4 lines
+ createFilterTopLevelGroups(),
+ android.R.layout.simple_expandable_list_item_1,
+ new String[] { KEY_FILTER_GROUP_NAME },
+ new int[] { android.R.id.text1 },
+
+ // child level entries in the next 4 lines
+ createFilterChildren(),
+ android.R.layout.simple_expandable_list_item_2,
+ new String[] { KEY_FILTER_NAME, "CHILD_NAME" },
+ new int[] { android.R.id.text1 }
+ );
+ filterList.setAdapter(adapter);
+ filterList.setOnChildClickListener(new OnChildClickListener() {
+
+ @Override
+ public boolean onChildClick(final ExpandableListView parent, final View v, final int groupPosition, final int childPosition, final long id) {
+ setFilterResult(groupPosition, childPosition);
+ return true;
+ }
+
+ });
+ }
+
+ public static @Nullable IFilter getFilterFromPosition(final int groupPosition, final int childPosition) {
+ if (groupPosition < 0 || childPosition < 0) {
+ return null;
+ }
+ final FactoryEntry factoryEntry = FilterRegistry.getInstance().getFactories().get(groupPosition);
+ return createFilterFactory(factoryEntry.getFactory()).getFilters().get(childPosition);
+ }
+
+ /**
+ * Creates the group list with the mapped properties.
+ */
+ private static List<Map<String, String>> createFilterTopLevelGroups() {
+ final ArrayList<Map<String, String>> groups = new ArrayList<>();
+ for (final FactoryEntry factoryEntry : FilterRegistry.getInstance().getFactories()) {
+ final Map<String, String> map = new HashMap<>();
+ map.put(KEY_FILTER_GROUP_NAME, factoryEntry.getName());
+ groups.add(map);
+ }
+ return groups;
+ }
+
+ private static List<List<Map<String, String>>> createFilterChildren() {
+ final List<List<Map<String, String>>> listOfChildGroups = new ArrayList<>();
+
+ for (final FactoryEntry factoryEntry : FilterRegistry.getInstance().getFactories()) {
+ final IFilterFactory factory = createFilterFactory(factoryEntry.getFactory());
+ final List<? extends IFilter> filters = factory.getFilters();
+
+ final List<Map<String, String>> childGroups = new ArrayList<>(filters.size());
+
+ for (final IFilter filter : filters) {
+ final HashMap<String, String> hashMap = new HashMap<>(1);
+ hashMap.put(KEY_FILTER_NAME, filter.getName());
+ hashMap.put("CHILD_NAME", filter.getName());
+ childGroups.add(hashMap);
+ }
+ listOfChildGroups.add(childGroups);
+ }
+ return listOfChildGroups;
+ }
+
+ private static IFilterFactory createFilterFactory(final Class<? extends IFilterFactory> class1) {
+ try {
+ return class1.newInstance();
+ } catch (final InstantiationException e) {
+ Log.e("createFilterFactory", e);
+ } catch (final IllegalAccessException e) {
+ Log.e("createFilterFactory", e);
+ }
+ return null;
+ }
+
+ /**
+ * After calling this method, the calling activity must implement onActivityResult, and check the
+ * {@link #EXTRA_FILTER_RESULT}.
+ */
+ public static void selectFilter(@NonNull final Activity context) {
+ context.startActivityForResult(new Intent(context, FilterActivity_.class), REQUEST_SELECT_FILTER);
+ }
+
+ @OptionsItem(R.id.menu_reset_filter)
+ void resetFilter() {
+ setFilterResult(-1, -1);
+ }
+
+ private void setFilterResult(final int groupPosition, final int childPosition) {
+ final Intent resultIntent = new Intent();
+ resultIntent.putExtra(EXTRA_FILTER_RESULT, new int[] { groupPosition, childPosition });
+ setResult(Activity.RESULT_OK, resultIntent);
+ finish();
+ }
+}
diff --git a/main/src/cgeo/geocaching/filter/FilterRegistry.java b/main/src/cgeo/geocaching/filter/FilterRegistry.java
new file mode 100644
index 0000000..d6d9db9
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/FilterRegistry.java
@@ -0,0 +1,86 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+import cgeo.geocaching.filter.SizeFilter.Factory;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.content.res.Resources;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * singleton registry of all available filter components
+ *
+ */
+public class FilterRegistry {
+ private final List<FactoryEntry> registry = new ArrayList<>();
+ private static Resources res;
+
+ static class FactoryEntry {
+ private final String name;
+ private final @NonNull Class<? extends IFilterFactory> filterFactory;
+
+ public FactoryEntry(final String name, final @NonNull Class<? extends IFilterFactory> filterFactory) {
+ this.name = name;
+ this.filterFactory = filterFactory;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Class<? extends IFilterFactory> getFactory() {
+ return filterFactory;
+ }
+ }
+
+ private static class SingletonHolder {
+ private static final FilterRegistry INSTANCE = new FilterRegistry();
+ }
+
+ public static FilterRegistry getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private FilterRegistry() {
+ res = CgeoApplication.getInstance().getResources();
+ register(R.string.caches_filter_type, TypeFilter.Factory.class);
+ register(R.string.caches_filter_size, SizeFilter.Factory.class);
+ register(R.string.cache_terrain, TerrainFilter.Factory.class);
+ register(R.string.cache_difficulty, DifficultyFilter.Factory.class);
+ register(R.string.cache_attributes, AttributeFilter.Factory.class);
+ register(R.string.cache_status, StateFilterFactory.class);
+ register(R.string.caches_filter_origin, OriginFilter.Factory.class);
+ register(R.string.caches_filter_distance, DistanceFilter.Factory.class);
+ register(R.string.caches_filter_popularity, PopularityFilter.Factory.class);
+ register(R.string.caches_filter_popularity_ratio, PopularityRatioFilter.Factory.class);
+ register(R.string.caches_filter_personal_data, PersonalDataFilterFactory.class);
+ }
+
+ private void register(final int resourceId, final @NonNull Class<? extends IFilterFactory> factoryClass) {
+ registry.add(new FactoryEntry(res.getString(resourceId), factoryClass));
+ }
+
+ public String getFactoryName(final Class<Factory> factoryClass) {
+ for (final FactoryEntry entry : registry) {
+ if (entry.filterFactory == factoryClass) {
+ return entry.name;
+ }
+ }
+ return StringUtils.EMPTY;
+ }
+
+ public List<FactoryEntry> getFactories() {
+ return Collections.unmodifiableList(registry);
+ }
+}
diff --git a/main/src/cgeo/geocaching/filter/FilterUserInterface.java b/main/src/cgeo/geocaching/filter/FilterUserInterface.java
deleted file mode 100644
index 9f1d563..0000000
--- a/main/src/cgeo/geocaching/filter/FilterUserInterface.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package cgeo.geocaching.filter;
-
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.R;
-import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.settings.Settings;
-import cgeo.geocaching.utils.Log;
-
-import rx.functions.Action1;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.widget.ArrayAdapter;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public final class FilterUserInterface {
-
- private static class FactoryEntry {
- private final String name;
- private final Class<? extends IFilterFactory> filterFactory;
-
- public FactoryEntry(final String name, final Class<? extends IFilterFactory> filterFactory) {
- this.name = name;
- this.filterFactory = filterFactory;
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- private final Activity activity;
- private final ArrayList<FactoryEntry> registry;
- private final Resources res;
-
- public FilterUserInterface(final Activity activity) {
- this.activity = activity;
- this.res = CgeoApplication.getInstance().getResources();
-
- registry = new ArrayList<>();
- if (Settings.getCacheType() == CacheType.ALL) {
- register(R.string.caches_filter_type, TypeFilter.Factory.class);
- }
- register(R.string.caches_filter_size, SizeFilter.Factory.class);
- register(R.string.cache_terrain, TerrainFilter.Factory.class);
- register(R.string.cache_difficulty, DifficultyFilter.Factory.class);
- register(R.string.cache_attributes, AttributeFilter.Factory.class);
- register(R.string.cache_status, StateFilter.Factory.class);
- register(R.string.caches_filter_track, TrackablesFilter.class);
- register(R.string.caches_filter_modified, ModifiedFilter.class);
- register(R.string.caches_filter_origin, OriginFilter.Factory.class);
- register(R.string.caches_filter_distance, DistanceFilter.Factory.class);
- register(R.string.caches_filter_personal_note, PersonalNoteFilter.class);
- register(R.string.caches_filter_popularity, PopularityFilter.Factory.class);
- register(R.string.caches_filter_popularity_ratio, PopularityRatioFilter.Factory.class);
-
- // sort by localized names
- Collections.sort(registry, new Comparator<FactoryEntry>() {
-
- @Override
- public int compare(final FactoryEntry lhs, final FactoryEntry rhs) {
- return lhs.name.compareToIgnoreCase(rhs.name);
- }
- });
-
- // reset shall be last
- register(R.string.caches_filter_clear, null);
- }
-
- private void register(final int resourceId, final Class<? extends IFilterFactory> factoryClass) {
- registry.add(new FactoryEntry(res.getString(resourceId), factoryClass));
- }
-
- public void selectFilter(final Action1<IFilter> runAfterwards) {
- final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(R.string.caches_filter_title);
-
- final ArrayAdapter<FactoryEntry> adapter = new ArrayAdapter<>(activity, android.R.layout.select_dialog_item, registry);
-
- builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog, final int itemIndex) {
- FactoryEntry entry = adapter.getItem(itemIndex);
- // reset?
- if (entry.filterFactory == null) {
- runAfterwards.call(null);
- }
- else {
- try {
- IFilterFactory factoryInstance = entry.filterFactory.newInstance();
- selectFromFactory(factoryInstance, entry.name, runAfterwards);
- } catch (Exception e) {
- Log.e("selectFilter", e);
- }
- }
- }
- });
-
- builder.create().show();
- }
-
- 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.call(filters.get(0));
- return;
- }
-
- final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle(menuTitle);
-
- final ArrayAdapter<IFilter> adapter = new ArrayAdapter<>(activity, android.R.layout.select_dialog_item, filters);
- builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog, final int item) {
- runAfterwards.call(filters.get(item));
- }
- });
-
- builder.create().show();
- }
-
-}
diff --git a/main/src/cgeo/geocaching/filter/IFilter.java b/main/src/cgeo/geocaching/filter/IFilter.java
index 4fafe6f..f590f79 100644
--- a/main/src/cgeo/geocaching/filter/IFilter.java
+++ b/main/src/cgeo/geocaching/filter/IFilter.java
@@ -2,17 +2,21 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.List;
public interface IFilter {
+ @NonNull
String getName();
/**
- * @param cache
- * @return true if the filter accepts the cache, false otherwise
+ * @return {@code true} if the filter accepts the cache, false otherwise
*/
- boolean accepts(final Geocache cache);
+ boolean accepts(@NonNull final Geocache cache);
+
+ void filter(@NonNull final List<Geocache> list);
- void filter(final List<Geocache> list);
+ int getImageId();
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/filter/IFilterFactory.java b/main/src/cgeo/geocaching/filter/IFilterFactory.java
index afc99af..82e69da 100644
--- a/main/src/cgeo/geocaching/filter/IFilterFactory.java
+++ b/main/src/cgeo/geocaching/filter/IFilterFactory.java
@@ -1,7 +1,10 @@
package cgeo.geocaching.filter;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.List;
interface IFilterFactory {
+ @NonNull
List<? extends IFilter> getFilters();
}
diff --git a/main/src/cgeo/geocaching/filter/ModifiedFilter.java b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
index 2ac088a..9b5c856 100644
--- a/main/src/cgeo/geocaching/filter/ModifiedFilter.java
+++ b/main/src/cgeo/geocaching/filter/ModifiedFilter.java
@@ -1,25 +1,27 @@
package cgeo.geocaching.filter;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.Collections;
import java.util.List;
class ModifiedFilter extends AbstractFilter implements IFilterFactory {
public ModifiedFilter() {
- super(CgeoApplication.getInstance().getString(R.string.caches_filter_modified));
+ super(R.string.caches_filter_modified);
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
// modified on GC
return cache.hasUserModifiedCoords() || cache.hasFinalDefined();
}
@Override
+ @NonNull
public List<ModifiedFilter> getFilters() {
return Collections.singletonList(this);
}
diff --git a/main/src/cgeo/geocaching/filter/OfflineLogFilter.java b/main/src/cgeo/geocaching/filter/OfflineLogFilter.java
new file mode 100644
index 0000000..0ed9618
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/OfflineLogFilter.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+public class OfflineLogFilter extends AbstractFilter {
+
+ protected OfflineLogFilter() {
+ super(R.string.caches_filter_offline_log);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isLogOffline();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/filter/OriginFilter.java b/main/src/cgeo/geocaching/filter/OriginFilter.java
index 99d1c05..d51b02c 100644
--- a/main/src/cgeo/geocaching/filter/OriginFilter.java
+++ b/main/src/cgeo/geocaching/filter/OriginFilter.java
@@ -4,6 +4,8 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -13,22 +15,23 @@ public class OriginFilter extends AbstractFilter {
private final IConnector connector;
- public OriginFilter(final IConnector connector) {
+ public OriginFilter(@NonNull final IConnector connector) {
super(connector.getName());
this.connector = connector;
}
@Override
- public final boolean accepts(final Geocache cache) {
+ public final boolean accepts(@NonNull final Geocache cache) {
return ConnectorFactory.getConnector(cache) == connector;
}
public static final class Factory implements IFilterFactory {
@Override
+ @NonNull
public List<OriginFilter> getFilters() {
final ArrayList<OriginFilter> filters = new ArrayList<>();
- for (IConnector connector : ConnectorFactory.getConnectors()) {
+ for (final IConnector connector : ConnectorFactory.getConnectors()) {
filters.add(new OriginFilter(connector));
}
diff --git a/main/src/cgeo/geocaching/filter/OwnRatingFilter.java b/main/src/cgeo/geocaching/filter/OwnRatingFilter.java
new file mode 100644
index 0000000..1b86bab
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/OwnRatingFilter.java
@@ -0,0 +1,34 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.gcvote.GCVote;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Filter {@link Geocache}s if they have a locally stored <b>own</b> {@link GCVote} rating. This filter will not do any
+ * network request to find potentially missing local votes.
+ *
+ */
+public class OwnRatingFilter extends AbstractFilter implements IFilterFactory {
+
+ protected OwnRatingFilter() {
+ super(R.string.caches_filter_own_rating);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.getMyVote() > 0;
+ }
+
+ @Override
+ @NonNull
+ public List<OwnRatingFilter> getFilters() {
+ return Collections.singletonList(this);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/filter/PersonalDataFilterFactory.java b/main/src/cgeo/geocaching/filter/PersonalDataFilterFactory.java
new file mode 100644
index 0000000..e9780da
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/PersonalDataFilterFactory.java
@@ -0,0 +1,16 @@
+package cgeo.geocaching.filter;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class PersonalDataFilterFactory implements IFilterFactory {
+
+ @Override
+ @NonNull
+ public List<? extends IFilter> getFilters() {
+ return Arrays.asList(new OwnRatingFilter(), new PersonalNoteFilter(), new ModifiedFilter(), new OfflineLogFilter());
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/filter/PersonalNoteFilter.java b/main/src/cgeo/geocaching/filter/PersonalNoteFilter.java
index 15d262f..11c623e 100644
--- a/main/src/cgeo/geocaching/filter/PersonalNoteFilter.java
+++ b/main/src/cgeo/geocaching/filter/PersonalNoteFilter.java
@@ -1,26 +1,30 @@
package cgeo.geocaching.filter;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import java.util.Collections;
import java.util.List;
+/**
+ * Filter that accepts {@link Geocache}s with a non empty personal note stored locally.
+ */
public class PersonalNoteFilter extends AbstractFilter implements IFilterFactory {
protected PersonalNoteFilter() {
- super(CgeoApplication.getInstance().getString(R.string.caches_filter_personal_note));
+ super(R.string.caches_filter_personal_note);
}
@Override
- public boolean accepts(Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return StringUtils.isNotBlank(cache.getPersonalNote());
}
@Override
+ @NonNull
public List<PersonalNoteFilter> getFilters() {
return Collections.singletonList(this);
}
diff --git a/main/src/cgeo/geocaching/filter/PopularityFilter.java b/main/src/cgeo/geocaching/filter/PopularityFilter.java
index a0244b9..eabc533 100644
--- a/main/src/cgeo/geocaching/filter/PopularityFilter.java
+++ b/main/src/cgeo/geocaching/filter/PopularityFilter.java
@@ -4,6 +4,8 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -11,14 +13,14 @@ class PopularityFilter extends AbstractFilter {
private final int minFavorites;
private final int maxFavorites;
- public PopularityFilter(String name, final int minFavorites, final int maxFavorites) {
+ public PopularityFilter(@NonNull final String name, final int minFavorites, final int maxFavorites) {
super(name);
this.minFavorites = minFavorites;
this.maxFavorites = maxFavorites;
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return (cache.getFavoritePoints() > minFavorites) && (cache.getFavoritePoints() <= maxFavorites);
}
@@ -27,10 +29,10 @@ class PopularityFilter extends AbstractFilter {
private static final int[] FAVORITES = { 10, 20, 50, 100, 200, 500 };
@Override
+ @NonNull
public List<IFilter> getFilters() {
final List<IFilter> filters = new ArrayList<>(FAVORITES.length);
- for (int i = 0; i < FAVORITES.length; i++) {
- final int minRange = FAVORITES[i];
+ for (final int minRange : FAVORITES) {
final int maxRange = Integer.MAX_VALUE;
final String range = "> " + minRange;
final String name = CgeoApplication.getInstance().getResources().getQuantityString(R.plurals.favorite_points, minRange, range);
diff --git a/main/src/cgeo/geocaching/filter/PopularityRatioFilter.java b/main/src/cgeo/geocaching/filter/PopularityRatioFilter.java
index a04f219..0548345 100644
--- a/main/src/cgeo/geocaching/filter/PopularityRatioFilter.java
+++ b/main/src/cgeo/geocaching/filter/PopularityRatioFilter.java
@@ -6,6 +6,8 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.enumerations.LogType;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -16,14 +18,14 @@ class PopularityRatioFilter extends AbstractFilter {
private final int minRatio;
private final int maxRatio;
- public PopularityRatioFilter(String name, final int minRatio, final int maxRatio) {
+ public PopularityRatioFilter(@NonNull final String name, final int minRatio, final int maxRatio) {
super(name);
this.minRatio = minRatio;
this.maxRatio = maxRatio;
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
final int finds = getFindsCount(cache);
if (finds == 0) { // Prevent division by zero
@@ -35,11 +37,11 @@ class PopularityRatioFilter extends AbstractFilter {
return ratio > minRatio && ratio <= maxRatio;
}
- private static int getFindsCount(Geocache cache) {
+ private static int getFindsCount(final Geocache cache) {
if (cache.getLogCounts().isEmpty()) {
cache.setLogCounts(DataStore.loadLogCounts(cache.getGeocode()));
}
- Integer logged = cache.getLogCounts().get(LogType.FOUND_IT);
+ final Integer logged = cache.getLogCounts().get(LogType.FOUND_IT);
if (logged != null) {
return logged;
}
@@ -51,12 +53,12 @@ class PopularityRatioFilter extends AbstractFilter {
private static final int[] RATIOS = { 10, 20, 30, 40, 50, 75 };
@Override
+ @NonNull
public List<IFilter> getFilters() {
final List<IFilter> filters = new ArrayList<>(RATIOS.length);
- for (int i = 0; i < RATIOS.length; i++) {
- final int minRange = RATIOS[i];
+ for (final int minRange : RATIOS) {
final int maxRange = Integer.MAX_VALUE;
- final String name = "> " + minRange + " " + CgeoApplication.getInstance().getResources().getString(R.string.percent_favorite_points);
+ final String name = CgeoApplication.getInstance().getResources().getString(R.string.more_than_percent_favorite_points, minRange);
filters.add(new PopularityRatioFilter(name, minRange, maxRange));
}
return filters;
diff --git a/main/src/cgeo/geocaching/filter/RatingFilter.java b/main/src/cgeo/geocaching/filter/RatingFilter.java
new file mode 100644
index 0000000..16ce16c
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/RatingFilter.java
@@ -0,0 +1,25 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.gcvote.GCVote;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Filter {@link Geocache}s if they have a locally stored {@link GCVote} rating. This filter will not do any network
+ * request to find potentially missing local votes.
+ *
+ */
+public class RatingFilter extends AbstractFilter {
+
+ protected RatingFilter() {
+ super(R.string.caches_filter_rating);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.getRating() > 0;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/filter/SizeFilter.java b/main/src/cgeo/geocaching/filter/SizeFilter.java
index f02874c..a19d95b 100644
--- a/main/src/cgeo/geocaching/filter/SizeFilter.java
+++ b/main/src/cgeo/geocaching/filter/SizeFilter.java
@@ -3,23 +3,26 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.enumerations.CacheSize;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.LinkedList;
import java.util.List;
class SizeFilter extends AbstractFilter {
private final CacheSize cacheSize;
- public SizeFilter(final CacheSize cacheSize) {
+ public SizeFilter(@NonNull final CacheSize cacheSize) {
super(cacheSize.id);
this.cacheSize = cacheSize;
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return cacheSize == cache.getSize();
}
@Override
+ @NonNull
public String getName() {
return cacheSize.getL10n();
}
@@ -27,16 +30,17 @@ class SizeFilter extends AbstractFilter {
public static class Factory implements IFilterFactory {
@Override
+ @NonNull
public List<IFilter> getFilters() {
final CacheSize[] cacheSizes = CacheSize.values();
final List<IFilter> filters = new LinkedList<>();
- for (CacheSize cacheSize : cacheSizes) {
+ for (final CacheSize cacheSize : cacheSizes) {
if (cacheSize != CacheSize.UNKNOWN) {
filters.add(new SizeFilter(cacheSize));
}
}
return filters;
}
-
}
+
}
diff --git a/main/src/cgeo/geocaching/filter/StateFilter.java b/main/src/cgeo/geocaching/filter/StateFilter.java
deleted file mode 100644
index ebe133c..0000000
--- a/main/src/cgeo/geocaching/filter/StateFilter.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package cgeo.geocaching.filter;
-
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.Geocache;
-import cgeo.geocaching.R;
-
-import android.content.res.Resources;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-abstract class StateFilter extends AbstractFilter {
-
- static final Resources res = CgeoApplication.getInstance().getResources();
-
- protected StateFilter(final String name) {
- super(name);
- }
-
- static class StateFoundFilter extends StateFilter {
-
- public StateFoundFilter() {
- super(res.getString(R.string.cache_status_found));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isFound();
- }
-
- }
-
- static class StateNotFoundFilter extends StateFilter {
-
- public StateNotFoundFilter() {
- super(res.getString(R.string.cache_not_status_found));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return !cache.isFound();
- }
-
- }
-
- static class StateArchivedFilter extends StateFilter {
- public StateArchivedFilter() {
- super(res.getString(R.string.cache_status_archived));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isArchived();
- }
- }
-
- static class StateDisabledFilter extends StateFilter {
- public StateDisabledFilter() {
- super(res.getString(R.string.cache_status_disabled));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isDisabled();
- }
- }
-
- static class StatePremiumFilter extends StateFilter {
- public StatePremiumFilter() {
- super(res.getString(R.string.cache_status_premium));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isPremiumMembersOnly();
- }
- }
-
- static class StateNonPremiumFilter extends StateFilter {
- public StateNonPremiumFilter() {
- super(res.getString(R.string.cache_status_not_premium));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return !cache.isPremiumMembersOnly();
- }
- }
-
- private static class StateOfflineLogFilter extends StateFilter {
- public StateOfflineLogFilter() {
- super(res.getString(R.string.cache_status_offline_log));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isLogOffline();
- }
- }
-
- static class StateStoredFilter extends StateFilter {
- public StateStoredFilter() {
- super(res.getString(R.string.cache_status_stored));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return cache.isOffline();
- }
- }
-
- static class StateNotStoredFilter extends StateFilter {
- public StateNotStoredFilter() {
- super(res.getString(R.string.cache_status_not_stored));
- }
-
- @Override
- public boolean accepts(final Geocache cache) {
- return !cache.isOffline();
- }
- }
-
- public static class Factory implements IFilterFactory {
-
- @Override
- public List<StateFilter> getFilters() {
- final List<StateFilter> filters = new ArrayList<>(6);
- filters.add(new StateFoundFilter());
- filters.add(new StateNotFoundFilter());
- filters.add(new StateArchivedFilter());
- filters.add(new StateDisabledFilter());
- filters.add(new StatePremiumFilter());
- filters.add(new StateNonPremiumFilter());
- filters.add(new StateOfflineLogFilter());
- filters.add(new StateStoredFilter());
- filters.add(new StateNotStoredFilter());
-
- Collections.sort(filters, new Comparator<StateFilter>() {
-
- @Override
- public int compare(final StateFilter filter1, final StateFilter filter2) {
- return String.CASE_INSENSITIVE_ORDER.compare(filter1.getName(), filter2.getName());
- }
- });
-
- return filters;
- }
-
- }
-
-}
diff --git a/main/src/cgeo/geocaching/filter/StateFilterFactory.java b/main/src/cgeo/geocaching/filter/StateFilterFactory.java
new file mode 100644
index 0000000..42de764
--- /dev/null
+++ b/main/src/cgeo/geocaching/filter/StateFilterFactory.java
@@ -0,0 +1,145 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+class StateFilterFactory implements IFilterFactory {
+
+ @Override
+ @NonNull
+ public List<? extends IFilter> getFilters() {
+ final List<AbstractFilter> filters = new ArrayList<>(6);
+ filters.add(new StateFoundFilter());
+ filters.add(new StateNotFoundFilter());
+ filters.add(new StateArchivedFilter());
+ filters.add(new StateDisabledFilter());
+ filters.add(new StatePremiumFilter());
+ filters.add(new StateNonPremiumFilter());
+ filters.add(new StateOfflineLogFilter());
+ filters.add(new StateStoredFilter());
+ filters.add(new StateNotStoredFilter());
+ filters.add(new RatingFilter());
+ filters.add(new TrackablesFilter());
+
+ Collections.sort(filters, new Comparator<AbstractFilter>() {
+
+ @Override
+ public int compare(final AbstractFilter filter1, final AbstractFilter filter2) {
+ return String.CASE_INSENSITIVE_ORDER.compare(filter1.getName(), filter2.getName());
+ }
+ });
+
+ return filters;
+ }
+
+ static class StateFoundFilter extends AbstractFilter {
+
+ public StateFoundFilter() {
+ super(R.string.cache_status_found);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isFound();
+ }
+
+ }
+
+ static class StateNotFoundFilter extends AbstractFilter {
+
+ public StateNotFoundFilter() {
+ super(R.string.cache_not_status_found);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return !cache.isFound();
+ }
+
+ }
+
+ static class StateArchivedFilter extends AbstractFilter {
+ public StateArchivedFilter() {
+ super(R.string.cache_status_archived);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isArchived();
+ }
+ }
+
+ static class StateDisabledFilter extends AbstractFilter {
+ public StateDisabledFilter() {
+ super(R.string.cache_status_disabled);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isDisabled();
+ }
+ }
+
+ static class StatePremiumFilter extends AbstractFilter {
+ public StatePremiumFilter() {
+ super(R.string.cache_status_premium);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isPremiumMembersOnly();
+ }
+ }
+
+ static class StateNonPremiumFilter extends AbstractFilter {
+ public StateNonPremiumFilter() {
+ super(R.string.cache_status_not_premium);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return !cache.isPremiumMembersOnly();
+ }
+ }
+
+ private static class StateOfflineLogFilter extends AbstractFilter {
+ public StateOfflineLogFilter() {
+ super(R.string.cache_status_offline_log);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isLogOffline();
+ }
+ }
+
+ static class StateStoredFilter extends AbstractFilter {
+ public StateStoredFilter() {
+ super(R.string.cache_status_stored);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return cache.isOffline();
+ }
+ }
+
+ static class StateNotStoredFilter extends AbstractFilter {
+ public StateNotStoredFilter() {
+ super(R.string.cache_status_not_stored);
+ }
+
+ @Override
+ public boolean accepts(@NonNull final Geocache cache) {
+ return !cache.isOffline();
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/filter/TerrainFilter.java b/main/src/cgeo/geocaching/filter/TerrainFilter.java
index 7da6a19..977e4a5 100644
--- a/main/src/cgeo/geocaching/filter/TerrainFilter.java
+++ b/main/src/cgeo/geocaching/filter/TerrainFilter.java
@@ -3,6 +3,8 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
@@ -13,7 +15,7 @@ class TerrainFilter extends AbstractRangeFilter {
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
final float terrain = cache.getTerrain();
return rangeMin <= terrain && terrain < rangeMax;
}
@@ -23,6 +25,7 @@ class TerrainFilter extends AbstractRangeFilter {
private static final int TERRAIN_MAX = 7;
@Override
+ @NonNull
public List<IFilter> getFilters() {
final ArrayList<IFilter> filters = new ArrayList<>(TERRAIN_MAX);
for (int terrain = TERRAIN_MIN; terrain <= TERRAIN_MAX; terrain++) {
diff --git a/main/src/cgeo/geocaching/filter/TrackablesFilter.java b/main/src/cgeo/geocaching/filter/TrackablesFilter.java
index d836a0f..debe11f 100644
--- a/main/src/cgeo/geocaching/filter/TrackablesFilter.java
+++ b/main/src/cgeo/geocaching/filter/TrackablesFilter.java
@@ -1,25 +1,18 @@
package cgeo.geocaching.filter;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
-import java.util.Collections;
-import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
-class TrackablesFilter extends AbstractFilter implements IFilterFactory {
+class TrackablesFilter extends AbstractFilter {
public TrackablesFilter() {
- super(CgeoApplication.getInstance().getString(R.string.caches_filter_track));
+ super(R.string.caches_filter_track);
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return cache.hasTrackables();
}
- @Override
- public List<TrackablesFilter> getFilters() {
- return Collections.singletonList(this);
- }
-
}
diff --git a/main/src/cgeo/geocaching/filter/TypeFilter.java b/main/src/cgeo/geocaching/filter/TypeFilter.java
index d363d39..b8c879f 100644
--- a/main/src/cgeo/geocaching/filter/TypeFilter.java
+++ b/main/src/cgeo/geocaching/filter/TypeFilter.java
@@ -3,23 +3,26 @@ package cgeo.geocaching.filter;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.enumerations.CacheType;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.LinkedList;
import java.util.List;
class TypeFilter extends AbstractFilter {
private final CacheType cacheType;
- public TypeFilter(final CacheType cacheType) {
+ public TypeFilter(@NonNull final CacheType cacheType) {
super(cacheType.id);
this.cacheType = cacheType;
}
@Override
- public boolean accepts(final Geocache cache) {
+ public boolean accepts(@NonNull final Geocache cache) {
return cacheType == cache.getType();
}
@Override
+ @NonNull
public String getName() {
return cacheType.getL10n();
}
@@ -27,10 +30,11 @@ class TypeFilter extends AbstractFilter {
public static class Factory implements IFilterFactory {
@Override
+ @NonNull
public List<IFilter> getFilters() {
final CacheType[] types = CacheType.values();
final List<IFilter> filters = new LinkedList<>();
- for (CacheType cacheType : types) {
+ for (final CacheType cacheType : types) {
if (cacheType != CacheType.ALL) {
filters.add(new TypeFilter(cacheType));
}
@@ -39,4 +43,9 @@ class TypeFilter extends AbstractFilter {
}
}
+
+ @Override
+ public int getImageId() {
+ return cacheType.markerId;
+ }
}
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index 8de3edc..2985e89 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -8,13 +8,18 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MatcherWrapper;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.io.Charsets;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserFactory;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -22,17 +27,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.regex.Pattern;
public final class GCVote {
public static final float NO_RATING = 0;
- private static final Pattern PATTERN_LOG_IN = Pattern.compile("loggedIn='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_GUID = Pattern.compile("cacheId='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_WAYPOINT = Pattern.compile("waypoint='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_RATING = Pattern.compile("voteAvg='([0-9.]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTES = Pattern.compile("voteCnt='([0-9]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTE = Pattern.compile("voteUser='([0-9.]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTE_ELEMENT = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE);
private static final int MAX_CACHED_RATINGS = 1000;
private static final LeastRecentlyUsedMap<String, GCVoteRating> RATINGS_CACHE = new LeastRecentlyUsedMap.LruCache<>(MAX_CACHED_RATINGS);
@@ -46,10 +43,6 @@ public final class GCVote {
/**
* Get user rating for a given guid or geocode. For a guid first the ratings cache is checked
* before a request to gcvote.com is made.
- *
- * @param guid
- * @param geocode
- * @return
*/
public static GCVoteRating getRating(final String guid, final String geocode) {
if (StringUtils.isNotBlank(guid) && RATINGS_CACHE.containsKey(guid)) {
@@ -66,161 +59,100 @@ public final class GCVote {
/**
* Get user ratings from gcvote.com
- *
- * @param guids
- * @param geocodes
- * @return
*/
+ @NonNull
private static Map<String, GCVoteRating> getRating(final List<String> guids, final List<String> geocodes) {
if (guids == null && geocodes == null) {
- return null;
+ return Collections.emptyMap();
}
- final Map<String, GCVoteRating> ratings = new HashMap<>();
+ final Parameters params = new Parameters("version", "cgeo");
+ final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
+ if (login != null) {
+ params.put("userName", login.left, "password", login.right);
+ }
+ // use guid or gccode for lookup
+ final boolean requestByGuids = CollectionUtils.isNotEmpty(guids);
+ if (requestByGuids) {
+ params.put("cacheIds", StringUtils.join(guids, ','));
+ } else {
+ params.put("waypoints", StringUtils.join(geocodes, ','));
+ }
+ final InputStream response = Network.getResponseStream(Network.getRequest("http://gcvote.com/getVotes.php", params));
+ if (response == null) {
+ return Collections.emptyMap();
+ }
try {
- final Parameters params = new Parameters();
- if (Settings.isLogin()) {
- final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
- if (login != null) {
- params.put("userName", login.left, "password", login.right);
- }
- }
- // use guid or gccode for lookup
- boolean requestByGuids = true;
- if (guids != null && !guids.isEmpty()) {
- params.put("cacheIds", StringUtils.join(guids.toArray(), ','));
- } else {
- params.put("waypoints", StringUtils.join(geocodes.toArray(), ','));
- requestByGuids = false;
- }
- params.put("version", "cgeo");
- final String page = Network.getResponseData(Network.getRequest("http://gcvote.com/getVotes.php", params));
- if (page == null) {
- return null;
- }
-
- final MatcherWrapper matcherVoteElement = new MatcherWrapper(PATTERN_VOTE_ELEMENT, page);
- while (matcherVoteElement.find()) {
- String voteData = matcherVoteElement.group(1);
- if (voteData == null) {
- continue;
- }
-
- String id = null;
- String guid = null;
- final MatcherWrapper matcherGuid = new MatcherWrapper(PATTERN_GUID, voteData);
- if (matcherGuid.find()) {
- if (matcherGuid.groupCount() > 0) {
- guid = matcherGuid.group(1);
- if (requestByGuids) {
- id = guid;
- }
- }
- }
- if (!requestByGuids) {
- final MatcherWrapper matcherWp = new MatcherWrapper(PATTERN_WAYPOINT, voteData);
- if (matcherWp.find()) {
- if (matcherWp.groupCount() > 0) {
- id = matcherWp.group(1);
- }
- }
- }
- if (id == null) {
- continue;
- }
-
- boolean loggedIn = false;
- final MatcherWrapper matcherLoggedIn = new MatcherWrapper(PATTERN_LOG_IN, page);
- if (matcherLoggedIn.find()) {
- if (matcherLoggedIn.groupCount() > 0) {
- if (matcherLoggedIn.group(1).equalsIgnoreCase("true")) {
- loggedIn = true;
- }
- }
- }
-
- float rating = NO_RATING;
- try {
- final MatcherWrapper matcherRating = new MatcherWrapper(PATTERN_RATING, voteData);
- if (matcherRating.find()) {
- rating = Float.parseFloat(matcherRating.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse rating");
- }
- if (!isValidRating(rating)) {
- continue;
- }
-
- int votes = -1;
- try {
- final MatcherWrapper matcherVotes = new MatcherWrapper(PATTERN_VOTES, voteData);
- if (matcherVotes.find()) {
- votes = Integer.parseInt(matcherVotes.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse vote count");
- }
- if (votes < 0) {
- continue;
- }
+ return getRatingsFromXMLResponse(response, requestByGuids);
+ } finally {
+ IOUtils.closeQuietly(response);
+ }
+ }
- float myVote = NO_RATING;
- if (loggedIn) {
- try {
- final MatcherWrapper matcherVote = new MatcherWrapper(PATTERN_VOTE, voteData);
- if (matcherVote.find()) {
- myVote = Float.parseFloat(matcherVote.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse user's vote");
+ static Map<String, GCVoteRating> getRatingsFromXMLResponse(@NonNull final InputStream response, final boolean requestByGuids) {
+ try {
+ final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ final XmlPullParser xpp = factory.newPullParser();
+ xpp.setInput(response, Charsets.UTF_8.name());
+ boolean loggedIn = false;
+ final Map<String, GCVoteRating> ratings = new HashMap<>();
+ int eventType = xpp.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = xpp.getName();
+ if (StringUtils.equals(tagName, "vote")) {
+ final String id = xpp.getAttributeValue(null, requestByGuids ? "cacheId" : "waypoint");
+ final float myVote = loggedIn ? Float.parseFloat(xpp.getAttributeValue(null, "voteUser")) : 0;
+ final GCVoteRating voteRating = new GCVoteRating(Float.parseFloat(xpp.getAttributeValue(null, "voteAvg")),
+ Integer.parseInt(xpp.getAttributeValue(null, "voteCnt")),
+ myVote);
+ ratings.put(id, voteRating);
+ } else if (StringUtils.equals(tagName, "votes")) {
+ loggedIn = StringUtils.equals(xpp.getAttributeValue(null, "loggedIn"), "true");
}
}
-
- if (StringUtils.isNotBlank(id)) {
- GCVoteRating gcvoteRating = new GCVoteRating(rating, votes, myVote);
- ratings.put(id, gcvoteRating);
- RATINGS_CACHE.put(guid, gcvoteRating);
- }
+ eventType = xpp.next();
}
- } catch (RuntimeException e) {
- Log.e("GCVote.getRating", e);
- }
+ RATINGS_CACHE.putAll(ratings);
+ return ratings;
+ } catch (final Exception e) {
+ Log.e("Cannot parse GC vote result", e);
+ return Collections.emptyMap();
- return ratings;
+ }
}
/**
* Transmit user vote to gcvote.com
*
- * @param cache
- * @param vote
+ * @param cache the geocache (supported by GCVote)
+ * @param rating the rating
* @return {@code true} if the rating was submitted successfully
*/
- public static boolean setRating(final Geocache cache, final float vote) {
+ public static boolean setRating(final Geocache cache, final float rating) {
if (!isVotingPossible(cache)) {
- return false;
+ throw new IllegalArgumentException("voting is not possible for " + cache);
}
- if (!isValidRating(vote)) {
- return false;
+ if (!isValidRating(rating)) {
+ throw new IllegalArgumentException("invalid rating " + rating);
}
final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
- if (login == null) {
- return false;
- }
-
final Parameters params = new Parameters(
"userName", login.left,
"password", login.right,
"cacheId", cache.getGuid(),
- "voteUser", String.format("%.1f", vote).replace(',', '.'),
+ "waypoint", cache.getGeocode(),
+ "voteUser", String.format(Locale.US, "%.1f", rating),
"version", "cgeo");
- final String result = Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params));
-
- return result != null && result.trim().equalsIgnoreCase("ok");
+ final String result = StringUtils.trim(Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params)));
+ if (!StringUtils.equalsIgnoreCase(result, "ok")) {
+ Log.e("GCVote.setRating: could not post rating, answer was " + result);
+ return false;
+ }
+ return true;
}
public static void loadRatings(final @NonNull ArrayList<Geocache> caches) {
@@ -236,34 +168,29 @@ public final class GCVote {
try {
final Map<String, GCVoteRating> ratings = GCVote.getRating(null, geocodes);
- if (MapUtils.isNotEmpty(ratings)) {
- // save found cache coordinates
- for (Geocache cache : caches) {
- if (ratings.containsKey(cache.getGeocode())) {
- GCVoteRating rating = ratings.get(cache.getGeocode());
+ // save found cache coordinates
+ for (final Geocache cache : caches) {
+ if (ratings.containsKey(cache.getGeocode())) {
+ final GCVoteRating rating = ratings.get(cache.getGeocode());
- cache.setRating(rating.getRating());
- cache.setVotes(rating.getVotes());
- cache.setMyVote(rating.getMyVote());
- }
+ cache.setRating(rating.getRating());
+ cache.setVotes(rating.getVotes());
+ cache.setMyVote(rating.getMyVote());
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCvote.loadRatings", e);
}
}
/**
* Get geocodes of all the caches, which can be used with GCVote. Non-GC caches will be filtered out.
- *
- * @param caches
- * @return
*/
private static @NonNull
ArrayList<String> getVotableGeocodes(final @NonNull Collection<Geocache> caches) {
final ArrayList<String> geocodes = new ArrayList<>(caches.size());
for (final Geocache cache : caches) {
- String geocode = cache.getGeocode();
+ final String geocode = cache.getGeocode();
if (StringUtils.isNotBlank(geocode) && cache.supportsGCVote()) {
geocodes.add(geocode);
}
@@ -275,11 +202,7 @@ public final class GCVote {
return rating >= MIN_RATING && rating <= MAX_RATING;
}
- public static String getRatingText(final float rating) {
- return String.format(Locale.getDefault(), "%.1f", rating);
- }
-
- public static boolean isVotingPossible(final Geocache cache) {
+ public static boolean isVotingPossible(@NonNull final Geocache cache) {
return Settings.isGCvoteLogin() && StringUtils.isNotBlank(cache.getGuid()) && cache.supportsGCVote();
}
@@ -308,7 +231,7 @@ public final class GCVote {
}
}
- private static String getString(int resId) {
+ private static String getString(final int resId) {
return CgeoApplication.getInstance().getString(resId);
}
diff --git a/main/src/cgeo/geocaching/gcvote/GCVoteDialog.java b/main/src/cgeo/geocaching/gcvote/GCVoteDialog.java
new file mode 100644
index 0000000..0738274
--- /dev/null
+++ b/main/src/cgeo/geocaching/gcvote/GCVoteDialog.java
@@ -0,0 +1,112 @@
+package cgeo.geocaching.gcvote;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.DataStore;
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.gcvote.GCVoteRatingBarUtil.OnRatingChangeListener;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import rx.functions.Action1;
+import rx.functions.Func0;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+/**
+ * Small dialog showing only a rating bar to vote on GCVote.com. Confirming the dialog will send the vote over the
+ * network (in the background).
+ */
+public class GCVoteDialog {
+
+ public static void show(final Activity context, final Geocache cache, final @Nullable Runnable afterVoteSent) {
+ final Context themedContext;
+
+ if (Settings.isLightSkin() && VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) {
+ themedContext = new ContextThemeWrapper(context, R.style.dark);
+ } else {
+ themedContext = context;
+ }
+
+ final View votingLayout = View.inflate(themedContext, R.layout.gcvote_dialog, null);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(themedContext);
+ builder.setView(votingLayout);
+ builder.setPositiveButton(R.string.cache_menu_vote, new OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ vote(cache, GCVoteRatingBarUtil.getRating(votingLayout), afterVoteSent);
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int whichButton) {
+ dialog.dismiss();
+ }
+ });
+ final AlertDialog dialog = builder.create();
+
+ GCVoteRatingBarUtil.initializeRatingBar(cache, votingLayout, new OnRatingChangeListener() {
+
+ @Override
+ public void onRatingChanged(final float stars) {
+ final Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ // this listener might be fired already while the dialog is not yet shown
+ if (button != null) {
+ button.setEnabled(GCVote.isValidRating(stars));
+ }
+ }
+ });
+ dialog.show();
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(GCVote.isValidRating(cache.getMyVote()));
+ }
+
+ private static void vote(final Geocache cache, final float rating, final @Nullable Runnable afterVoteSent) {
+ RxUtils.andThenOnUi(RxUtils.networkScheduler, new Func0<Boolean>() {
+ @Override
+ public Boolean call() {
+ try {
+ if (GCVote.isValidRating(rating) && GCVote.isVotingPossible(cache)) {
+ // send over network
+ if (GCVote.setRating(cache, rating)) {
+ // store locally
+ cache.setMyVote(rating);
+ DataStore.saveChangedCache(cache);
+ return true;
+ }
+ Log.w("GCVoteDialog.vote: could not send vote");
+ }
+ } catch (final RuntimeException e) {
+ Log.e("GCVoteDialog.vote: could not send vote", e);
+ }
+
+ return false;
+ }
+ }, new Action1<Boolean>() {
+ @Override
+ public void call(final Boolean status) {
+ final CgeoApplication context = CgeoApplication.getInstance();
+ final String text = context.getString(status ? R.string.gcvote_sent : R.string.err_gcvote_send_rating);
+ Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
+ if (afterVoteSent != null) {
+ afterVoteSent.run();
+ }
+ }
+ });
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/gcvote/GCVoteRatingBarUtil.java b/main/src/cgeo/geocaching/gcvote/GCVoteRatingBarUtil.java
new file mode 100644
index 0000000..2d485bd
--- /dev/null
+++ b/main/src/cgeo/geocaching/gcvote/GCVoteRatingBarUtil.java
@@ -0,0 +1,58 @@
+package cgeo.geocaching.gcvote;
+
+import butterknife.ButterKnife;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.R;
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.view.View;
+import android.widget.RatingBar;
+import android.widget.RatingBar.OnRatingBarChangeListener;
+import android.widget.TextView;
+
+/**
+ * TODO: convert to fragment
+ *
+ */
+public final class GCVoteRatingBarUtil {
+ public interface OnRatingChangeListener {
+ public void onRatingChanged(final float stars);
+ }
+
+ private GCVoteRatingBarUtil() {
+ // utility class
+ }
+
+ public static void initializeRatingBar(final Geocache cache, final View parentView, @Nullable final OnRatingChangeListener changeListener) {
+ if (GCVote.isVotingPossible(cache)) {
+ final RatingBar ratingBar = ButterKnife.findById(parentView, R.id.gcvoteRating);
+ final TextView label = ButterKnife.findById(parentView, R.id.gcvoteLabel);
+ ratingBar.setVisibility(View.VISIBLE);
+ label.setVisibility(View.VISIBLE);
+ ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
+
+ @Override
+ public void onRatingChanged(final RatingBar ratingBar, final float stars, final boolean fromUser) {
+ // 0.5 is not a valid rating, therefore we must limit
+ final float rating = GCVote.isValidRating(stars) ? stars : 0;
+ if (rating < stars) {
+ ratingBar.setRating(rating);
+ }
+ label.setText(GCVote.getDescription(rating));
+ if (changeListener != null) {
+ changeListener.onRatingChanged(rating);
+ }
+ }
+ });
+ ratingBar.setRating(cache.getMyVote());
+ }
+ }
+
+ public static float getRating(final View parentView) {
+ final RatingBar ratingBar = ButterKnife.findById(parentView, R.id.gcvoteRating);
+ return ratingBar.getRating();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/list/AbstractList.java b/main/src/cgeo/geocaching/list/AbstractList.java
index 9b57b3a..5836e6c 100644
--- a/main/src/cgeo/geocaching/list/AbstractList.java
+++ b/main/src/cgeo/geocaching/list/AbstractList.java
@@ -8,7 +8,7 @@ public abstract class AbstractList {
public final int id;
public final String title;
- private static SparseArray<AbstractList> LISTS = new SparseArray<>();
+ private final static SparseArray<AbstractList> LISTS = new SparseArray<>();
public AbstractList(final int id, final String title) {
this.id = id;
@@ -25,7 +25,7 @@ public abstract class AbstractList {
public abstract int getNumberOfCaches();
@Nullable
- public static AbstractList getListById(int listId) {
+ public static AbstractList getListById(final int listId) {
return LISTS.get(listId);
}
diff --git a/main/src/cgeo/geocaching/list/ListNameMemento.java b/main/src/cgeo/geocaching/list/ListNameMemento.java
new file mode 100644
index 0000000..6d5d481
--- /dev/null
+++ b/main/src/cgeo/geocaching/list/ListNameMemento.java
@@ -0,0 +1,21 @@
+package cgeo.geocaching.list;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Memento to remember list name suggestions from search terms.
+ */
+public class ListNameMemento {
+ public static final ListNameMemento EMPTY = new ListNameMemento();
+ private String newListName = StringUtils.EMPTY;
+
+ public String rememberTerm(final String term) {
+ newListName = term;
+ return term;
+ }
+
+ public String getTerm() {
+ return newListName;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/list/StoredList.java b/main/src/cgeo/geocaching/list/StoredList.java
index 53632a0..0ffd58a 100644
--- a/main/src/cgeo/geocaching/list/StoredList.java
+++ b/main/src/cgeo/geocaching/list/StoredList.java
@@ -24,12 +24,12 @@ import java.util.Comparator;
import java.util.List;
public final class StoredList extends AbstractList {
- public static final int TEMPORARY_LIST_ID = 0;
- public static final StoredList TEMPORARY_LIST = new StoredList(TEMPORARY_LIST_ID, "<temporary>", 0); // Never displayed
+ private static final int TEMPORARY_LIST_ID = 0;
+ public static final StoredList TEMPORARY_LIST = new StoredList(TEMPORARY_LIST_ID, "<temporary>", 0); // Never displayed
public static final int STANDARD_LIST_ID = 1;
private final int count; // this value is only valid as long as the list is not changed by other database operations
- public StoredList(int id, String title, int count) {
+ public StoredList(final int id, final String title, final int count) {
super(id, title);
this.count = count;
}
@@ -48,7 +48,7 @@ public final class StoredList extends AbstractList {
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
@@ -69,34 +69,30 @@ public final class StoredList extends AbstractList {
res = app.getResources();
}
- public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards) {
- promptForListSelection(titleId, runAfterwards, false, -1);
- }
-
public void promptForListSelection(final int titleId, @NonNull final Action1<Integer> runAfterwards, final boolean onlyConcreteLists, final int exceptListId) {
- promptForListSelection(titleId, runAfterwards, onlyConcreteLists, exceptListId, StringUtils.EMPTY);
+ promptForListSelection(titleId, runAfterwards, onlyConcreteLists, exceptListId, ListNameMemento.EMPTY);
}
- public void promptForListSelection(final int titleId, @NonNull final Action1<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 @NonNull ListNameMemento listNameMemento) {
final List<AbstractList> lists = getMenuLists(onlyConcreteLists, exceptListId);
final List<CharSequence> listsTitle = new ArrayList<>();
- for (AbstractList list : lists) {
+ for (final AbstractList list : lists) {
listsTitle.add(list.getTitleAndCount());
}
final CharSequence[] items = new CharSequence[listsTitle.size()];
final Activity activity = activityRef.get();
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(res.getString(titleId));
builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialogInterface, int itemId) {
+ public void onClick(final DialogInterface dialogInterface, final int itemId) {
final AbstractList list = lists.get(itemId);
if (list == PseudoList.NEW_LIST) {
// create new list on the fly
- promptForListCreation(runAfterwards, newListName);
+ promptForListCreation(runAfterwards, listNameMemento.getTerm());
}
else {
runAfterwards.call(lists.get(itemId).id);
@@ -106,15 +102,12 @@ public final class StoredList extends AbstractList {
builder.create().show();
}
- public static List<AbstractList> getMenuLists(boolean onlyConcreteLists, int exceptListId) {
+ public static List<AbstractList> getMenuLists(final boolean onlyConcreteLists, final int exceptListId) {
final List<AbstractList> lists = new ArrayList<>();
lists.addAll(getSortedLists());
- if (exceptListId > StoredList.TEMPORARY_LIST_ID) {
- StoredList exceptList = DataStore.getList(exceptListId);
- if (exceptList != null) {
- lists.remove(exceptList);
- }
+ if (exceptListId == StoredList.STANDARD_LIST_ID || exceptListId >= DataStore.customListIdOffset) {
+ lists.remove(DataStore.getList(exceptListId));
}
if (!onlyConcreteLists) {
@@ -138,7 +131,7 @@ public final class StoredList extends AbstractList {
Collections.sort(lists, new Comparator<StoredList>() {
@Override
- public int compare(StoredList lhs, StoredList rhs) {
+ public int compare(final StoredList lhs, final StoredList rhs) {
// have the standard list at the top
if (lhs.id == STANDARD_LIST_ID) {
return -1;
@@ -153,7 +146,7 @@ public final class StoredList extends AbstractList {
return lists;
}
- public void promptForListCreation(@NonNull final Action1<Integer> runAfterwards, String newListName) {
+ public void promptForListCreation(@NonNull final Action1<Integer> runAfterwards, final String newListName) {
handleListNameInput(newListName, R.string.list_dialog_create_title, R.string.list_dialog_create, new Action1<String>() {
// We need to update the list cache by creating a new StoredList object here.
@@ -177,7 +170,7 @@ public final class StoredList extends AbstractList {
});
}
- private void handleListNameInput(final String defaultValue, int dialogTitle, int buttonTitle, final Action1<String> runnable) {
+ private void handleListNameInput(final String defaultValue, final int dialogTitle, final int buttonTitle, final Action1<String> runnable) {
final Activity activity = activityRef.get();
if (activity == null) {
return;
@@ -187,7 +180,7 @@ public final class StoredList extends AbstractList {
@Override
public void call(final String input) {
// remove whitespaces added by autocompletion of Android keyboard
- String listName = StringUtils.trim(input);
+ final String listName = StringUtils.trim(input);
if (StringUtils.isNotBlank(listName)) {
runnable.call(listName);
}
@@ -225,8 +218,8 @@ 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 || listId == PseudoList.HISTORY_LIST.id) {
+ public static int getConcreteList(final int listId) {
+ 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 b2cb0b2..8e4b114 100644
--- a/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
+++ b/main/src/cgeo/geocaching/loaders/AbstractSearchLoader.java
@@ -29,7 +29,6 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
FINDER,
OWNER,
MAP,
- REMOVE_FROM_HISTORY,
NEXT_PAGE;
public int getLoaderId() {
@@ -43,9 +42,9 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
private String recaptchaText = null;
private SearchResult search;
private boolean loading;
- private CountDownLatch latch = new CountDownLatch(1);
+ private final CountDownLatch latch = new CountDownLatch(1);
- public AbstractSearchLoader(Context context) {
+ public AbstractSearchLoader(final Context context) {
super(context);
}
@@ -65,7 +64,7 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
// Unless we make a new Search the Loader framework won't deliver results. It does't do equals only identity
search = new SearchResult(search);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("Error in Loader ", e);
}
loading = false;
@@ -95,13 +94,13 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
public void waitForUser() {
try {
latch.await();
- } catch (InterruptedException e) {
+ } catch (final InterruptedException ignored) {
Log.w("searchThread is not waiting for user…");
}
}
@Override
- public void setKey(String key) {
+ public void setKey(final String key) {
recaptchaKey = key;
}
@@ -125,7 +124,7 @@ public abstract class AbstractSearchLoader extends AsyncTaskLoader<SearchResult>
}
@Override
- public void setText(String text) {
+ public void setText(final String text) {
recaptchaText = text;
latch.countDown();
}
diff --git a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
deleted file mode 100644
index e1573c9..0000000
--- a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package cgeo.geocaching.loaders;
-
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.connector.gc.GCParser;
-import cgeo.geocaching.settings.Settings;
-
-import android.content.Context;
-
-public class AddressGeocacheListLoader extends AbstractSearchLoader {
-
- private final String address;
-
- public AddressGeocacheListLoader(Context context, String address) {
- super(context);
- this.address = address;
- }
-
- @Override
- public SearchResult runSearch() {
- return GCParser.searchByAddress(address, Settings.getCacheType(), Settings.isShowCaptcha(), this);
- }
-
-}
diff --git a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
index c2d92bf..2549b7b 100644
--- a/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/CoordsGeocacheListLoader.java
@@ -3,9 +3,10 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.capability.ISearchByCenter;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import org.eclipse.jdt.annotation.NonNull;
+
import rx.functions.Func1;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
index fdb35f2..53e5de1 100644
--- a/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/HistoryGeocacheListLoader.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.settings.Settings;
import android.content.Context;
@@ -11,7 +11,7 @@ import android.content.Context;
public class HistoryGeocacheListLoader extends AbstractSearchLoader {
private final Geopoint coords;
- public HistoryGeocacheListLoader(Context context, Geopoint coords) {
+ public HistoryGeocacheListLoader(final Context context, final Geopoint coords) {
super(context);
this.coords = coords;
}
diff --git a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
index 45b264f..4c3baf5 100644
--- a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java
@@ -13,7 +13,7 @@ public class KeywordGeocacheListLoader extends AbstractSearchLoader {
private final @NonNull String keyword;
- public KeywordGeocacheListLoader(Context context, final @NonNull String keyword) {
+ public KeywordGeocacheListLoader(final Context context, final @NonNull String keyword) {
super(context);
this.keyword = keyword;
}
diff --git a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
index 05eac18..cd81619 100644
--- a/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/NextPageGeocacheListLoader.java
@@ -9,7 +9,7 @@ import android.content.Context;
public class NextPageGeocacheListLoader extends AbstractSearchLoader {
private final SearchResult search;
- public NextPageGeocacheListLoader(Context context, SearchResult search) {
+ public NextPageGeocacheListLoader(final Context context, final SearchResult search) {
super(context);
this.search = search;
}
diff --git a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
index 0d5af6a..b9fbc76 100644
--- a/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/OfflineGeocacheListLoader.java
@@ -3,7 +3,7 @@ package cgeo.geocaching.loaders;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Intents;
import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.settings.Settings;
import android.content.Context;
@@ -26,7 +26,6 @@ public class OfflineGeocacheListLoader extends AbstractSearchLoader {
}
/**
- * @param listId
* @return the bundle needed for querying the LoaderManager for the offline list with the given id
*/
public static Bundle getBundleForList(final int listId) {
diff --git a/main/src/cgeo/geocaching/loaders/PocketGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/PocketGeocacheListLoader.java
index 32fb020..47472be 100644
--- a/main/src/cgeo/geocaching/loaders/PocketGeocacheListLoader.java
+++ b/main/src/cgeo/geocaching/loaders/PocketGeocacheListLoader.java
@@ -9,7 +9,7 @@ import android.content.Context;
public class PocketGeocacheListLoader extends AbstractSearchLoader {
private final String guid;
- public PocketGeocacheListLoader(Context context, String guid) {
+ public PocketGeocacheListLoader(final Context context, final String guid) {
super(context);
this.guid = guid;
}
diff --git a/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java b/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java
deleted file mode 100644
index dc1a5df..0000000
--- a/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package cgeo.geocaching.loaders;
-
-import cgeo.geocaching.DataStore;
-import cgeo.geocaching.SearchResult;
-import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.settings.Settings;
-
-import android.content.Context;
-
-public class RemoveFromHistoryLoader extends AbstractSearchLoader {
-
- private final String[] selected;
- private final Geopoint coords;
-
- public RemoveFromHistoryLoader(Context context, String[] selected, Geopoint coords) {
- super(context);
- this.selected = selected.clone();
- this.coords = coords;
- }
-
- @Override
- public SearchResult runSearch() {
- DataStore.clearVisitDate(selected);
- return DataStore.getHistoryOfCaches(true, coords != null ? Settings.getCacheType() : CacheType.ALL);
- }
-
-}
diff --git a/main/src/cgeo/geocaching/location/AndroidGeocoder.java b/main/src/cgeo/geocaching/location/AndroidGeocoder.java
new file mode 100644
index 0000000..d0d07e8
--- /dev/null
+++ b/main/src/cgeo/geocaching/location/AndroidGeocoder.java
@@ -0,0 +1,82 @@
+package cgeo.geocaching.location;
+
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import rx.Observable;
+import rx.functions.Func0;
+
+import android.content.Context;
+import android.location.Address;
+import android.location.Geocoder;
+
+import java.util.List;
+import java.util.Locale;
+
+public class AndroidGeocoder {
+ private final Geocoder geocoder;
+
+ public AndroidGeocoder(final Context context) {
+ geocoder = new Geocoder(context, Locale.getDefault());
+ }
+
+ /**
+ * Retrieve addresses from a textual location using Android geocoding API. The work happens on the network
+ * scheduler.
+ *
+ * @param keyword
+ * the location
+ * @return an observable containing zero or more locations
+ *
+ * @see Geocoder#getFromLocationName(String, int)
+ */
+ public Observable<Address> getFromLocationName(@NonNull final String keyword) {
+ if (!Geocoder.isPresent()) {
+ return Observable.error(new RuntimeException("no Android geocoder"));
+ }
+ return Observable.defer(new Func0<Observable<Address>>() {
+ @Override
+ public Observable<Address> call() {
+ try {
+ return addressesToObservable(geocoder.getFromLocationName(keyword, 20));
+ } catch (final Exception e) {
+ Log.i("Unable to use Android reverse geocoder: " + e.getMessage());
+ return Observable.error(e);
+ }
+ }
+ }).subscribeOn(RxUtils.networkScheduler);
+ }
+
+ /**
+ * Retrieve the physical address for coordinates. The work happens on the network scheduler.
+ *
+ * @param coords the coordinates
+ * @return an observable containing one location or an error
+ */
+ public Observable<Address> getFromLocation(@NonNull final Geopoint coords) {
+ if (!Geocoder.isPresent()) {
+ return Observable.error(new RuntimeException("no Android reverse geocoder"));
+ }
+ return Observable.defer(new Func0<Observable<Address>>() {
+ @Override
+ public Observable<Address> call() {
+ try {
+ return addressesToObservable(geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 1));
+ } catch (final Exception e) {
+ Log.i("Unable to use Android reverse geocoder: " + e.getMessage());
+ return Observable.error(e);
+ }
+ }
+ }).subscribeOn(RxUtils.networkScheduler).first();
+ }
+
+ private static Observable<Address> addressesToObservable(final List<Address> addresses) {
+ return CollectionUtils.isEmpty(addresses) ?
+ Observable.<Address>error(new RuntimeException("no result from Android geocoder")) :
+ Observable.from(addresses);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/geopoint/DistanceParser.java b/main/src/cgeo/geocaching/location/DistanceParser.java
index e3a7482..7cbc19f 100644
--- a/main/src/cgeo/geocaching/geopoint/DistanceParser.java
+++ b/main/src/cgeo/geocaching/location/DistanceParser.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
import cgeo.geocaching.utils.MatcherWrapper;
@@ -22,7 +22,7 @@ public final class DistanceParser {
* @throws NumberFormatException
* if the given number is invalid
*/
- public static float parseDistance(String distanceText, final boolean metricUnit)
+ public static float parseDistance(final String distanceText, final boolean metricUnit)
throws NumberFormatException {
final MatcherWrapper matcher = new MatcherWrapper(pattern, distanceText);
diff --git a/main/src/cgeo/geocaching/location/GCGeocoder.java b/main/src/cgeo/geocaching/location/GCGeocoder.java
new file mode 100644
index 0000000..549044f
--- /dev/null
+++ b/main/src/cgeo/geocaching/location/GCGeocoder.java
@@ -0,0 +1,65 @@
+package cgeo.geocaching.location;
+
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import rx.Observable;
+import rx.functions.Func0;
+
+import android.location.Address;
+
+import java.util.Locale;
+
+public class GCGeocoder {
+
+ private GCGeocoder() {
+ // Do not instantiate
+ }
+
+ /**
+ * Retrieve addresses from a textual location using geocaching.com geocoding API. The work happens on the network
+ * scheduler.
+ *
+ * @param address
+ * the location
+ * @return an observable containing zero or more locations
+ *
+ * @see android.location.Geocoder#getFromLocationName(String, int)
+ */
+ public static Observable<Address> getFromLocationName(@NonNull final String address) {
+ return Observable.defer(new Func0<Observable<Address>>() {
+ @Override
+ public Observable<Address> call() {
+ if (!Settings.isGCConnectorActive()) {
+ return Observable.error(new RuntimeException("geocaching.com connector is not active"));
+ }
+ final ObjectNode response = Network.requestJSON("https://www.geocaching.com/api/geocode", new Parameters("q", address));
+ if (response == null || !StringUtils.equalsIgnoreCase(response.path("status").asText(), "success")) {
+ return Observable.error(new RuntimeException("unable to use geocaching.com geocoder"));
+ }
+
+ final JsonNode data = response.path("data");
+ final Address geocodedAddress = new Address(Locale.getDefault());
+ try {
+ geocodedAddress.setLatitude(data.get("lat").asDouble());
+ geocodedAddress.setLongitude(data.get("lng").asDouble());
+ geocodedAddress.setAddressLine(0, address);
+ return Observable.just(geocodedAddress);
+ } catch (final Exception e) {
+ Log.e("unable to decode answer from geocaching.com geocoder", e);
+ return Observable.error(e);
+ }
+ }
+ }).subscribeOn(RxUtils.networkScheduler);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/geopoint/Geopoint.java b/main/src/cgeo/geocaching/location/Geopoint.java
index bb34114..a746a1e 100644
--- a/main/src/cgeo/geocaching/geopoint/Geopoint.java
+++ b/main/src/cgeo/geocaching/location/Geopoint.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
import cgeo.geocaching.ICoordinates;
import cgeo.geocaching.R;
@@ -53,7 +53,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
* if the string cannot be parsed
* @see GeopointParser#parse(String)
*/
- public Geopoint(final String text) {
+ public Geopoint(@NonNull final String text) {
final Geopoint parsed = GeopointParser.parse(text);
latitude = parsed.latitude;
longitude = parsed.longitude;
@@ -97,12 +97,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Create new Geopoint from individual textual components.
*
- * @param latDir
- * @param latDeg
- * @param latDegFrac
- * @param lonDir
- * @param lonDeg
- * @param lonDegFrac
*/
public Geopoint(final String latDir, final String latDeg, final String latDegFrac,
final String lonDir, final String lonDeg, final String lonDegFrac) {
@@ -113,14 +107,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Create new Geopoint from individual textual components.
*
- * @param latDir
- * @param latDeg
- * @param latMin
- * @param latMinFrac
- * @param lonDir
- * @param lonDeg
- * @param lonMin
- * @param lonMinFrac
*/
public Geopoint(final String latDir, final String latDeg, final String latMin, final String latMinFrac,
final String lonDir, final String lonDeg, final String lonMin, final String lonMinFrac) {
@@ -131,16 +117,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Create new Geopoint from individual textual components.
*
- * @param latDir
- * @param latDeg
- * @param latMin
- * @param latSec
- * @param latSecFrac
- * @param lonDir
- * @param lonDeg
- * @param lonMin
- * @param lonSec
- * @param lonSecFrac
*/
public Geopoint(final String latDir, final String latDeg, final String latMin, final String latSec, final String latSecFrac,
final String lonDir, final String lonDeg, final String lonMin, final String lonSec, final String lonSecFrac) {
@@ -202,8 +178,8 @@ public final class Geopoint implements ICoordinates, Parcelable {
* @return An array of floats: the distance in meters, then the bearing in degrees
*/
private float[] pathTo(final Geopoint target) {
- float[] results = new float[2];
- android.location.Location.distanceBetween(latitude, longitude, target.latitude, target.longitude, results);
+ final float[] results = new float[2];
+ Location.distanceBetween(latitude, longitude, target.latitude, target.longitude, results);
return results;
}
@@ -283,7 +259,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
* @see GeopointFormatter
* @return formatted coordinates
*/
- public String format(GeopointFormatter.Format format) {
+ public String format(final GeopointFormatter.Format format) {
return GeopointFormatter.format(format, this);
}
@@ -301,7 +277,7 @@ public final class Geopoint implements ICoordinates, Parcelable {
abstract public static class GeopointException extends NumberFormatException {
private static final long serialVersionUID = 1L;
- protected GeopointException(String msg) {
+ protected GeopointException(final String msg) {
super(msg);
}
}
@@ -347,7 +323,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get latitude character (N or S).
*
- * @return
*/
public char getLatDir() {
return latitude >= 0 ? 'N' : 'S';
@@ -356,7 +331,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get longitude character (E or W).
*
- * @return
*/
public char getLonDir() {
return longitude >= 0 ? 'E' : 'W';
@@ -365,7 +339,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral non-negative latitude degrees.
*
- * @return
*/
public int getLatDeg() {
return getDeg(latitude);
@@ -374,7 +347,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral non-negative longitude degrees.
*
- * @return
*/
public int getLonDeg() {
return getDeg(longitude);
@@ -387,7 +359,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the latitude degrees scaled up by 10^5.
*
- * @return
*/
public int getLatDegFrac() {
return getDegFrac(latitude);
@@ -396,7 +367,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the longitude degrees scaled up by 10^5.
*
- * @return
*/
public int getLonDegFrac() {
return getDegFrac(longitude);
@@ -409,7 +379,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral latitude minutes.
*
- * @return
*/
public int getLatMin() {
return getMin(latitude);
@@ -418,7 +387,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral longitude minutes.
*
- * @return
*/
public int getLonMin() {
return getMin(longitude);
@@ -431,7 +399,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the latitude minutes scaled up by 1000.
*
- * @return
*/
public int getLatMinFrac() {
return getMinFrac(latitude);
@@ -440,7 +407,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the longitude minutes scaled up by 1000.
*
- * @return
*/
public int getLonMinFrac() {
return getMinFrac(longitude);
@@ -453,7 +419,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the latitude minutes.
*
- * @return
*/
public double getLatMinRaw() {
return getMinRaw(latitude);
@@ -462,7 +427,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the longitude minutes.
*
- * @return
*/
public double getLonMinRaw() {
return getMinRaw(longitude);
@@ -475,7 +439,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral part of the latitude seconds.
*
- * @return
*/
public int getLatSec() {
return getSec(latitude);
@@ -484,7 +447,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the integral part of the longitude seconds.
*
- * @return
*/
public int getLonSec() {
return getSec(longitude);
@@ -497,7 +459,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the latitude seconds scaled up by 1000.
*
- * @return
*/
public int getLatSecFrac() {
@@ -507,7 +468,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the fractional part of the longitude seconds scaled up by 1000.
*
- * @return
*/
public int getLonSecFrac() {
@@ -521,7 +481,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the latitude seconds.
*
- * @return
*/
public double getLatSecRaw() {
return getSecRaw(latitude);
@@ -530,7 +489,6 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Get the longitude seconds.
*
- * @return
*/
public double getLonSecRaw() {
return getSecRaw(longitude);
@@ -555,19 +513,19 @@ public final class Geopoint implements ICoordinates, Parcelable {
/**
* Gets distance in meters (workaround for 4.2.1 JIT bug).
*/
- public static double getDistance(double lat1, double lon1, double lat2, double lon2) {
+ public static double getDistance(final double lat1, final double lon1, final double lat2, final double lon2) {
// for haversine use R = 6372.8 km instead of 6371 km
- double earthRadius = 6372.8;
- double dLat = toRadians(lat2 - lat1);
- double dLon = toRadians(lon2 - lon1);
- double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+ final double earthRadius = 6372.8;
+ final double dLat = toRadians(lat2 - lat1);
+ final double dLon = toRadians(lon2 - lon1);
+ final double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
// simplify haversine
return (2 * earthRadius * 1000 * Math.asin(Math.sqrt(a)));
}
- private static double toRadians(double angdeg) {
+ private static double toRadians(final double angdeg) {
return angdeg * DEG_TO_RAD;
}
diff --git a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java b/main/src/cgeo/geocaching/location/GeopointFormatter.java
index a6965f9..599b6c7 100644
--- a/main/src/cgeo/geocaching/geopoint/GeopointFormatter.java
+++ b/main/src/cgeo/geocaching/location/GeopointFormatter.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
import java.util.Locale;
diff --git a/main/src/cgeo/geocaching/geopoint/GeopointParser.java b/main/src/cgeo/geocaching/location/GeopointParser.java
index b486f01..273c5b8 100644
--- a/main/src/cgeo/geocaching/geopoint/GeopointParser.java
+++ b/main/src/cgeo/geocaching/location/GeopointParser.java
@@ -1,9 +1,9 @@
-package cgeo.geocaching.geopoint;
-
+package cgeo.geocaching.location;
import cgeo.geocaching.utils.MatcherWrapper;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import java.util.regex.Pattern;
@@ -17,16 +17,16 @@ class GeopointParser {
final int matcherPos;
final int matcherLength;
- public ResultWrapper(final double result, int matcherPos, int stringLength) {
+ public ResultWrapper(final double result, final int matcherPos, final int stringLength) {
this.result = result;
this.matcherPos = matcherPos;
this.matcherLength = stringLength;
}
}
- // ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 )
- private static final Pattern PATTERN_LAT = Pattern.compile("\\b([NS]|)\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_LON = Pattern.compile("\\b([WE]|)\\s*(\\d+)°?(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE);
+ // ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 )
+ private static final Pattern PATTERN_LAT = Pattern.compile("\\b([NS]|)\\s*(\\d+°?|°)(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE);
+ private static final Pattern PATTERN_LON = Pattern.compile("\\b([WE]|)\\s*(\\d+°?|°)(?:\\s*(\\d+)(?:[.,](\\d+)|'?\\s*(\\d+(?:[.,]\\d+)?)(?:''|\")?)?)?", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_BAD_BLANK = Pattern.compile("(\\d)[,.] (\\d{2,})");
@@ -55,7 +55,7 @@ class GeopointParser {
* @throws Geopoint.ParseException
* if lat or lon could not be parsed
*/
- public static Geopoint parse(final String text) {
+ public static Geopoint parse(@NonNull final String text) {
final ResultWrapper latitudeWrapper = parseHelper(text, LatLon.LAT);
// cut away the latitude part when parsing the longitude
final ResultWrapper longitudeWrapper = parseHelper(text.substring(latitudeWrapper.matcherPos + latitudeWrapper.matcherLength), LatLon.LON);
@@ -78,55 +78,58 @@ class GeopointParser {
/**
* Helper for coordinates-parsing
*
- * @param text
- * @param latlon
- * @return
+ * @param text the text to parse
+ * @param latlon the kind of coordinate to parse
+ * @return a wrapper with the result and the corresponding matching part
+ * @throws Geopoint.ParseException if the text cannot be parsed
*/
- private static ResultWrapper parseHelper(final String text, final LatLon latlon) {
-
+ private static ResultWrapper parseHelper(@NonNull final String text, final LatLon latlon) {
MatcherWrapper matcher = new MatcherWrapper(PATTERN_BAD_BLANK, text);
- String replaceSpaceAfterComma = matcher.replaceAll("$1.$2");
+ final String replaceSpaceAfterComma = matcher.replaceAll("$1.$2");
final Pattern pattern = LatLon.LAT == latlon ? PATTERN_LAT : PATTERN_LON;
matcher = new MatcherWrapper(pattern, replaceSpaceAfterComma);
try {
return new ResultWrapper(Double.valueOf(replaceSpaceAfterComma), 0, text.length());
- } catch (NumberFormatException e1) {
+ } catch (final NumberFormatException ignored) {
// fall through to advanced parsing
}
- if (matcher.find()) {
- final double sign = matcher.group(1).equalsIgnoreCase("S") || matcher.group(1).equalsIgnoreCase("W") ? -1.0 : 1.0;
- final double degree = Integer.valueOf(matcher.group(2)).doubleValue();
+ try {
+ if (matcher.find()) {
+ final double sign = matcher.group(1).equalsIgnoreCase("S") || matcher.group(1).equalsIgnoreCase("W") ? -1.0 : 1.0;
+ final double degree = Integer.valueOf(StringUtils.defaultIfEmpty(StringUtils.stripEnd(matcher.group(2), "°"), "0")).doubleValue();
- double minutes = 0.0;
- double seconds = 0.0;
+ double minutes = 0.0;
+ double seconds = 0.0;
- if (null != matcher.group(3)) {
- minutes = Integer.valueOf(matcher.group(3)).doubleValue();
+ if (null != matcher.group(3)) {
+ minutes = Integer.valueOf(matcher.group(3)).doubleValue();
- if (null != matcher.group(4)) {
- seconds = Double.parseDouble("0." + matcher.group(4)) * 60.0;
- } else if (null != matcher.group(5)) {
- seconds = Double.parseDouble(matcher.group(5).replace(",", "."));
+ if (null != matcher.group(4)) {
+ seconds = Double.parseDouble("0." + matcher.group(4)) * 60.0;
+ } else if (null != matcher.group(5)) {
+ seconds = Double.parseDouble(matcher.group(5).replace(",", "."));
+ }
}
- }
-
- return new ResultWrapper(sign * (degree + minutes / 60.0 + seconds / 3600.0), matcher.start(), matcher.group().length());
+ return new ResultWrapper(sign * (degree + minutes / 60.0 + seconds / 3600.0), matcher.start(), matcher.group().length());
+ }
+ } catch (final NumberFormatException ignored) {
+ // We might have encountered too large a number. This was not the right way to do it, try another.
}
// Nothing found with "N 52...", try to match string as decimal degree parts (i.e. multiple doubles)
try {
- final String[] items = StringUtils.split(text.trim());
+ final String[] items = StringUtils.split(StringUtils.trimToEmpty(text));
if (items.length > 0 && items.length <= 2) {
final int index = (latlon == LatLon.LON ? items.length - 1 : 0);
final String textPart = items[index];
final int pos = (latlon == LatLon.LON ? text.lastIndexOf(textPart) : text.indexOf(textPart));
return new ResultWrapper(Double.parseDouble(textPart), pos, textPart.length());
}
- } catch (NumberFormatException e) {
+ } catch (final NumberFormatException ignored) {
// The right exception will be raised below.
}
diff --git a/main/src/cgeo/geocaching/geopoint/IConversion.java b/main/src/cgeo/geocaching/location/IConversion.java
index b1cbffd..f7f0e36 100644
--- a/main/src/cgeo/geocaching/geopoint/IConversion.java
+++ b/main/src/cgeo/geocaching/location/IConversion.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
public interface IConversion {
public static final float MILES_TO_KILOMETER = 1.609344f;
diff --git a/main/src/cgeo/geocaching/location/MapQuestGeocoder.java b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java
new file mode 100644
index 0000000..ae82546
--- /dev/null
+++ b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java
@@ -0,0 +1,135 @@
+package cgeo.geocaching.location;
+
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Subscriber;
+import rx.functions.Func0;
+
+import android.location.Address;
+
+import java.util.Locale;
+
+public class MapQuestGeocoder {
+
+ private static final String MAPQUEST_KEY = "Fmjtd|luurn1u2n9,bs=o5-9wynua";
+
+ private MapQuestGeocoder() {
+ // Do not instantiate
+ }
+
+ /**
+ * Retrieve addresses from a textual location using MapQuest geocoding API. The work happens on the network
+ * scheduler.
+ *
+ * @param address
+ * the location
+ * @return an observable containing zero or more locations
+ *
+ * @see android.location.Geocoder#getFromLocationName(String, int)
+ */
+ public static Observable<Address> getFromLocationName(@NonNull final String address) {
+ return get("address", new Parameters("location", address, "maxResults", "20", "thumbMaps", "false"));
+ }
+
+ /**
+ * Retrieve the physical address for coordinates. The work happens on the network scheduler.
+ *
+ * @param coords the coordinates
+ * @return an observable containing one location or an error
+ */
+ public static Observable<Address> getFromLocation(@NonNull final Geopoint coords) {
+ return get("reverse", new Parameters("location", String.format(Locale.US, "%f,%f", coords.getLatitude(), coords.getLongitude()))).first();
+ }
+
+ private static Observable<Address> get(@NonNull final String method, @NonNull final Parameters parameters) {
+ return Observable.defer(new Func0<Observable<Address>>() {
+ @Override
+ public Observable<Address> call() {
+ final ObjectNode response = Network.requestJSON("https://open.mapquestapi.com/geocoding/v1/" + method,
+ parameters.put("key", MAPQUEST_KEY));
+ if (response == null) {
+ Log.w("MapQuest decoder error: no response");
+ return Observable.error(new RuntimeException("no answer from MapQuest geocoder"));
+ }
+ final int statusCode = response.path("info").path("statuscode").asInt(-1);
+ if (statusCode != 0) {
+ Log.w("MapQuest decoder error: statuscode is not 0");
+ return Observable.error(new RuntimeException("no correct answer from MapQuest geocoder"));
+ }
+ return Observable.create(new OnSubscribe<Address>() {
+ @Override
+ public void call(final Subscriber<? super Address> subscriber) {
+ try {
+ for (final JsonNode address: response.get("results").get(0).get("locations")) {
+ subscriber.onNext(mapquestToAddress(address));
+ }
+ subscriber.onCompleted();
+ } catch (final Exception e) {
+ Log.e("Error decoding MapQuest address", e);
+ subscriber.onError(e);
+ }
+ }
+ });
+ }
+ }).subscribeOn(RxUtils.networkScheduler);
+ }
+
+ private static Address mapquestToAddress(final JsonNode mapquestAddress) {
+ final Address address = new Address(Locale.getDefault());
+ for (int i = 1; i <= 6; i++) {
+ final String adminAreaName = "adminArea" + i;
+ setComponent(address, mapquestAddress, adminAreaName, mapquestAddress.path(adminAreaName + "Type").asText());
+ }
+ setComponent(address, mapquestAddress, "postalCode", "PostalCode");
+ int index = 0;
+ for (final String addressComponent: new String[]{ mapquestAddress.path("street").asText(), address.getSubLocality(), address.getLocality(),
+ address.getPostalCode(), address.getSubAdminArea(), address.getAdminArea(), address.getCountryCode() }) {
+ if (StringUtils.isNotBlank(addressComponent)) {
+ address.setAddressLine(index++, addressComponent);
+ }
+ }
+ address.setLatitude(mapquestAddress.get("latLng").get("lat").asDouble());
+ address.setLongitude(mapquestAddress.get("latLng").get("lng").asDouble());
+ return address;
+ }
+
+ private static void setComponent(final Address address, final JsonNode mapquestAddress, final String adminArea, final String adminAreaType) {
+ final String content = StringUtils.trimToNull(mapquestAddress.path(adminArea).asText());
+ switch (adminAreaType) {
+ case "City":
+ address.setLocality(content);
+ break;
+ case "Neighborhood":
+ address.setSubLocality(content);
+ break;
+ case "PostalCode":
+ address.setPostalCode(content);
+ break;
+ case "State":
+ address.setAdminArea(content);
+ break;
+ case "County":
+ address.setSubAdminArea(content);
+ break;
+ case "Country":
+ address.setCountryCode(content);
+ address.setCountryName(new Locale("", content).getDisplayCountry());
+ break;
+ // Make checkers happy
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/geopoint/Units.java b/main/src/cgeo/geocaching/location/Units.java
index 018216d..842bd83 100644
--- a/main/src/cgeo/geocaching/geopoint/Units.java
+++ b/main/src/cgeo/geocaching/location/Units.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
import cgeo.geocaching.settings.Settings;
@@ -10,8 +10,8 @@ public class Units {
public static ImmutablePair<Double, String> scaleDistance(final double distanceKilometers) {
double distance;
- String units;
- if (Settings.isUseImperialUnits()) {
+ final String units;
+ if (Settings.useImperialUnits()) {
distance = distanceKilometers / IConversion.MILES_TO_KILOMETER;
if (distance >= 0.1) {
units = "mi";
@@ -37,24 +37,24 @@ public class Units {
}
final ImmutablePair<Double, String> scaled = scaleDistance(distanceKilometers);
- String formatString;
+ final String formatString;
if (scaled.left >= 100) {
- formatString = "%.0f";
+ formatString = "%.0f %s";
} else if (scaled.left >= 10) {
- formatString = "%.1f";
+ formatString = "%.1f %s";
} else {
- formatString = "%.2f";
+ formatString = "%.2f %s";
}
- return String.format(formatString + " %s", scaled.left, scaled.right);
+ return String.format(formatString, scaled.left, scaled.right);
}
- public static String getDistanceFromMeters(float meters) {
+ public static String getDistanceFromMeters(final float meters) {
return getDistanceFromKilometers(meters / 1000f);
}
public static String getSpeed(final float kilometersPerHour) {
- if (Settings.isUseImperialUnits()) {
+ if (Settings.useImperialUnits()) {
return String.format(Locale.US, "%.0f mph", kilometersPerHour / IConversion.MILES_TO_KILOMETER);
}
return String.format(Locale.US, "%.0f km/h", kilometersPerHour);
diff --git a/main/src/cgeo/geocaching/geopoint/Viewport.java b/main/src/cgeo/geocaching/location/Viewport.java
index ba0e040..b885336 100644
--- a/main/src/cgeo/geocaching/geopoint/Viewport.java
+++ b/main/src/cgeo/geocaching/location/Viewport.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.geopoint;
+package cgeo.geocaching.location;
import cgeo.geocaching.ICoordinates;
@@ -79,6 +79,22 @@ public final class Viewport {
&& coords.getLatitudeE6() <= topRight.getLatitudeE6();
}
+ /**
+ * Count the number of points present in the viewport.
+ *
+ * @param points a collection of (possibly null) points
+ * @return the number of non-null points in the viewport
+ */
+ public int count(final @NonNull Collection<? extends ICoordinates> points) {
+ int total = 0;
+ for (final ICoordinates point: points) {
+ if (point != null && contains(point)) {
+ total += 1;
+ }
+ }
+ return total;
+ }
+
@Override
public String toString() {
return "(" + bottomLeft.toString() + "," + topRight.toString() + ")";
@@ -86,7 +102,7 @@ public final class Viewport {
/**
* Check whether another viewport is fully included into the current one.
- *
+ *
* @param vp
* the other viewport
* @return true if the viewport is fully included into this one, false otherwise
@@ -102,6 +118,7 @@ public final class Viewport {
* the database table to use as prefix, or null if no prefix is required
* @return the string without the "where" keyword
*/
+ @NonNull
public StringBuilder sqlWhere(@Nullable final String dbTable) {
final String prefix = dbTable == null ? "" : (dbTable + ".");
return new StringBuilder(prefix).append("latitude >= ").append(getLatitudeMin()).append(" and ")
diff --git a/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java b/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java
index 747618b..9436b2a 100644
--- a/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java
+++ b/main/src/cgeo/geocaching/maps/AbstractItemizedOverlay.java
@@ -17,9 +17,9 @@ import android.graphics.drawable.Drawable;
*/
public abstract class AbstractItemizedOverlay implements GeneralOverlay {
- private ItemizedOverlayImpl ovlImpl;
+ private final ItemizedOverlayImpl ovlImpl;
- protected AbstractItemizedOverlay(ItemizedOverlayImpl ovlImplIn) {
+ protected AbstractItemizedOverlay(final ItemizedOverlayImpl ovlImplIn) {
ovlImpl = ovlImplIn;
}
@@ -27,26 +27,26 @@ public abstract class AbstractItemizedOverlay implements GeneralOverlay {
ovlImpl.superPopulate();
}
- public boolean onTap(int index) {
+ public boolean onTap(final int index) {
return ovlImpl.superOnTap(index);
}
- Drawable boundCenterBottom(Drawable markerIn) {
+ Drawable boundCenterBottom(final Drawable markerIn) {
return ovlImpl.superBoundCenterBottom(markerIn);
}
- void setLastFocusedItemIndex(int index) {
+ void setLastFocusedItemIndex(final int index) {
ovlImpl.superSetLastFocusedItemIndex(index);
}
@Override
- public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ public void draw(final Canvas canvas, final MapViewImpl mapView, final boolean shadow) {
ovlImpl.superDraw(canvas, mapView, shadow);
}
@Override
- public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
+ public void drawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final MapProjectionImpl projection, final byte drawZoomLevel) {
ovlImpl.superDrawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
}
diff --git a/main/src/cgeo/geocaching/maps/AbstractMap.java b/main/src/cgeo/geocaching/maps/AbstractMap.java
index 2eceadb..f62fb3a 100644
--- a/main/src/cgeo/geocaching/maps/AbstractMap.java
+++ b/main/src/cgeo/geocaching/maps/AbstractMap.java
@@ -19,7 +19,7 @@ public abstract class AbstractMap {
MapActivityImpl mapActivity;
- protected AbstractMap(MapActivityImpl activity) {
+ protected AbstractMap(final MapActivityImpl activity) {
mapActivity = activity;
}
@@ -31,10 +31,10 @@ public abstract class AbstractMap {
return mapActivity.getActivity();
}
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(final Bundle savedInstanceState) {
mapActivity.superOnCreate(savedInstanceState);
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mapActivity.getActivity().requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
}
}
@@ -55,17 +55,17 @@ public abstract class AbstractMap {
mapActivity.superOnDestroy();
}
- public boolean onCreateOptionsMenu(Menu menu) {
+ public boolean onCreateOptionsMenu(final Menu menu) {
final boolean result = mapActivity.superOnCreateOptionsMenu(menu);
mapActivity.getActivity().getMenuInflater().inflate(R.menu.map_activity, menu);
return result;
}
- public boolean onPrepareOptionsMenu(Menu menu) {
+ public boolean onPrepareOptionsMenu(final Menu menu) {
return mapActivity.superOnPrepareOptionsMenu(menu);
}
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(final MenuItem item) {
return mapActivity.superOnOptionsItemSelected(item);
}
diff --git a/main/src/cgeo/geocaching/maps/AbstractMapProvider.java b/main/src/cgeo/geocaching/maps/AbstractMapProvider.java
index 620b953..bd42223 100644
--- a/main/src/cgeo/geocaching/maps/AbstractMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/AbstractMapProvider.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.maps.interfaces.MapSource;
public abstract class AbstractMapProvider implements MapProvider {
@Override
- public void registerMapSource(MapSource mapSource) {
+ public void registerMapSource(final MapSource mapSource) {
MapProviderFactory.registerMapSource(mapSource);
}
}
diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java
index 9bbf7af..42e41b1 100644
--- a/main/src/cgeo/geocaching/maps/CGeoMap.java
+++ b/main/src/cgeo/geocaching/maps/CGeoMap.java
@@ -4,8 +4,10 @@ import butterknife.ButterKnife;
import cgeo.geocaching.CacheListActivity;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.CompassActivity;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Waypoint;
@@ -15,13 +17,12 @@ import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag;
import cgeo.geocaching.enumerations.WaypointType;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Viewport;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapActivityImpl;
@@ -31,13 +32,15 @@ import cgeo.geocaching.maps.interfaces.MapProvider;
import cgeo.geocaching.maps.interfaces.MapSource;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
-import cgeo.geocaching.sensors.DirectionProvider;
+import cgeo.geocaching.network.AndroidBeam;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.ui.dialog.LiveMapInfoDialogBuilder;
import cgeo.geocaching.utils.AngleUtils;
import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.LeastRecentlyUsedSet;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.MapUtils;
@@ -45,6 +48,7 @@ import cgeo.geocaching.utils.MapUtils;
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.Subscription;
import rx.functions.Action0;
@@ -61,11 +65,13 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.location.Location;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
@@ -123,16 +129,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
private static final int UPDATE_PROGRESS = 0;
private static final int FINISHED_LOADING_DETAILS = 1;
- //Menu
- private static final String EXTRAS_GEOCODE = "geocode";
- private static final String EXTRAS_COORDS = "coords";
- private static final String EXTRAS_WPTTYPE = "wpttype";
- private static final String EXTRAS_MAPSTATE = "mapstate";
- private static final String EXTRAS_SEARCH = "search";
- private static final String EXTRAS_MAP_TITLE = "mapTitle";
- private static final String EXTRAS_MAP_MODE = "mapMode";
- private static final String EXTRAS_LIVE_ENABLED = "liveEnabled";
-
private static final String BUNDLE_MAP_SOURCE = "mapSource";
private static final String BUNDLE_MAP_STATE = "mapState";
private static final String BUNDLE_LIVE_ENABLED = "liveEnabled";
@@ -141,15 +137,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// Those are initialized in onCreate() and will never be null afterwards
private Resources res;
private Activity activity;
- private CgeoApplication app;
private MapItemFactory mapItemFactory;
private String mapTitle;
- private LeastRecentlyUsedSet<Geocache> caches;
+ final private LeastRecentlyUsedSet<Geocache> caches = new LeastRecentlyUsedSet<>(MAX_CACHES + DataStore.getAllCachesCount());
private MapViewImpl mapView;
private CachesOverlay overlayCaches;
private PositionAndScaleOverlay overlayPositionAndScale;
- final private GeoDirHandler geoDirUpdate;
+ final private GeoDirHandler geoDirUpdate = new UpdateLoc(this);
private SearchResult searchIntent = null;
private String geocodeIntent = null;
private Geopoint coordsIntent = null;
@@ -161,7 +156,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
private MapTokens tokens = null;
private boolean noMapTokenShowed = false;
// map status data
- private boolean followMyLocation = false;
+ private static boolean followMyLocation = true;
// threads
private Subscription loadTimer;
private LoadDetails loadDetailsThread = null;
@@ -191,19 +186,20 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
private boolean centered = false; // if map is already centered
private boolean alreadyCentered = false; // -""- for setting my location
private static final Set<String> dirtyCaches = new HashSet<>();
+ // flag for honeycomb special popup menu handling
+ private boolean honeycombMenu = false;
/**
* if live map is enabled, this is the minimum zoom level, independent of the stored setting
*/
private static final int MIN_LIVEMAP_ZOOM = 12;
// Thread pooling
- private static BlockingQueue<Runnable> displayQueue = new ArrayBlockingQueue<>(1);
- private static ThreadPoolExecutor displayExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, displayQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
- private static BlockingQueue<Runnable> downloadQueue = new ArrayBlockingQueue<>(1);
- private static ThreadPoolExecutor downloadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, downloadQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
- private static BlockingQueue<Runnable> loadQueue = new ArrayBlockingQueue<>(1);
-
- private static ThreadPoolExecutor loadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, loadQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
+ private static final BlockingQueue<Runnable> displayQueue = new ArrayBlockingQueue<>(1);
+ private static final ThreadPoolExecutor displayExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, displayQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
+ private static final BlockingQueue<Runnable> downloadQueue = new ArrayBlockingQueue<>(1);
+ private static final ThreadPoolExecutor downloadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, downloadQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
+ private static final BlockingQueue<Runnable> loadQueue = new ArrayBlockingQueue<>(1);
+ private static final ThreadPoolExecutor loadExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, loadQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
// handlers
/** Updates the titles */
@@ -224,29 +220,9 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
switch (what) {
case UPDATE_TITLE:
- // set title
- final StringBuilder title = new StringBuilder();
-
- if (map.mapMode == MapMode.LIVE && map.isLiveEnabled) {
- title.append(map.res.getString(R.string.map_live));
- } else {
- title.append(map.mapTitle);
- }
-
- map.countVisibleCaches();
- if (!map.caches.isEmpty() && !map.mapTitle.contains("[")) {
- title.append(" [").append(map.cachesCnt);
- if (map.cachesCnt != map.caches.size()) {
- title.append('/').append(map.caches.size());
- }
- title.append(']');
- }
+ map.setTitle();
+ map.setSubtitle();
- if (Settings.isDebug() && map.lastSearchResult != null && StringUtils.isNotBlank(map.lastSearchResult.getUrl())) {
- title.append('[').append(map.lastSearchResult.getUrl()).append(']');
- }
-
- map.setTitle(title.toString());
break;
case INVALIDATE_MAP:
map.mapView.repaintRequired(null);
@@ -261,7 +237,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
final private Handler displayHandler = new DisplayHandler(this);
- private void setTitle(final String title) {
+ private void setTitle() {
+ final String title = calculateTitle();
/* Compatibility for the old Action Bar, only used by the maps activity at the moment */
final TextView titleview = ButterKnife.findById(activity, R.id.actionbar_title);
if (titleview != null) {
@@ -273,10 +250,84 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
}
+ private String calculateTitle() {
+ if (isLiveEnabled) {
+ return res.getString(R.string.map_live);
+ }
+ if (mapMode == MapMode.SINGLE) {
+ final Geocache cache = getSingleModeCache();
+ if (cache != null) {
+ return cache.getName();
+ }
+ }
+ return StringUtils.defaultIfEmpty(mapTitle, res.getString(R.string.map_map));
+ }
+
+ @Nullable
+ private Geocache getSingleModeCache() {
+ // use a copy of the caches list to avoid concurrent modification
+ for (final Geocache geocache : new ArrayList<>(caches)) {
+ if (geocache.getGeocode().equals(geocodeIntent)) {
+ return geocache;
+ }
+ }
+ return null;
+ }
+
+ private void setSubtitle() {
+ final String subtitle = calculateSubtitle();
+ if (StringUtils.isEmpty(subtitle)) {
+ return;
+ }
+
+ /* Compatibility for the old Action Bar, only used by the maps activity at the moment */
+ final TextView titleView = ButterKnife.findById(activity, R.id.actionbar_title);
+ if (titleView != null) {
+ titleView.setText(titleView.getText().toString() + ' ' + subtitle);
+ }
+ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)) {
+ setSubtitleIceCreamSandwich(subtitle);
+ }
+ }
+
+ private String calculateSubtitle() {
+ // count caches in the sub title
+ countVisibleCaches();
+ final StringBuilder subtitle = new StringBuilder();
+ if (!isLiveEnabled && mapMode == MapMode.SINGLE) {
+ final Geocache cache = getSingleModeCache();
+ if (cache != null) {
+ return Formatter.formatMapSubtitle(cache);
+ }
+ }
+ if (!caches.isEmpty()) {
+ final int totalCount = caches.size();
+
+ if (cachesCnt != totalCount && Settings.isDebug()) {
+ subtitle.append(cachesCnt).append('/').append(res.getQuantityString(R.plurals.cache_counts, totalCount, totalCount));
+ }
+ else {
+ subtitle.append(res.getQuantityString(R.plurals.cache_counts, cachesCnt, cachesCnt));
+ }
+ }
+
+ if (Settings.isDebug() && lastSearchResult != null && StringUtils.isNotBlank(lastSearchResult.getUrl())) {
+ subtitle.append(" [").append(lastSearchResult.getUrl()).append(']');
+ }
+
+ return subtitle.toString();
+ }
+
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void setTitleIceCreamSandwich(final String title) {
activity.getActionBar().setTitle(title);
}
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private void setSubtitleIceCreamSandwich(final String subtitle) {
+ activity.getActionBar().setSubtitle(subtitle);
+ }
+
/** Updates the progress. */
private static final class ShowProgressHandler extends Handler {
private int counter = 0;
@@ -331,7 +382,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
if (msg.what == UPDATE_PROGRESS) {
if (waitDialog != null) {
final int secondsElapsed = (int) ((System.currentTimeMillis() - detailProgressTime) / 1000);
- int secondsRemaining;
+ final int secondsRemaining;
if (detailProgress > 0) {
secondsRemaining = (detailTotal - detailProgress) * secondsElapsed / detailProgress;
} else {
@@ -367,25 +418,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
public CGeoMap(final MapActivityImpl activity) {
super(activity);
- geoDirUpdate = new UpdateLoc(this);
}
protected void countVisibleCaches() {
- final List<Geocache> protectedCaches = caches.getAsList();
-
- int count = 0;
- if (!protectedCaches.isEmpty()) {
- final Viewport viewport = mapView.getViewport();
-
- for (final Geocache cache : protectedCaches) {
- if (cache != null && cache.getCoords() != null) {
- if (viewport.contains(cache)) {
- count++;
- }
- }
- }
- }
- cachesCnt = count;
+ cachesCnt = mapView.getViewport().count(caches.getAsList());
}
@Override
@@ -404,10 +440,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// class init
res = this.getResources();
activity = this.getActivity();
- app = (CgeoApplication) activity.getApplication();
-
- final int countBubbleCnt = DataStore.getAllCachesCount();
- caches = new LeastRecentlyUsedSet<>(MAX_CACHES + countBubbleCnt);
final MapProvider mapProvider = Settings.getMapProvider();
mapItemFactory = mapProvider.getMapItemFactory();
@@ -415,14 +447,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// Get parameters from the intent
final Bundle extras = activity.getIntent().getExtras();
if (extras != null) {
- mapMode = (MapMode) extras.get(EXTRAS_MAP_MODE);
- isLiveEnabled = extras.getBoolean(EXTRAS_LIVE_ENABLED, false);
- searchIntent = extras.getParcelable(EXTRAS_SEARCH);
- geocodeIntent = extras.getString(EXTRAS_GEOCODE);
- coordsIntent = extras.getParcelable(EXTRAS_COORDS);
- waypointTypeIntent = WaypointType.findById(extras.getString(EXTRAS_WPTTYPE));
- mapStateIntent = extras.getIntArray(EXTRAS_MAPSTATE);
- mapTitle = extras.getString(EXTRAS_MAP_TITLE);
+ mapMode = (MapMode) extras.get(Intents.EXTRA_MAP_MODE);
+ isLiveEnabled = extras.getBoolean(Intents.EXTRA_LIVE_ENABLED, false);
+ searchIntent = extras.getParcelable(Intents.EXTRA_SEARCH);
+ geocodeIntent = extras.getString(Intents.EXTRA_GEOCODE);
+ coordsIntent = extras.getParcelable(Intents.EXTRA_COORDS);
+ waypointTypeIntent = WaypointType.findById(extras.getString(Intents.EXTRA_WPTTYPE));
+ mapStateIntent = extras.getIntArray(Intents.EXTRA_MAPSTATE);
+ mapTitle = extras.getString(Intents.EXTRA_TITLE);
}
else {
mapMode = MapMode.LIVE;
@@ -461,7 +493,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
activity.getActionBar().setDisplayHomeAsUpEnabled(true);
}
activity.setContentView(mapProvider.getMapLayoutId());
- setTitle(res.getString(R.string.map_map));
+ setTitle();
// initialize map
mapView = (MapViewImpl) activity.findViewById(mapProvider.getMapViewId());
@@ -475,18 +507,21 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
mapView.clearOverlays();
overlayCaches = mapView.createAddMapOverlay(mapView.getContext(), getResources().getDrawable(R.drawable.marker));
- overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay();
+
+
+ overlayPositionAndScale = mapView.createAddPositionAndScaleOverlay(coordsIntent, geocodeIntent);
if (trailHistory != null) {
overlayPositionAndScale.setHistory(trailHistory);
}
+
mapView.repaintRequired(null);
- setZoom(Settings.getMapZoom());
+ setZoom(Settings.getMapZoom(mapMode));
mapView.getMapController().setCenter(Settings.getMapCenter());
if (null == mapStateIntent) {
- followMyLocation = mapMode == MapMode.LIVE;
+ followMyLocation = followMyLocation && (mapMode == MapMode.LIVE);
} else {
followMyLocation = 1 == mapStateIntent[3];
if ((overlayCaches.getCircles() ? 1 : 0) != mapStateIntent[4]) {
@@ -504,9 +539,22 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
prepareFilterBar();
- if (!app.isLiveMapHintShownInThisSession() && !Settings.getHideLiveMapHint() && Settings.getLiveMapHintShowCount() <= 3) {
+ // Check for Honeycomb fake overflow button and attach popup
+ final View overflowActionBar = ButterKnife.findById(activity, R.id.overflowActionBar);
+ if (overflowActionBar != null) {
+ honeycombMenu = true;
+ overflowActionBar.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ showPopupHoneycomb(v);
+ }
+ });
+ }
+
+ if (!CgeoApplication.getInstance().isLiveMapHintShownInThisSession() && Settings.getLiveMapHintShowCount() <= 3) {
LiveMapInfoDialogBuilder.create(activity).show();
}
+ AndroidBeam.disable(activity);
}
private void initMyLocationSwitchButton(final CheckBox locSwitch) {
@@ -522,7 +570,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
/**
* Set the zoom of the map. The zoom is restricted to a certain minimum in case of live map.
*
- * @param zoom
*/
private void setZoom(final int zoom) {
mapView.getMapController().setZoom(isLiveEnabled ? Math.max(zoom, MIN_LIVEMAP_ZOOM) : zoom);
@@ -546,18 +593,28 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
resumeSubscription = Subscriptions.from(geoDirUpdate.start(GeoDirHandler.UPDATE_GEODIR), startTimer());
if (!CollectionUtils.isEmpty(dirtyCaches)) {
- for (final String geocode : dirtyCaches) {
- final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
- if (cache != null) {
- // new collection type needs to remove first
- caches.remove(cache);
- // re-add to update the freshness
- caches.add(cache);
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ public Void doInBackground(final Void... params) {
+ for (final String geocode : dirtyCaches) {
+ final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS);
+ if (cache != null) {
+ // new collection type needs to remove first
+ caches.remove(cache);
+ // re-add to update the freshness
+ caches.add(cache);
+ }
+ }
+ return null;
}
- }
- dirtyCaches.clear();
- // Update display
- displayExecutor.execute(new DisplayRunnable(this));
+
+ @Override
+ public void onPostExecute(final Void result) {
+ dirtyCaches.clear();
+ // Update display
+ displayExecutor.execute(new DisplayRunnable(CGeoMap.this));
+ }
+ }.execute();
}
}
@@ -581,10 +638,37 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ private void showPopupHoneycomb(final View view) {
+ // Inflate the core menu ourselves
+ final android.widget.PopupMenu popupMenu = new android.widget.PopupMenu(getActivity(), view);
+ final MenuInflater inflater = new MenuInflater(getActivity());
+ inflater.inflate(R.menu.map_activity, popupMenu.getMenu());
+
+ // continue processing menu items as usual
+ onCreateOptionsMenu(popupMenu.getMenu());
+
+ onPrepareOptionsMenu(popupMenu.getMenu());
+
+ popupMenu.setOnMenuItemClickListener(
+ new android.widget.PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(final MenuItem item) {
+ return onOptionsItemSelected(item);
+ }
+ }
+ );
+ // display menu
+ popupMenu.show();
+ }
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
// menu inflation happens in Google/Mapsforge specific classes
- super.onCreateOptionsMenu(menu);
+ // skip it for honeycomb - handled specially in @see showPopupHoneycomb
+ if (!honeycombMenu) {
+ super.onCreateOptionsMenu(menu);
+ }
MapProviderFactory.addMapviewMenuItems(menu);
@@ -592,7 +676,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
subMenuStrategy.setHeaderTitle(res.getString(R.string.map_strategy_title));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
/* if we have an Actionbar find the my position toggle */
final MenuItem item = menu.findItem(R.id.menu_toggle_mypos);
myLocSwitch = new CheckBox(activity);
@@ -640,7 +724,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
item = menu.findItem(R.id.menu_theme_mode); // show theme selection
item.setVisible(mapView.hasMapThemes());
- menu.findItem(R.id.menu_as_list).setVisible(!isLoading());
+ menu.findItem(R.id.menu_as_list).setVisible(!isLoading() && caches.size() > 1);
menu.findItem(R.id.submenu_strategy).setVisible(isLiveEnabled);
@@ -657,6 +741,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
default: // DETAILED
menu.findItem(R.id.menu_strategy_detailed).setChecked(true);
}
+ menu.findItem(R.id.menu_hint).setVisible(mapMode == MapMode.SINGLE);
+ menu.findItem(R.id.menu_compass).setVisible(mapMode == MapMode.SINGLE);
} catch (final RuntimeException e) {
Log.e("CGeoMap.onPrepareOptionsMenu", e);
}
@@ -685,6 +771,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
lastSearchResult = null;
searchIntent = null;
ActivityMixin.invalidateOptionsMenu(activity);
+ if (mapMode != MapMode.SINGLE) {
+ mapTitle = StringUtils.EMPTY;
+ }
+ updateMapTitle();
return true;
case R.id.menu_store_caches:
if (!isLoading()) {
@@ -714,7 +804,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
public void call(final Integer selectedListId) {
storeCaches(geocodes, selectedListId);
}
- }, true, StoredList.TEMPORARY_LIST_ID);
+ }, true, StoredList.TEMPORARY_LIST.id);
} else {
storeCaches(geocodes, StoredList.STANDARD_LIST_ID);
}
@@ -742,24 +832,30 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
case R.id.menu_strategy_fastest: {
item.setChecked(true);
- Settings.setLiveMapStrategy(Strategy.FASTEST);
+ Settings.setLiveMapStrategy(LivemapStrategy.FASTEST);
return true;
}
case R.id.menu_strategy_fast: {
item.setChecked(true);
- Settings.setLiveMapStrategy(Strategy.FAST);
+ Settings.setLiveMapStrategy(LivemapStrategy.FAST);
return true;
}
case R.id.menu_strategy_auto: {
item.setChecked(true);
- Settings.setLiveMapStrategy(Strategy.AUTO);
+ Settings.setLiveMapStrategy(LivemapStrategy.AUTO);
return true;
}
case R.id.menu_strategy_detailed: {
item.setChecked(true);
- Settings.setLiveMapStrategy(Strategy.DETAILED);
+ Settings.setLiveMapStrategy(LivemapStrategy.DETAILED);
return true;
}
+ case R.id.menu_hint:
+ menuShowHint();
+ return true;
+ case R.id.menu_compass:
+ menuCompass();
+ return true;
default:
final MapSource mapSource = MapProviderFactory.getMapSource(id);
if (mapSource != null) {
@@ -771,6 +867,20 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
return false;
}
+ private void menuCompass() {
+ final Geocache cache = getSingleModeCache();
+ if (cache != null) {
+ CompassActivity.startActivityCache(this.getActivity(), cache);
+ }
+ }
+
+ private void menuShowHint() {
+ final Geocache cache = getSingleModeCache();
+ if (cache != null) {
+ cache.showHintToast(getActivity());
+ }
+ }
+
private void selectMapTheme() {
final File[] themeFiles = Settings.getMapThemeFiles();
@@ -853,7 +963,12 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
if (restartRequired) {
mapRestart();
} else if (mapView != null) { // changeMapSource can be called by onCreate()
+ mapStateIntent = currentMapState();
mapView.setMapSource();
+ // re-center the map
+ centered = false;
+ centerMap(geocodeIntent, searchIntent, coordsIntent, mapStateIntent);
+ // re-build menues
ActivityMixin.invalidateOptionsMenu(activity);
}
@@ -864,27 +979,27 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
* Restart the current activity with the default map source.
*/
private void mapRestart() {
- // close old mapview
- activity.finish();
-
// prepare information to restart a similar view
final Intent mapIntent = new Intent(activity, Settings.getMapProvider().getMapClass());
- mapIntent.putExtra(EXTRAS_SEARCH, searchIntent);
- mapIntent.putExtra(EXTRAS_GEOCODE, geocodeIntent);
+ mapIntent.putExtra(Intents.EXTRA_SEARCH, searchIntent);
+ mapIntent.putExtra(Intents.EXTRA_GEOCODE, geocodeIntent);
if (coordsIntent != null) {
- mapIntent.putExtra(EXTRAS_COORDS, coordsIntent);
+ mapIntent.putExtra(Intents.EXTRA_COORDS, coordsIntent);
}
- mapIntent.putExtra(EXTRAS_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null);
- mapIntent.putExtra(EXTRAS_MAP_TITLE, mapTitle);
- mapIntent.putExtra(EXTRAS_MAP_MODE, mapMode);
- mapIntent.putExtra(EXTRAS_LIVE_ENABLED, isLiveEnabled);
+ mapIntent.putExtra(Intents.EXTRA_WPTTYPE, waypointTypeIntent != null ? waypointTypeIntent.id : null);
+ mapIntent.putExtra(Intents.EXTRA_TITLE, mapTitle);
+ mapIntent.putExtra(Intents.EXTRA_MAP_MODE, mapMode);
+ mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, isLiveEnabled);
final int[] mapState = currentMapState();
if (mapState != null) {
- mapIntent.putExtra(EXTRAS_MAPSTATE, mapState);
+ mapIntent.putExtra(Intents.EXTRA_MAPSTATE, mapState);
}
+ // close old map
+ activity.finish();
+
// start the new map
activity.startActivity(mapIntent);
}
@@ -909,13 +1024,13 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
private void savePrefs() {
- Settings.setMapZoom(mapView.getMapZoomLevel());
+ Settings.setMapZoom(mapMode, mapView.getMapZoomLevel());
Settings.setMapCenter(mapView.getMapViewCenter());
}
// Set center of map to my location if appropriate.
- private void myLocationInMiddle(final IGeoData geo) {
- if (followMyLocation && !geo.isPseudoLocation()) {
+ private void myLocationInMiddle(final GeoData geo) {
+ if (followMyLocation) {
centerMap(geo.getCoords());
}
}
@@ -931,8 +1046,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// minimum change of location in fraction of map width/height (whatever is smaller) for position overlay update
private static final float MIN_LOCATION_DELTA = 0.01f;
- Location currentLocation = new Location("");
- boolean locationValid = false;
+ Location currentLocation = Sensors.getInstance().currentGeo();
float currentHeading;
private long timeLastPositionOverlayCalculation = 0;
@@ -946,16 +1060,10 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
@Override
- public void updateGeoDir(final IGeoData geo, final float dir) {
- if (geo.isPseudoLocation()) {
- locationValid = false;
- } else {
- locationValid = true;
-
- currentLocation = geo.getLocation();
- currentHeading = DirectionProvider.getDirectionNow(dir);
- repaintPositionOverlay();
- }
+ public void updateGeoDir(final GeoData geo, final float dir) {
+ currentLocation = geo;
+ currentHeading = AngleUtils.getDirectionNow(dir);
+ repaintPositionOverlay();
}
/**
@@ -969,23 +1077,24 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
try {
final CGeoMap map = mapRef.get();
if (map != null) {
- final boolean needsRepaintForDistance = needsRepaintForDistance();
+ final boolean needsRepaintForDistanceOrAccuracy = needsRepaintForDistanceOrAccuracy();
final boolean needsRepaintForHeading = needsRepaintForHeading();
- if (needsRepaintForDistance) {
- if (map.followMyLocation) {
+ if (needsRepaintForDistanceOrAccuracy) {
+ if (CGeoMap.followMyLocation) {
map.centerMap(new Geopoint(currentLocation));
}
}
- if (needsRepaintForDistance || needsRepaintForHeading) {
+ if (needsRepaintForDistanceOrAccuracy || needsRepaintForHeading) {
+
map.overlayPositionAndScale.setCoordinates(currentLocation);
map.overlayPositionAndScale.setHeading(currentHeading);
map.mapView.repaintRequired(map.overlayPositionAndScale);
}
}
} catch (final RuntimeException e) {
- Log.w("Failed to update location.");
+ Log.w("Failed to update location", e);
}
}
}
@@ -998,11 +1107,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
return Math.abs(AngleUtils.difference(currentHeading, map.overlayPositionAndScale.getHeading())) > MIN_HEADING_DELTA;
}
- boolean needsRepaintForDistance() {
- if (!locationValid) {
- return false;
- }
-
+ boolean needsRepaintForDistanceOrAccuracy() {
final CGeoMap map = mapRef.get();
if (map == null) {
return false;
@@ -1011,6 +1116,9 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
float dist = Float.MAX_VALUE;
if (lastLocation != null) {
+ if (lastLocation.getAccuracy() != currentLocation.getAccuracy()) {
+ return true;
+ }
dist = currentLocation.distanceTo(lastLocation);
}
@@ -1028,7 +1136,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
/**
- * Starts the {@link LoadTimer}.
+ * Starts the load timer.
*/
private Subscription startTimer() {
@@ -1037,7 +1145,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
displayPoint(coordsIntent);
loadTimer = Subscriptions.empty();
} else {
- loadTimer = startLoadTimer();
+ loadTimer = Schedulers.newThread().createWorker().schedulePeriodically(new LoadTimerAction(this), 0, 250, TimeUnit.MILLISECONDS);
}
return loadTimer;
}
@@ -1072,7 +1180,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
// update title on any change
if (moved || !viewportNow.equals(previousViewport)) {
- map.displayHandler.sendEmptyMessage(UPDATE_TITLE);
+ map.updateMapTitle();
}
previousZoom = zoomNow;
@@ -1094,16 +1202,8 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
/**
- * loading timer Triggers every 250ms and checks for viewport change and starts a {@link LoadRunnable}.
- */
- private Subscription startLoadTimer() {
- return Schedulers.newThread().createWorker().schedulePeriodically(new LoadTimerAction(this), 0, 250, TimeUnit.MILLISECONDS);
- }
-
- /**
* get if map is loading something
*
- * @return
*/
public boolean isLoading() {
return !loadTimer.isUnsubscribed() &&
@@ -1114,7 +1214,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
/**
* Worker thread that loads caches and waypoints from the database and then spawns the {@link DownloadRunnable}.
- * started by {@link LoadTimer}
+ * started by the load timer.
*/
private static class LoadRunnable extends DoRunnable {
@@ -1134,7 +1234,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
showProgressHandler.sendEmptyMessage(SHOW_PROGRESS);
loadThreadRun = System.currentTimeMillis();
- SearchResult searchResult;
+ final SearchResult searchResult;
if (mapMode == MapMode.LIVE) {
searchResult = isLiveEnabled ? new SearchResult() : new SearchResult(DataStore.loadStoredInViewport(mapView.getViewport(), Settings.getCacheType()));
} else {
@@ -1250,9 +1350,6 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
//render
displayExecutor.execute(new DisplayRunnable(this));
- } catch (final ThreadDeath e) {
- Log.d("DownloadThread stopped");
- displayHandler.sendEmptyMessage(UPDATE_TITLE);
} finally {
showProgressHandler.sendEmptyMessage(HIDE_PROGRESS); // hide progress
}
@@ -1302,19 +1399,14 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
}
itemsToDisplay.add(getCacheItem(cache));
}
-
- overlayCaches.updateItems(itemsToDisplay);
- displayHandler.sendEmptyMessage(INVALIDATE_MAP);
-
- } else {
+ }
+ // don't add other waypoints to overlayCaches if just one point should be displayed
+ if (coordsIntent == null) {
overlayCaches.updateItems(itemsToDisplay);
- displayHandler.sendEmptyMessage(INVALIDATE_MAP);
}
+ displayHandler.sendEmptyMessage(INVALIDATE_MAP);
- displayHandler.sendEmptyMessage(UPDATE_TITLE);
- } catch (final ThreadDeath e) {
- Log.d("DisplayThread stopped");
- displayHandler.sendEmptyMessage(UPDATE_TITLE);
+ updateMapTitle();
} finally {
showProgressHandler.sendEmptyMessage(HIDE_PROGRESS);
}
@@ -1327,11 +1419,15 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
final CachesOverlayItemImpl item = getWaypointItem(waypoint);
overlayCaches.updateItems(item);
displayHandler.sendEmptyMessage(INVALIDATE_MAP);
- displayHandler.sendEmptyMessage(UPDATE_TITLE);
+ updateMapTitle();
cachesCnt = 1;
}
+ private void updateMapTitle() {
+ displayHandler.sendEmptyMessage(UPDATE_TITLE);
+ }
+
private static abstract class DoRunnable implements Runnable {
private final WeakReference<CGeoMap> mapRef;
@@ -1538,7 +1634,7 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
if (myLocSwitch != null) {
myLocSwitch.setChecked(followMyLocation);
if (followMyLocation) {
- myLocationInMiddle(app.currentGeo());
+ myLocationInMiddle(Sensors.getInstance().currentGeo());
}
}
}
@@ -1610,42 +1706,40 @@ public class CGeoMap extends AbstractMap implements ViewFactory {
public static void startActivitySearch(final Activity fromActivity, final SearchResult search, final String title) {
final Intent mapIntent = newIntent(fromActivity);
- mapIntent.putExtra(EXTRAS_SEARCH, search);
- mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.LIST);
- mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false);
+ mapIntent.putExtra(Intents.EXTRA_SEARCH, search);
+ mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.LIST);
+ mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false);
if (StringUtils.isNotBlank(title)) {
- mapIntent.putExtra(CGeoMap.EXTRAS_MAP_TITLE, title);
+ mapIntent.putExtra(Intents.EXTRA_TITLE, title);
}
fromActivity.startActivity(mapIntent);
}
- public static void startActivityLiveMap(final Activity fromActivity) {
- final Intent mapIntent = newIntent(fromActivity);
- mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.LIVE);
- mapIntent.putExtra(EXTRAS_LIVE_ENABLED, Settings.isLiveMap());
- fromActivity.startActivity(mapIntent);
+ public static Intent getLiveMapIntent(final Activity fromActivity) {
+ return newIntent(fromActivity)
+ .putExtra(Intents.EXTRA_MAP_MODE, MapMode.LIVE)
+ .putExtra(Intents.EXTRA_LIVE_ENABLED, Settings.isLiveMap());
}
public static void startActivityCoords(final Activity fromActivity, final Geopoint coords, final WaypointType type, final String title) {
final Intent mapIntent = newIntent(fromActivity);
- mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.COORDS);
- mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false);
- mapIntent.putExtra(EXTRAS_COORDS, coords);
+ mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.COORDS);
+ mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false);
+ mapIntent.putExtra(Intents.EXTRA_COORDS, coords);
if (type != null) {
- mapIntent.putExtra(EXTRAS_WPTTYPE, type.id);
+ mapIntent.putExtra(Intents.EXTRA_WPTTYPE, type.id);
}
if (StringUtils.isNotBlank(title)) {
- mapIntent.putExtra(EXTRAS_MAP_TITLE, title);
+ mapIntent.putExtra(Intents.EXTRA_TITLE, title);
}
fromActivity.startActivity(mapIntent);
}
public static void startActivityGeoCode(final Activity fromActivity, final String geocode) {
final Intent mapIntent = newIntent(fromActivity);
- mapIntent.putExtra(EXTRAS_MAP_MODE, MapMode.SINGLE);
- mapIntent.putExtra(EXTRAS_LIVE_ENABLED, false);
- mapIntent.putExtra(EXTRAS_GEOCODE, geocode);
- mapIntent.putExtra(EXTRAS_MAP_TITLE, geocode);
+ mapIntent.putExtra(Intents.EXTRA_MAP_MODE, MapMode.SINGLE);
+ mapIntent.putExtra(Intents.EXTRA_LIVE_ENABLED, false);
+ mapIntent.putExtra(Intents.EXTRA_GEOCODE, geocode);
fromActivity.startActivity(mapIntent);
}
diff --git a/main/src/cgeo/geocaching/maps/CachesOverlay.java b/main/src/cgeo/geocaching/maps/CachesOverlay.java
index 3c6109e..9649c0d 100644
--- a/main/src/cgeo/geocaching/maps/CachesOverlay.java
+++ b/main/src/cgeo/geocaching/maps/CachesOverlay.java
@@ -10,7 +10,7 @@ import cgeo.geocaching.activity.Progress;
import cgeo.geocaching.connector.gc.GCMap;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
@@ -43,13 +43,13 @@ public class CachesOverlay extends AbstractItemizedOverlay {
private List<CachesOverlayItemImpl> items = new ArrayList<>();
private Context context = null;
private boolean displayCircles = false;
- private Progress progress = new Progress();
+ private final Progress progress = new Progress();
private Paint blockedCircle = null;
private PaintFlagsDrawFilter setFilter = null;
private PaintFlagsDrawFilter removeFilter = null;
private MapItemFactory mapItemFactory = null;
- public CachesOverlay(ItemizedOverlayImpl ovlImpl, Context contextIn) {
+ public CachesOverlay(final ItemizedOverlayImpl ovlImpl, final Context contextIn) {
super(ovlImpl);
populate();
@@ -60,19 +60,19 @@ public class CachesOverlay extends AbstractItemizedOverlay {
mapItemFactory = mapProvider.getMapItemFactory();
}
- void updateItems(CachesOverlayItemImpl item) {
- List<CachesOverlayItemImpl> itemsPre = new ArrayList<>();
+ void updateItems(final CachesOverlayItemImpl item) {
+ final List<CachesOverlayItemImpl> itemsPre = new ArrayList<>();
itemsPre.add(item);
updateItems(itemsPre);
}
- void updateItems(List<CachesOverlayItemImpl> itemsPre) {
+ void updateItems(final List<CachesOverlayItemImpl> itemsPre) {
if (itemsPre == null) {
return;
}
- for (CachesOverlayItemImpl item : itemsPre) {
+ for (final CachesOverlayItemImpl item : itemsPre) {
item.setMarker(boundCenterBottom(item.getMarker(0)));
}
@@ -97,7 +97,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
}
@Override
- public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ public void draw(final Canvas canvas, final MapViewImpl mapView, final boolean shadow) {
drawInternal(canvas, mapView.getMapProjection());
@@ -105,15 +105,15 @@ public class CachesOverlay extends AbstractItemizedOverlay {
}
@Override
- public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
+ public void drawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final MapProjectionImpl projection, final byte drawZoomLevel) {
drawInternal(canvas, projection);
super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
}
- private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+ private void drawInternal(final Canvas canvas, final MapProjectionImpl projection) {
if (!displayCircles || items.isEmpty()) {
return;
}
@@ -129,7 +129,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
final int radius = calculateDrawingRadius(projection);
final Point center = new Point();
- for (CachesOverlayItemImpl item : items) {
+ for (final CachesOverlayItemImpl item : items) {
if (item.applyDistanceRule()) {
final Geopoint itemCoord = item.getCoord().getCoords();
final GeoPointImpl itemGeo = mapItemFactory.getGeoPointBase(itemCoord);
@@ -158,11 +158,9 @@ public class CachesOverlay extends AbstractItemizedOverlay {
* reality and therefore the minor changes due to the projection will not make any visible difference at the zoom
* levels which are used to see the circles.
*
- * @param projection
- * @return
*/
- private int calculateDrawingRadius(MapProjectionImpl projection) {
- float[] distanceArray = new float[1];
+ private int calculateDrawingRadius(final MapProjectionImpl projection) {
+ final float[] distanceArray = new float[1];
final Geopoint itemCoord = items.get(0).getCoord().getCoords();
Location.distanceBetween(itemCoord.getLatitude(), itemCoord.getLongitude(),
@@ -202,7 +200,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
}
@Override
- public boolean onTap(int index) {
+ public boolean onTap(final int index) {
try {
if (items.size() <= index) {
@@ -232,7 +230,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
if (StringUtils.equalsIgnoreCase(coordType, "cache") && StringUtils.isNotBlank(coordinate.getGeocode())) {
final Geocache cache = DataStore.loadCache(coordinate.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
if (cache != null) {
- RequestDetailsThread requestDetailsThread = new RequestDetailsThread(cache);
+ final RequestDetailsThread requestDetailsThread = new RequestDetailsThread(cache);
if (!requestDetailsThread.requestRequired()) {
// don't show popup if we have enough details
progress.dismiss();
@@ -253,21 +251,19 @@ public class CachesOverlay extends AbstractItemizedOverlay {
}
progress.dismiss();
- } catch (NotFoundException e) {
+ } catch (final NotFoundException e) {
Log.e("CachesOverlay.onTap", e);
- if (progress != null) {
- progress.dismiss();
- }
+ progress.dismiss();
}
return true;
}
@Override
- public CachesOverlayItemImpl createItem(int index) {
+ public CachesOverlayItemImpl createItem(final int index) {
try {
return items.get(index);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("CachesOverlay.createItem", e);
}
@@ -278,7 +274,7 @@ public class CachesOverlay extends AbstractItemizedOverlay {
public int size() {
try {
return items.size();
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("CachesOverlay.size", e);
}
diff --git a/main/src/cgeo/geocaching/maps/DirectionDrawer.java b/main/src/cgeo/geocaching/maps/DirectionDrawer.java
new file mode 100644
index 0000000..c746221
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/DirectionDrawer.java
@@ -0,0 +1,60 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.maps.interfaces.MapItemFactory;
+import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
+import cgeo.geocaching.settings.Settings;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.location.Location;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+public class DirectionDrawer {
+ private Geopoint currentCoords;
+ private final Geopoint destinationCoords;
+ private final MapItemFactory mapItemFactory;
+ private final float width;
+
+ private Paint line = null;
+
+ public DirectionDrawer(final Geopoint coords) {
+ this.destinationCoords = coords;
+ this.mapItemFactory = Settings.getMapProvider().getMapItemFactory();
+
+ final DisplayMetrics metrics = new DisplayMetrics();
+ final WindowManager windowManager = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+
+ width = 4f * metrics.density;
+
+ }
+
+ public void setCoordinates(final Location coordinatesIn) {
+ currentCoords = new Geopoint(coordinatesIn);
+ }
+
+ void drawDirection(final Canvas canvas, final MapProjectionImpl projection) {
+ if (currentCoords == null) {
+ return;
+ }
+
+ if (line == null) {
+ line = new Paint();
+ line.setAntiAlias(true);
+ line.setStrokeWidth(width);
+ line.setColor(0x80EB391E);
+ }
+
+ final Point pos = new Point();
+ final Point dest = new Point();
+ projection.toPixels(mapItemFactory.getGeoPointBase(currentCoords), pos);
+ projection.toPixels(mapItemFactory.getGeoPointBase(destinationCoords), dest);
+
+ canvas.drawLine(pos.x, pos.y, dest.x, dest.y, line);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/DistanceDrawer.java b/main/src/cgeo/geocaching/maps/DistanceDrawer.java
new file mode 100644
index 0000000..9dde8e6
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/DistanceDrawer.java
@@ -0,0 +1,130 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.maps.interfaces.MapViewImpl;
+
+import android.content.Context;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.location.Location;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+public class DistanceDrawer {
+ private final Geopoint destinationCoords;
+
+ private Paint paintBox = null;
+ private Paint paintBoxShadow = null;
+ private Paint paintText = null;
+ private BlurMaskFilter blurBoxShadow = null;
+
+ private final boolean needsInvertedColors;
+ private float pixelDensity = 0;
+ private final float boxWidth, boxHeight, boxCornerRadius, boxShadowSize, boxPadding;
+ private final float textHeight, maxTextWidth;
+ private final float boxX, boxY;
+
+ private String distanceText = null;
+
+ public DistanceDrawer(final MapViewImpl mapView, final Geopoint destinationCoords) {
+ this.destinationCoords = destinationCoords;
+
+ final DisplayMetrics metrics = new DisplayMetrics();
+ final WindowManager windowManager = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+
+ pixelDensity = metrics.density;
+
+ boxPadding = 2;
+ boxWidth = 100 * pixelDensity + 3 * boxPadding;
+ boxHeight = 30 * pixelDensity + 2 * boxPadding;
+ boxCornerRadius = 5 * pixelDensity;
+ boxShadowSize = 1 * pixelDensity;
+ textHeight = 20 * pixelDensity;
+
+ needsInvertedColors = mapView.needsInvertedColors();
+ boxX = metrics.widthPixels - boxWidth;
+ boxY = 0;
+
+ maxTextWidth = boxWidth - 3 * boxPadding;
+ }
+
+ public void setCoordinates(final Location location) {
+ final Geopoint currentCoords = new Geopoint(location);
+
+ final float distance = currentCoords.distanceTo(destinationCoords);
+ distanceText = Units.getDistanceFromKilometers(distance);
+ }
+
+ void drawDistance(final Canvas canvas) {
+ if (distanceText == null) {
+ return;
+ }
+
+ if (blurBoxShadow == null) {
+ blurBoxShadow = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL);
+
+ paintBoxShadow = new Paint();
+ paintBoxShadow.setAntiAlias(true);
+ paintBoxShadow.setMaskFilter(blurBoxShadow);
+
+ paintBox = new Paint();
+ paintBox.setAntiAlias(true);
+
+ paintText = new Paint();
+ paintText.setAntiAlias(true);
+ paintText.setTextAlign(Paint.Align.LEFT);
+ paintText.setTypeface(Typeface.DEFAULT_BOLD);
+
+ final int TRANSPARENCY = 0x80000000;
+ if (needsInvertedColors) {
+ paintBoxShadow.setColor(0x000000 | TRANSPARENCY);
+ paintBox.setColor(0xFFFFFF | TRANSPARENCY);
+ paintText.setColor(0xFF000000);
+ } else {
+ paintBoxShadow.setColor(0xFFFFFF | TRANSPARENCY);
+ paintBox.setColor(0x000000 | TRANSPARENCY);
+ paintText.setColor(0xFFFFFFFF);
+ }
+ }
+
+ /* Calculate text size */
+ final Rect textBounds = new Rect();
+ paintText.setTextSize(textHeight);
+ paintText.getTextBounds(distanceText, 0, distanceText.length(), textBounds);
+ while (textBounds.height() > maxTextWidth) {
+ paintText.setTextSize(paintText.getTextSize() - 1);
+ paintText.getTextBounds(distanceText, 0, distanceText.length(), textBounds);
+ }
+
+ final float textX = (boxWidth - 3 * boxPadding - textBounds.width()) / 2 + boxX + 2 * boxPadding;
+ final float textY = (boxHeight + textBounds.height()) / 2 + boxY;
+
+ /* Paint background box */
+ canvas.drawRoundRect(
+ new RectF(
+ boxX - boxShadowSize, boxY - boxShadowSize - boxCornerRadius,
+ boxX + boxWidth + boxShadowSize + boxCornerRadius, boxY + boxHeight + boxShadowSize
+ ),
+ boxCornerRadius, boxCornerRadius,
+ paintBoxShadow
+ );
+ canvas.drawRoundRect(
+ new RectF(
+ boxX, boxY - boxCornerRadius,
+ boxX + boxWidth + boxCornerRadius, boxY + boxHeight
+ ),
+ boxCornerRadius, boxCornerRadius,
+ paintBox
+ );
+
+ /* Paint distance */
+ canvas.drawText(distanceText, textX, textY, paintText);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/LivemapStrategy.java b/main/src/cgeo/geocaching/maps/LivemapStrategy.java
new file mode 100644
index 0000000..c135fc8
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/LivemapStrategy.java
@@ -0,0 +1,45 @@
+package cgeo.geocaching.maps;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+
+import java.util.EnumSet;
+
+/**
+ * Defines the strategy for the Live Map
+ */
+public enum LivemapStrategy {
+ FASTEST(1, EnumSet.of(Flag.LOAD_TILES), R.string.map_strategy_fastest),
+ FAST(2, EnumSet.of(Flag.LOAD_TILES, Flag.PARSE_TILES), R.string.map_strategy_fast),
+ AUTO(3, EnumSet.noneOf(Flag.class), R.string.map_strategy_auto),
+ DETAILED(4, EnumSet.allOf(Flag.class), R.string.map_strategy_detailed);
+
+ public final int id;
+ public final EnumSet<Flag> flags;
+ private final int stringId;
+
+ public enum Flag {
+ LOAD_TILES, // 2x2 tiles filling the complete viewport
+ PARSE_TILES, // parse PNG images
+ SEARCH_NEARBY // searchByCoords()
+ }
+
+ LivemapStrategy(final int id, final EnumSet<Flag> flags, final int stringId) {
+ this.id = id;
+ this.flags = flags;
+ this.stringId = stringId;
+ }
+
+ public static LivemapStrategy getById(final int id) {
+ for (final LivemapStrategy strategy : LivemapStrategy.values()) {
+ if (strategy.id == id) {
+ return strategy;
+ }
+ }
+ return AUTO;
+ }
+
+ public final String getL10n() {
+ return CgeoApplication.getInstance().getBaseContext().getResources().getString(stringId);
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/MapActivity.java b/main/src/cgeo/geocaching/maps/MapActivity.java
new file mode 100644
index 0000000..28668ca
--- /dev/null
+++ b/main/src/cgeo/geocaching/maps/MapActivity.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.maps;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * This activity provides an entry point for external intent calls, and then forwards to the currently used map activity
+ * implementation.
+ */
+public class MapActivity extends Activity {
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ startActivity(CGeoMap.getLiveMapIntent(this));
+ finish();
+ }
+}
diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
index 8685d94..b504020 100644
--- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java
+++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java
@@ -33,7 +33,8 @@ public class MapProviderFactory {
public static boolean isGoogleMapsInstalled() {
// Check if API key is available
- if (StringUtils.isBlank(CgeoApplication.getInstance().getString(R.string.maps_api_key))) {
+ final String mapsKey = CgeoApplication.getInstance().getString(R.string.maps_api_key);
+ if (StringUtils.length(mapsKey) < 30 || StringUtils.contains(mapsKey, "key")) {
Log.w("No Google API key available.");
return false;
}
@@ -41,7 +42,7 @@ public class MapProviderFactory {
// Check if API is available
try {
Class.forName("com.google.android.maps.MapActivity");
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException ignored) {
return false;
}
@@ -59,7 +60,7 @@ public class MapProviderFactory {
return provider1 == provider2 && provider1.isSameActivity(source1, source2);
}
- public static void addMapviewMenuItems(Menu menu) {
+ public static void addMapviewMenuItems(final Menu menu) {
final SubMenu parentMenu = menu.findItem(R.id.menu_select_mapview).getSubMenu();
final int currentSource = Settings.getMapSource().getNumericalId();
@@ -78,8 +79,8 @@ public class MapProviderFactory {
* @return the map source, or <tt>null</tt> if <tt>id</tt> does not correspond to a registered map source
*/
@Nullable
- public static MapSource getMapSource(int id) {
- for (MapSource mapSource : mapSources) {
+ public static MapSource getMapSource(final int id) {
+ for (final MapSource mapSource : mapSources) {
if (mapSource.getNumericalId() == id) {
return mapSource;
}
@@ -109,7 +110,7 @@ public class MapProviderFactory {
*/
public static void deleteOfflineMapSources() {
final ArrayList<MapSource> deletion = new ArrayList<>();
- for (MapSource mapSource : mapSources) {
+ for (final MapSource mapSource : mapSources) {
if (mapSource instanceof MapsforgeMapProvider.OfflineMapSource) {
deletion.add(mapSource);
}
diff --git a/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
index 63fcd73..9a6e4b9 100644
--- a/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
+++ b/main/src/cgeo/geocaching/maps/PositionAndScaleOverlay.java
@@ -1,5 +1,8 @@
package cgeo.geocaching.maps;
+import cgeo.geocaching.DataStore;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
@@ -16,22 +19,40 @@ public class PositionAndScaleOverlay implements GeneralOverlay {
PositionDrawer positionDrawer = null;
ScaleDrawer scaleDrawer = null;
+ DirectionDrawer directionDrawer = null;
+ DistanceDrawer distanceDrawer = null;
- public PositionAndScaleOverlay(OverlayImpl ovlImpl) {
+ public PositionAndScaleOverlay(final OverlayImpl ovlImpl, final MapViewImpl mapView, final Geopoint coords, final String geocode) {
this.ovlImpl = ovlImpl;
positionDrawer = new PositionDrawer();
scaleDrawer = new ScaleDrawer();
+
+ if (coords != null) {
+ directionDrawer = new DirectionDrawer(coords);
+ distanceDrawer = new DistanceDrawer(mapView, coords);
+ } else if (geocode != null) {
+ final Viewport bounds = DataStore.getBounds(geocode);
+ if (bounds != null) {
+ directionDrawer = new DirectionDrawer(bounds.center);
+ distanceDrawer = new DistanceDrawer(mapView, bounds.center);
+ }
+ }
}
- public void setCoordinates(Location coordinatesIn) {
+ public void setCoordinates(final Location coordinatesIn) {
positionDrawer.setCoordinates(coordinatesIn);
+ if (directionDrawer != null) {
+ directionDrawer.setCoordinates(coordinatesIn);
+ distanceDrawer.setCoordinates(coordinatesIn);
+ }
+
}
public Location getCoordinates() {
return positionDrawer.getCoordinates();
}
- public void setHeading(float bearingNow) {
+ public void setHeading(final float bearingNow) {
positionDrawer.setHeading(bearingNow);
}
@@ -40,21 +61,27 @@ public class PositionAndScaleOverlay implements GeneralOverlay {
}
@Override
- public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
+ public void drawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final MapProjectionImpl projection, final byte drawZoomLevel) {
drawInternal(canvas, projection, getOverlayImpl().getMapViewImpl());
}
@Override
- public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ public void draw(final Canvas canvas, final MapViewImpl mapView, final boolean shadow) {
drawInternal(canvas, mapView.getMapProjection(), mapView);
}
- private void drawInternal(Canvas canvas, MapProjectionImpl projection, MapViewImpl mapView) {
+ private void drawInternal(final Canvas canvas, final MapProjectionImpl projection, final MapViewImpl mapView) {
+ if (directionDrawer != null) {
+ directionDrawer.drawDirection(canvas, projection);
+ }
positionDrawer.drawPosition(canvas, projection);
scaleDrawer.drawScale(canvas, mapView);
+ if (distanceDrawer != null) {
+ distanceDrawer.drawDistance(canvas);
+ }
}
@Override
@@ -66,7 +93,7 @@ public class PositionAndScaleOverlay implements GeneralOverlay {
return positionDrawer.getHistory();
}
- public void setHistory(ArrayList<Location> history) {
+ public void setHistory(final ArrayList<Location> history) {
positionDrawer.setHistory(history);
}
}
diff --git a/main/src/cgeo/geocaching/maps/PositionDrawer.java b/main/src/cgeo/geocaching/maps/PositionDrawer.java
index 08244ef..c7d1734 100644
--- a/main/src/cgeo/geocaching/maps/PositionDrawer.java
+++ b/main/src/cgeo/geocaching/maps/PositionDrawer.java
@@ -2,7 +2,7 @@ package cgeo.geocaching.maps;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
@@ -28,21 +28,21 @@ public class PositionDrawer {
private Paint accuracyCircle = null;
private Paint historyLine = null;
private Paint historyLineShadow = null;
- private Point center = new Point();
- private Point left = new Point();
+ private final Point center = new Point();
+ private final Point left = new Point();
private Bitmap arrow = null;
private int widthArrowHalf = 0;
private int heightArrowHalf = 0;
private PaintFlagsDrawFilter setfil = null;
private PaintFlagsDrawFilter remfil = null;
- private PositionHistory positionHistory = new PositionHistory();
- private MapItemFactory mapItemFactory;
+ private final PositionHistory positionHistory = new PositionHistory();
+ private final MapItemFactory mapItemFactory;
public PositionDrawer() {
this.mapItemFactory = Settings.getMapProvider().getMapItemFactory();
}
- void drawPosition(Canvas canvas, MapProjectionImpl projection) {
+ void drawPosition(final Canvas canvas, final MapProjectionImpl projection) {
if (coordinates == null || location == null) {
return;
}
@@ -76,20 +76,20 @@ public class PositionDrawer {
canvas.setDrawFilter(setfil);
- double latitude = coordinates.getLatitude();
- double longitude = coordinates.getLongitude();
- float accuracy = coordinates.getAccuracy();
+ final double latitude = coordinates.getLatitude();
+ final double longitude = coordinates.getLongitude();
+ final float accuracy = coordinates.getAccuracy();
- float[] result = new float[1];
+ final float[] result = new float[1];
Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result);
- float longitudeLineDistance = result[0];
+ final float longitudeLineDistance = result[0];
final Geopoint leftCoords = new Geopoint(latitude, longitude - accuracy / longitudeLineDistance);
- GeoPointImpl leftGeo = mapItemFactory.getGeoPointBase(leftCoords);
+ final GeoPointImpl leftGeo = mapItemFactory.getGeoPointBase(leftCoords);
projection.toPixels(leftGeo, left);
projection.toPixels(location, center);
- int radius = center.x - left.x;
+ final int radius = center.x - left.x;
accuracyCircle.setColor(0x66000000);
accuracyCircle.setStyle(Style.STROKE);
@@ -106,23 +106,23 @@ public class PositionDrawer {
final ArrayList<Location> paintHistory = new ArrayList<>(positionHistory.getHistory());
paintHistory.add(coordinates);
- int size = paintHistory.size();
+ final int size = paintHistory.size();
if (size > 1) {
int alphaCnt = size - 201;
if (alphaCnt < 1) {
alphaCnt = 1;
}
- Point pointNow = new Point();
- Point pointPrevious = new Point();
- Location prev = paintHistory.get(0);
+ final Point pointNow = new Point();
+ final Point pointPrevious = new Point();
+ final Location prev = paintHistory.get(0);
projection.toPixels(mapItemFactory.getGeoPointBase(new Geopoint(prev)), pointPrevious);
for (int cnt = 1; cnt < size; cnt++) {
- Location now = paintHistory.get(cnt);
+ final Location now = paintHistory.get(cnt);
projection.toPixels(mapItemFactory.getGeoPointBase(new Geopoint(now)), pointNow);
- int alpha;
+ final int alpha;
if ((alphaCnt - cnt) > 0) {
alpha = 255 / (alphaCnt - cnt);
}
@@ -147,10 +147,10 @@ public class PositionDrawer {
heightArrowHalf = arrow.getHeight() / 2;
}
- int marginLeft = center.x - widthArrowHalf;
- int marginTop = center.y - heightArrowHalf;
+ final int marginLeft = center.x - widthArrowHalf;
+ final int marginTop = center.y - heightArrowHalf;
- Matrix matrix = new Matrix();
+ final Matrix matrix = new Matrix();
matrix.setRotate(heading, widthArrowHalf, heightArrowHalf);
matrix.postTranslate(marginLeft, marginTop);
@@ -163,11 +163,11 @@ public class PositionDrawer {
return positionHistory.getHistory();
}
- public void setHistory(ArrayList<Location> history) {
+ public void setHistory(final ArrayList<Location> history) {
positionHistory.setHistory(history);
}
- public void setHeading(float bearingNow) {
+ public void setHeading(final float bearingNow) {
heading = bearingNow;
}
@@ -175,7 +175,7 @@ public class PositionDrawer {
return heading;
}
- public void setCoordinates(Location coordinatesIn) {
+ public void setCoordinates(final Location coordinatesIn) {
coordinates = coordinatesIn;
location = mapItemFactory.getGeoPointBase(new Geopoint(coordinates));
}
diff --git a/main/src/cgeo/geocaching/maps/PositionHistory.java b/main/src/cgeo/geocaching/maps/PositionHistory.java
index af13740..4394eba 100644
--- a/main/src/cgeo/geocaching/maps/PositionHistory.java
+++ b/main/src/cgeo/geocaching/maps/PositionHistory.java
@@ -24,7 +24,7 @@ public class PositionHistory {
/**
* Adds the current position to the trail history to be able to show the trail on the map.
*/
- void rememberTrailPosition(Location coordinates) {
+ void rememberTrailPosition(final Location coordinates) {
if (coordinates.getAccuracy() >= 50f) {
return;
}
@@ -36,7 +36,7 @@ public class PositionHistory {
return;
}
- Location historyRecent = history.get(history.size() - 1);
+ final Location historyRecent = history.get(history.size() - 1);
if (historyRecent.distanceTo(coordinates) <= MINIMUM_DISTANCE_METERS) {
return;
}
@@ -56,7 +56,7 @@ public class PositionHistory {
return history;
}
- public void setHistory(ArrayList<Location> history) {
+ public void setHistory(final ArrayList<Location> history) {
this.history = history;
}
diff --git a/main/src/cgeo/geocaching/maps/ScaleDrawer.java b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
index 95c987d..e905873 100644
--- a/main/src/cgeo/geocaching/maps/ScaleDrawer.java
+++ b/main/src/cgeo/geocaching/maps/ScaleDrawer.java
@@ -1,8 +1,8 @@
package cgeo.geocaching.maps;
import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
@@ -25,8 +25,8 @@ public class ScaleDrawer {
private float pixelDensity = 0;
public ScaleDrawer() {
- DisplayMetrics metrics = new DisplayMetrics();
- WindowManager windowManager = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
+ final DisplayMetrics metrics = new DisplayMetrics();
+ final WindowManager windowManager = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(metrics);
pixelDensity = metrics.density;
}
@@ -36,7 +36,7 @@ public class ScaleDrawer {
return scale * Math.floor(distance / scale);
}
- void drawScale(Canvas canvas, MapViewImpl mapView) {
+ void drawScale(final Canvas canvas, final MapViewImpl mapView) {
final double span = mapView.getLongitudeSpan() / 1e6;
final GeoPointImpl center = mapView.getMapViewCenter();
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
index 3596d5f..1e69b44 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapActivityImpl.java
@@ -33,5 +33,8 @@ public interface MapActivityImpl {
boolean superOnOptionsItemSelected(MenuItem item);
+ /**
+ * called from the pseudo actionbar layout
+ */
public abstract void navigateUp(View view);
}
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java b/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
index 22c6698..f69de03 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapItemFactory.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps.interfaces;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
public interface MapItemFactory {
diff --git a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
index 4a6d733..1876dfc 100644
--- a/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
+++ b/main/src/cgeo/geocaching/maps/interfaces/MapViewImpl.java
@@ -1,6 +1,7 @@
package cgeo.geocaching.maps.interfaces;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
import cgeo.geocaching.maps.PositionAndScaleOverlay;
@@ -46,7 +47,7 @@ public interface MapViewImpl {
CachesOverlay createAddMapOverlay(Context context, Drawable drawable);
- PositionAndScaleOverlay createAddPositionAndScaleOverlay();
+ PositionAndScaleOverlay createAddPositionAndScaleOverlay(final Geopoint coords, final String geocode);
void setMapSource();
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
index b9e40d7..02e4243 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlay.java
@@ -18,10 +18,10 @@ import java.util.concurrent.locks.ReentrantLock;
public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlayItem> implements ItemizedOverlayImpl {
- private CachesOverlay base;
- private Lock lock = new ReentrantLock();
+ private final CachesOverlay base;
+ private final Lock lock = new ReentrantLock();
- public MapsforgeCacheOverlay(Context contextIn, Drawable markerIn) {
+ public MapsforgeCacheOverlay(final Context contextIn, final Drawable markerIn) {
super(boundCenterBottom(markerIn));
base = new CachesOverlay(this, contextIn);
}
@@ -32,7 +32,7 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- protected MapsforgeCacheOverlayItem createItem(int i) {
+ protected MapsforgeCacheOverlayItem createItem(final int i) {
if (base == null) {
return null;
}
@@ -50,7 +50,7 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- protected boolean onTap(int arg0) {
+ protected boolean onTap(final int arg0) {
if (base == null) {
return false;
}
@@ -59,8 +59,8 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- Projection projection, byte drawZoomLevel) {
+ protected void drawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final Projection projection, final byte drawZoomLevel) {
base.drawOverlayBitmap(canvas, drawPosition, new MapsforgeMapProjection(projection), drawZoomLevel);
}
@@ -70,28 +70,28 @@ public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlay
}
@Override
- public Drawable superBoundCenterBottom(Drawable marker) {
+ public Drawable superBoundCenterBottom(final Drawable marker) {
return ItemizedOverlay.boundCenterBottom(marker);
}
@Override
- public void superSetLastFocusedItemIndex(int i) {
+ public void superSetLastFocusedItemIndex(final int i) {
// nothing to do
}
@Override
- public boolean superOnTap(int index) {
+ public boolean superOnTap(final int index) {
return super.onTap(index);
}
@Override
- public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ public void superDraw(final Canvas canvas, final MapViewImpl mapView, final boolean shadow) {
// nothing to do here...
}
@Override
- public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
+ public void superDrawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final MapProjectionImpl projection, final byte drawZoomLevel) {
super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
index 27ca664..4a1b080 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeCacheOverlayItem.java
@@ -12,7 +12,7 @@ public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOver
final private IWaypoint coord;
final private boolean applyDistanceRule;
- public MapsforgeCacheOverlayItem(IWaypoint coordinate, boolean applyDistanceRule) {
+ public MapsforgeCacheOverlayItem(final IWaypoint coordinate, final boolean applyDistanceRule) {
super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), "");
this.coord = coordinate;
@@ -25,7 +25,7 @@ public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOver
}
@Override
- public Drawable getMarker(int index) {
+ public Drawable getMarker(final int index) {
return getMarker();
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java
index 197bd76..25269e6 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeGeoPoint.java
@@ -1,6 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import org.mapsforge.core.GeoPoint;
@@ -9,7 +9,7 @@ public class MapsforgeGeoPoint extends GeoPoint implements GeoPointImpl {
private static final long serialVersionUID = 1L;
- public MapsforgeGeoPoint(int latitudeE6, int longitudeE6) {
+ public MapsforgeGeoPoint(final int latitudeE6, final int longitudeE6) {
super(latitudeE6, longitudeE6);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
index 94213ba..5220e05 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapActivity.java
@@ -16,7 +16,7 @@ import android.view.View;
public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl, FilteredActivity {
- private AbstractMap mapBase;
+ private final AbstractMap mapBase;
public MapsforgeMapActivity() {
mapBase = new CGeoMap(this);
@@ -28,7 +28,7 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
}
@Override
- protected void onCreate(Bundle icicle) {
+ protected void onCreate(final Bundle icicle) {
mapBase.onCreate(icicle);
}
@@ -53,17 +53,17 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
+ public boolean onCreateOptionsMenu(final Menu menu) {
return mapBase.onCreateOptionsMenu(menu);
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
+ public boolean onOptionsItemSelected(final MenuItem item) {
return mapBase.onOptionsItemSelected(item);
}
@Override
- public boolean onPrepareOptionsMenu(Menu menu) {
+ public boolean onPrepareOptionsMenu(final Menu menu) {
return mapBase.onPrepareOptionsMenu(menu);
}
@@ -73,12 +73,12 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
}
@Override
- public void superOnCreate(Bundle savedInstanceState) {
+ public void superOnCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
- public boolean superOnCreateOptionsMenu(Menu menu) {
+ public boolean superOnCreateOptionsMenu(final Menu menu) {
return super.onCreateOptionsMenu(menu);
}
@@ -88,7 +88,7 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
}
@Override
- public boolean superOnOptionsItemSelected(MenuItem item) {
+ public boolean superOnOptionsItemSelected(final MenuItem item) {
return super.onOptionsItemSelected(item);
}
@@ -108,17 +108,17 @@ public class MapsforgeMapActivity extends MapActivity implements MapActivityImpl
}
@Override
- public boolean superOnPrepareOptionsMenu(Menu menu) {
+ public boolean superOnPrepareOptionsMenu(final Menu menu) {
return super.onPrepareOptionsMenu(menu);
}
@Override
- public void navigateUp(View view) {
+ public void navigateUp(final View view) {
ActivityMixin.navigateUp(this);
}
@Override
- public void showFilterMenu(View view) {
+ public void showFilterMenu(final View view) {
// do nothing, the filter bar only shows the global filter
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapController.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapController.java
index 8b2e1e9..cfce07d 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapController.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapController.java
@@ -8,26 +8,26 @@ import org.mapsforge.core.GeoPoint;
public class MapsforgeMapController implements MapControllerImpl {
- private MapController mapController;
- private int maxZoomLevel;
+ private final MapController mapController;
+ private final int maxZoomLevel;
- public MapsforgeMapController(MapController mapControllerIn, int maxZoomLevelIn) {
+ public MapsforgeMapController(final MapController mapControllerIn, final int maxZoomLevelIn) {
mapController = mapControllerIn;
maxZoomLevel = maxZoomLevelIn;
}
@Override
- public void animateTo(GeoPointImpl geoPoint) {
+ public void animateTo(final GeoPointImpl geoPoint) {
mapController.setCenter(castToGeoPoint(geoPoint));
}
- private static GeoPoint castToGeoPoint(GeoPointImpl geoPoint) {
+ private static GeoPoint castToGeoPoint(final GeoPointImpl geoPoint) {
assert geoPoint instanceof GeoPoint;
return (GeoPoint) geoPoint;
}
@Override
- public void setCenter(GeoPointImpl geoPoint) {
+ public void setCenter(final GeoPointImpl geoPoint) {
mapController.setCenter(castToGeoPoint(geoPoint));
}
@@ -36,19 +36,19 @@ public class MapsforgeMapController implements MapControllerImpl {
* mapzoom-1 is used to be compatible with Google Maps zoom levels
*/
@Override
- public void setZoom(int mapzoom) {
+ public void setZoom(final int mapzoom) {
// Google Maps and OSM Maps use different zoom levels for the same view.
// All OSM Maps zoom levels are offset by 1 so they match Google Maps.
mapController.setZoom(Math.min(mapzoom - 1, maxZoomLevel));
}
@Override
- public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+ public void zoomToSpan(final int latSpanE6, final int lonSpanE6) {
if (latSpanE6 != 0 && lonSpanE6 != 0) {
// calculate zoomlevel
- int distDegree = Math.max(latSpanE6, lonSpanE6);
- int zoomLevel = (int) Math.floor(Math.log(360.0 * 1e6 / distDegree) / Math.log(2));
+ final int distDegree = Math.max(latSpanE6, lonSpanE6);
+ final int zoomLevel = (int) Math.floor(Math.log(360.0 * 1e6 / distDegree) / Math.log(2));
mapController.setZoom(zoomLevel + 1);
}
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
index 4ade09c..8adf4ad 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapItemFactory.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.maps.mapsforge;
import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
@@ -14,7 +14,7 @@ public class MapsforgeMapItemFactory implements MapItemFactory {
}
@Override
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
+ public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, final boolean applyDistanceRule) {
return new MapsforgeCacheOverlayItem(coordinate, applyDistanceRule);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProjection.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProjection.java
index 68d7123..a042eca 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProjection.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProjection.java
@@ -10,14 +10,14 @@ import android.graphics.Point;
public class MapsforgeMapProjection implements MapProjectionImpl {
- private Projection projection;
+ private final Projection projection;
- public MapsforgeMapProjection(Projection projectionIn) {
+ public MapsforgeMapProjection(final Projection projectionIn) {
projection = projectionIn;
}
@Override
- public void toPixels(GeoPointImpl leftGeo, Point left) {
+ public void toPixels(final GeoPointImpl leftGeo, final Point left) {
projection.toPixels((GeoPoint) leftGeo, left);
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
index 01b10ec..76d645c 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapProvider.java
@@ -7,8 +7,6 @@ import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapItemFactory;
import cgeo.geocaching.maps.interfaces.MapProvider;
import cgeo.geocaching.maps.interfaces.MapSource;
-import cgeo.geocaching.maps.mapsforge.v024.MapsforgeMapActivity024;
-import cgeo.geocaching.maps.mapsforge.v024.MapsforgeMapItemFactory024;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -30,7 +28,6 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
public static final String MAPSFORGE_CYCLEMAP_ID = "MAPSFORGE_CYCLEMAP";
public static final String MAPSFORGE_MAPNIK_ID = "MAPSFORGE_MAPNIK";
- private boolean oldMap = false;
private MapItemFactory mapItemFactory = new MapsforgeMapItemFactory();
private MapsforgeMapProvider() {
@@ -56,13 +53,13 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
return Collections.emptyList();
}
- File directory = new File(directoryPath);
+ final File directory = new File(directoryPath);
if (directory.isDirectory()) {
try {
- ArrayList<String> mapFileList = new ArrayList<>();
+ final ArrayList<String> mapFileList = new ArrayList<>();
final File[] files = directory.listFiles();
if (ArrayUtils.isNotEmpty(files)) {
- for (File file : files) {
+ for (final File file : files) {
if (file.getName().endsWith(".map")) {
if (MapsforgeMapProvider.isValidMapFile(file.getAbsolutePath())) {
mapFileList.add(file.getAbsolutePath());
@@ -72,69 +69,44 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
Collections.sort(mapFileList, String.CASE_INSENSITIVE_ORDER);
}
return mapFileList;
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("MapsforgeMapProvider.getOfflineMaps: ", e);
}
}
return Collections.emptyList();
}
- public static boolean isValidMapFile(String mapFileIn) {
+ public static boolean isValidMapFile(final String mapFileIn) {
if (StringUtils.isEmpty(mapFileIn)) {
return false;
}
- MapDatabase mapDB = new MapDatabase();
- FileOpenResult result = mapDB.openFile(new File(mapFileIn));
+ final MapDatabase mapDB = new MapDatabase();
+ final FileOpenResult result = mapDB.openFile(new File(mapFileIn));
mapDB.closeFile();
- boolean isValid = result.isSuccess();
-
- if (!isValid) {
- isValid = isMapfile024(mapFileIn);
- }
-
- return isValid;
- }
-
- private static boolean isMapfile024(String mapFileIn) {
- return mapFileIn != null && org.mapsforge.android.mapsold.MapDatabase.isValidMapFile(mapFileIn);
+ return result.isSuccess();
}
@Override
public boolean isSameActivity(final MapSource source1, final MapSource source2) {
- return source1 == source2 ||
- !isMapfile024(Settings.getMapFile()) ||
- (!(source1 instanceof OfflineMapSource) && !(source2 instanceof OfflineMapSource));
+ return source1.getNumericalId() == source2.getNumericalId() || (!(source1 instanceof OfflineMapSource) && !(source2 instanceof OfflineMapSource));
}
@Override
public Class<? extends Activity> getMapClass() {
- final MapSource source = Settings.getMapSource();
- if (source instanceof OfflineMapSource && isMapfile024(Settings.getMapFile())) {
- oldMap = true;
- mapItemFactory = new MapsforgeMapItemFactory024();
- return MapsforgeMapActivity024.class;
- }
- oldMap = false;
mapItemFactory = new MapsforgeMapItemFactory();
return MapsforgeMapActivity.class;
}
@Override
public int getMapViewId() {
- if (oldMap) {
- return R.id.mfmap_old;
- }
return R.id.mfmap;
}
@Override
public int getMapLayoutId() {
- if (oldMap) {
- return R.layout.map_mapsforge_old;
- }
return R.layout.map_mapsforge;
}
@@ -152,7 +124,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
private final String fileName;
- public OfflineMapSource(final String fileName, MapProvider mapProvider, final String name, final MapGeneratorInternal generator) {
+ public OfflineMapSource(final String fileName, final MapProvider mapProvider, final String name, final MapGeneratorInternal generator) {
super(fileName, mapProvider, name, generator);
this.fileName = fileName;
}
@@ -171,7 +143,7 @@ public final class MapsforgeMapProvider extends AbstractMapProvider {
MapProviderFactory.deleteOfflineMapSources();
final Resources resources = CgeoApplication.getInstance().getResources();
final List<String> offlineMaps = getOfflineMaps();
- for (String mapFile : offlineMaps) {
+ for (final String mapFile : offlineMaps) {
final String mapName = StringUtils.capitalize(StringUtils.substringBeforeLast(new File(mapFile).getName(), "."));
registerMapSource(new OfflineMapSource(mapFile, this, mapName + " (" + resources.getString(R.string.map_source_osm_offline) + ")", MapGeneratorInternal.DATABASE_RENDERER));
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapSource.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapSource.java
index 861e567..23e9a23 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapSource.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapSource.java
@@ -9,7 +9,7 @@ class MapsforgeMapSource extends AbstractMapSource {
private final MapGeneratorInternal generator;
- public MapsforgeMapSource(final String id, MapProvider mapProvider, String name, MapGeneratorInternal generator) {
+ public MapsforgeMapSource(final String id, final MapProvider mapProvider, final String name, final MapGeneratorInternal generator) {
super(id, mapProvider, name);
this.generator = generator;
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
index d95cc80..71bf583 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeMapView.java
@@ -1,7 +1,8 @@
package cgeo.geocaching.maps.mapsforge;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
@@ -40,12 +41,12 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
private OnMapDragListener onDragListener;
private final MapsforgeMapController mapController = new MapsforgeMapController(getController(), getMapGenerator().getZoomLevelMax());
- public MapsforgeMapView(Context context, AttributeSet attrs) {
+ public MapsforgeMapView(final Context context, final AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
- private void initialize(Context context) {
+ private void initialize(final Context context) {
if (isInEditMode()) {
return;
}
@@ -56,7 +57,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public void draw(@NonNull Canvas canvas) {
+ public void draw(@NonNull final Canvas canvas) {
try {
// Google Maps and OSM Maps use different zoom levels for the same view.
// Here we don't want the Google Maps compatible zoom level, but the actual one.
@@ -65,13 +66,13 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
super.draw(canvas);
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("MapsforgeMapView.draw", e);
}
}
@Override
- public void displayZoomControls(boolean takeFocus) {
+ public void displayZoomControls(final boolean takeFocus) {
// nothing to do here
}
@@ -83,7 +84,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
@Override
@NonNull
public GeoPointImpl getMapViewCenter() {
- GeoPoint point = getMapPosition().getMapCenter();
+ final GeoPoint point = getMapPosition().getMapCenter();
return new MapsforgeGeoPoint(point.latitudeE6, point.longitudeE6);
}
@@ -103,16 +104,16 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public CachesOverlay createAddMapOverlay(Context context, Drawable drawable) {
+ public CachesOverlay createAddMapOverlay(final Context context, final Drawable drawable) {
- MapsforgeCacheOverlay ovl = new MapsforgeCacheOverlay(context, drawable);
+ final MapsforgeCacheOverlay ovl = new MapsforgeCacheOverlay(context, drawable);
getOverlays().add(ovl);
return ovl.getBase();
}
@Override
- public PositionAndScaleOverlay createAddPositionAndScaleOverlay() {
- MapsforgeOverlay ovl = new MapsforgeOverlay();
+ public PositionAndScaleOverlay createAddPositionAndScaleOverlay(final Geopoint coords, final String geocode) {
+ final MapsforgeOverlay ovl = new MapsforgeOverlay(this, coords, geocode);
getOverlays().add(ovl);
return (PositionAndScaleOverlay) ovl.getBase();
}
@@ -122,12 +123,12 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
int span = 0;
- Projection projection = getProjection();
+ final Projection projection = getProjection();
if (projection != null && getHeight() > 0) {
- GeoPoint low = projection.fromPixels(0, 0);
- GeoPoint high = projection.fromPixels(0, getHeight());
+ final GeoPoint low = projection.fromPixels(0, 0);
+ final GeoPoint high = projection.fromPixels(0, getHeight());
if (low != null && high != null) {
span = Math.abs(high.latitudeE6 - low.latitudeE6);
@@ -142,11 +143,11 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
int span = 0;
- Projection projection = getProjection();
+ final Projection projection = getProjection();
if (projection != null && getWidth() > 0) {
- GeoPoint low = projection.fromPixels(0, 0);
- GeoPoint high = projection.fromPixels(getWidth(), 0);
+ final GeoPoint low = projection.fromPixels(0, 0);
+ final GeoPoint high = projection.fromPixels(getWidth(), 0);
if (low != null && high != null) {
span = Math.abs(high.longitudeE6 - low.longitudeE6);
@@ -191,7 +192,7 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
newMapType = ((MapsforgeMapSource) mapSource).getGenerator();
}
- MapGenerator mapGenerator = MapGeneratorFactory.createMapGenerator(newMapType);
+ final MapGenerator mapGenerator = MapGeneratorFactory.createMapGenerator(newMapType);
// When swapping map sources, make sure we aren't exceeding max zoom. See bug #1535
final int maxZoom = mapGenerator.getZoomLevelMax();
@@ -230,11 +231,11 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
@Override
public void setMapTheme() {
- String customRenderTheme = Settings.getCustomRenderThemeFilePath();
+ final String customRenderTheme = Settings.getCustomRenderThemeFilePath();
if (StringUtils.isNotEmpty(customRenderTheme)) {
try {
setRenderTheme(new File(customRenderTheme));
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException ignored) {
Toast.makeText(
getContext(),
getContext().getResources().getString(R.string.warn_rendertheme_missing),
@@ -247,38 +248,38 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public void repaintRequired(GeneralOverlay overlay) {
+ public void repaintRequired(final GeneralOverlay overlay) {
if (null == overlay) {
invalidate();
} else {
try {
- Overlay ovl = (Overlay) overlay.getOverlayImpl();
+ final Overlay ovl = (Overlay) overlay.getOverlayImpl();
if (ovl != null) {
ovl.requestRedraw();
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("MapsforgeMapView.repaintRequired", e);
}
}
}
@Override
- public void setOnDragListener(OnMapDragListener onDragListener) {
+ public void setOnDragListener(final OnMapDragListener onDragListener) {
this.onDragListener = onDragListener;
}
@Override
- public boolean onTouchEvent(MotionEvent ev) {
+ public boolean onTouchEvent(final MotionEvent ev) {
gestureDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
private class GestureListener extends SimpleOnGestureListener {
@Override
- public boolean onDoubleTap(MotionEvent e) {
+ public boolean onDoubleTap(final MotionEvent e) {
if (onDragListener != null) {
onDragListener.onDrag();
}
@@ -286,8 +287,8 @@ public class MapsforgeMapView extends MapView implements MapViewImpl {
}
@Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
+ public boolean onScroll(final MotionEvent e1, final MotionEvent e2,
+ final float distanceX, final float distanceY) {
if (onDragListener != null) {
onDragListener.onDrag();
}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
index 3df4ab0..3926eb6 100644
--- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
+++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java
@@ -1,5 +1,6 @@
package cgeo.geocaching.maps.mapsforge;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
@@ -17,15 +18,15 @@ import java.util.concurrent.locks.ReentrantLock;
public class MapsforgeOverlay extends Overlay implements OverlayImpl {
private PositionAndScaleOverlay overlayBase = null;
- private Lock lock = new ReentrantLock();
+ private final Lock lock = new ReentrantLock();
- public MapsforgeOverlay() {
- overlayBase = new PositionAndScaleOverlay(this);
+ public MapsforgeOverlay(final MapViewImpl mapView, final Geopoint coords, final String geocode) {
+ overlayBase = new PositionAndScaleOverlay(this, mapView, coords, geocode);
}
@Override
- protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- Projection projection, byte drawZoomLevel) {
+ protected void drawOverlayBitmap(final Canvas canvas, final Point drawPosition,
+ final Projection projection, final byte drawZoomLevel) {
if (overlayBase != null) {
overlayBase.drawOverlayBitmap(canvas, drawPosition, new MapsforgeMapProjection(projection), drawZoomLevel);
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
deleted file mode 100644
index a8111ed..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlay.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.interfaces.ItemizedOverlayImpl;
-import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
-import cgeo.geocaching.maps.interfaces.MapViewImpl;
-
-import org.mapsforge.android.mapsold.ItemizedOverlay;
-import org.mapsforge.android.mapsold.Projection;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Point;
-import android.graphics.drawable.Drawable;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class MapsforgeCacheOverlay extends ItemizedOverlay<MapsforgeCacheOverlayItem> implements ItemizedOverlayImpl {
-
- private CachesOverlay base;
- private Lock lock = new ReentrantLock();
-
- public MapsforgeCacheOverlay(Context contextIn, Drawable markerIn) {
- super(boundCenterBottom(markerIn));
- base = new CachesOverlay(this, contextIn);
- }
-
- @Override
- public CachesOverlay getBase() {
- return base;
- }
-
- @Override
- protected MapsforgeCacheOverlayItem createItem(int i) {
- if (base == null) {
- return null;
- }
-
- return (MapsforgeCacheOverlayItem) base.createItem(i);
- }
-
- @Override
- public int size() {
- if (base == null) {
- return 0;
- }
-
- return base.size();
- }
-
- @Override
- protected boolean onTap(int arg0) {
- if (base == null) {
- return false;
- }
-
- return base.onTap(arg0);
- }
-
- @Override
- protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- Projection projection, byte drawZoomLevel) {
- base.drawOverlayBitmap(canvas, drawPosition, new MapsforgeMapProjection(projection), drawZoomLevel);
- }
-
- @Override
- public void superPopulate() {
- populate();
- }
-
- @Override
- public Drawable superBoundCenterBottom(Drawable marker) {
- return ItemizedOverlay.boundCenterBottom(marker);
- }
-
- @Override
- public void superSetLastFocusedItemIndex(int i) {
- // nothing to do
- }
-
- @Override
- public boolean superOnTap(int index) {
- return super.onTap(index);
- }
-
- @Override
- public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
- // nothing to do here...
- }
-
- @Override
- public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
- MapProjectionImpl projection, byte drawZoomLevel) {
- super.drawOverlayBitmap(canvas, drawPosition, (Projection) projection.getImpl(), drawZoomLevel);
- }
-
- @Override
- public void lock() {
- lock.lock();
- }
-
- @Override
- public void unlock() {
- lock.unlock();
- }
-
- @Override
- public MapViewImpl getMapViewImpl() {
- return (MapViewImpl) internalMapView;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java
deleted file mode 100644
index 4e4a358..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeCacheOverlayItem.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
-
-import org.mapsforge.android.mapsold.GeoPoint;
-import org.mapsforge.android.mapsold.OverlayItem;
-
-import android.graphics.drawable.Drawable;
-
-public class MapsforgeCacheOverlayItem extends OverlayItem implements CachesOverlayItemImpl {
- final private IWaypoint coord;
- final private boolean applyDistanceRule;
-
- public MapsforgeCacheOverlayItem(IWaypoint coordinate, boolean applyDistanceRule) {
- super(new GeoPoint(coordinate.getCoords().getLatitudeE6(), coordinate.getCoords().getLongitudeE6()), coordinate.getName(), "");
-
- this.coord = coordinate;
- this.applyDistanceRule = applyDistanceRule;
- }
-
- @Override
- public IWaypoint getCoord() {
- return coord;
- }
-
- @Override
- public Drawable getMarker(int index) {
- return getMarker();
- }
-
- @Override
- public boolean applyDistanceRule() {
- return applyDistanceRule;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeGeoPoint.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeGeoPoint.java
deleted file mode 100644
index c801e3f..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeGeoPoint.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-
-import org.mapsforge.android.mapsold.GeoPoint;
-
-public class MapsforgeGeoPoint extends GeoPoint implements GeoPointImpl {
-
- public MapsforgeGeoPoint(int latitudeE6, int longitudeE6) {
- super(latitudeE6, longitudeE6);
- }
-
- @Override
- public Geopoint getCoords() {
- return new Geopoint(getLatitudeE6() / 1e6, getLongitudeE6() / 1e6);
- }
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java
deleted file mode 100644
index daeb2b8..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapActivity024.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.activity.FilteredActivity;
-import cgeo.geocaching.maps.AbstractMap;
-import cgeo.geocaching.maps.CGeoMap;
-import cgeo.geocaching.maps.interfaces.MapActivityImpl;
-
-import org.mapsforge.android.mapsold.MapActivity;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-
-public class MapsforgeMapActivity024 extends MapActivity implements MapActivityImpl, FilteredActivity {
-
- private AbstractMap mapBase;
-
- public MapsforgeMapActivity024() {
- mapBase = new CGeoMap(this);
- }
-
- @Override
- public Activity getActivity() {
- return this;
- }
-
- @Override
- protected void onCreate(Bundle icicle) {
- mapBase.onCreate(icicle);
- }
-
- @Override
- protected void onSaveInstanceState(final Bundle outState) {
- mapBase.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onDestroy() {
- mapBase.onDestroy();
- }
-
- @Override
- protected void onPause() {
- mapBase.onPause();
- }
-
- @Override
- protected void onResume() {
- mapBase.onResume();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- return mapBase.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- return mapBase.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- return mapBase.onPrepareOptionsMenu(menu);
- }
-
- @Override
- protected void onStop() {
- mapBase.onStop();
- }
-
- @Override
- public void superOnCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public boolean superOnCreateOptionsMenu(Menu menu) {
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public void superOnDestroy() {
- super.onDestroy();
- }
-
- @Override
- public boolean superOnOptionsItemSelected(MenuItem item) {
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public void superOnResume() {
- super.onResume();
- }
-
- @Override
- public void superOnStop() {
- super.onStop();
- }
-
- @Override
- public void superOnPause() {
- super.onPause();
- }
-
- @Override
- public boolean superOnPrepareOptionsMenu(Menu menu) {
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public void navigateUp(View view) {
- ActivityMixin.navigateUp(this);
- }
-
- @Override
- public void showFilterMenu(View view) {
- // do nothing, the filter bar only shows the global filter
- }
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapController.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapController.java
deleted file mode 100644
index db33d56..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapController.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-import cgeo.geocaching.maps.interfaces.MapControllerImpl;
-
-import org.mapsforge.android.mapsold.GeoPoint;
-import org.mapsforge.android.mapsold.MapController;
-
-public class MapsforgeMapController implements MapControllerImpl {
-
- private MapController mapController;
- private int maxZoomLevel;
-
- public MapsforgeMapController(MapController mapControllerIn, int maxZoomLevelIn) {
- mapController = mapControllerIn;
- maxZoomLevel = maxZoomLevelIn;
- }
-
- @Override
- public void animateTo(GeoPointImpl geoPoint) {
- mapController.setCenter(castToGeoPointImpl(geoPoint));
- }
-
- private static GeoPoint castToGeoPointImpl(GeoPointImpl geoPoint) {
- assert geoPoint instanceof GeoPoint;
- return (GeoPoint) geoPoint;
- }
-
- @Override
- public void setCenter(GeoPointImpl geoPoint) {
- mapController.setCenter(castToGeoPointImpl(geoPoint));
- }
-
- /**
- * Set the map zoom level to mapzoom-1 or maxZoomLevel, whichever is least
- * mapzoom-1 is used to be compatible with Google Maps zoom levels
- */
- @Override
- public void setZoom(int mapzoom) {
- // Google Maps and OSM Maps use different zoom levels for the same view.
- // All OSM Maps zoom levels are offset by 1 so they match Google Maps.
- mapController.setZoom(Math.min(mapzoom - 1, maxZoomLevel));
- }
-
- @Override
- public void zoomToSpan(int latSpanE6, int lonSpanE6) {
-
- if (latSpanE6 != 0 && lonSpanE6 != 0) {
- // calculate zoomlevel
- int distDegree = Math.max(latSpanE6, lonSpanE6);
- int zoomLevel = (int) Math.floor(Math.log(360.0 * 1e6 / distDegree) / Math.log(2));
- mapController.setZoom(zoomLevel + 1);
- }
- }
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java
deleted file mode 100644
index 4f1d34c..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapItemFactory024.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.IWaypoint;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.maps.interfaces.CachesOverlayItemImpl;
-import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-import cgeo.geocaching.maps.interfaces.MapItemFactory;
-
-public class MapsforgeMapItemFactory024 implements MapItemFactory {
-
- @Override
- public GeoPointImpl getGeoPointBase(final Geopoint coords) {
- return new MapsforgeGeoPoint(coords.getLatitudeE6(), coords.getLongitudeE6());
- }
-
- @Override
- public CachesOverlayItemImpl getCachesOverlayItem(final IWaypoint coordinate, boolean applyDistanceRule) {
- return new MapsforgeCacheOverlayItem(coordinate, applyDistanceRule);
- }
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapProjection.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapProjection.java
deleted file mode 100644
index 9d36b7d..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapProjection.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
-
-import org.mapsforge.android.mapsold.GeoPoint;
-import org.mapsforge.android.mapsold.Projection;
-
-import android.graphics.Point;
-
-public class MapsforgeMapProjection implements MapProjectionImpl {
-
- private Projection projection;
-
- public MapsforgeMapProjection(Projection projectionIn) {
- projection = projectionIn;
- }
-
- @Override
- public void toPixels(GeoPointImpl leftGeo, Point left) {
- projection.toPixels((GeoPoint) leftGeo, left);
- }
-
- @Override
- public Object getImpl() {
- return projection;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
deleted file mode 100644
index 8dd15fc..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeMapView024.java
+++ /dev/null
@@ -1,254 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Viewport;
-import cgeo.geocaching.maps.CachesOverlay;
-import cgeo.geocaching.maps.PositionAndScaleOverlay;
-import cgeo.geocaching.maps.interfaces.GeneralOverlay;
-import cgeo.geocaching.maps.interfaces.GeoPointImpl;
-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.settings.Settings;
-import cgeo.geocaching.utils.Log;
-
-import org.eclipse.jdt.annotation.NonNull;
-import org.mapsforge.android.mapsold.GeoPoint;
-import org.mapsforge.android.mapsold.MapDatabase;
-import org.mapsforge.android.mapsold.MapView;
-import org.mapsforge.android.mapsold.MapViewMode;
-import org.mapsforge.android.mapsold.Overlay;
-import org.mapsforge.android.mapsold.Projection;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.MotionEvent;
-import android.widget.Toast;
-public class MapsforgeMapView024 extends MapView implements MapViewImpl {
- private GestureDetector gestureDetector;
- private OnMapDragListener onDragListener;
- private final MapsforgeMapController mapController = new MapsforgeMapController(getController(), getMaxZoomLevel());
-
- public MapsforgeMapView024(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize(context);
- }
-
- private void initialize(Context context) {
- if (isInEditMode()) {
- return;
- }
- gestureDetector = new GestureDetector(context, new GestureListener());
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- try {
- // Google Maps and OSM Maps use different zoom levels for the same view.
- // Here we don't want the Google Maps compatible zoom level, but the actual one.
- if (getActualMapZoomLevel() > 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
- getController().setZoom(22);
- }
-
- super.draw(canvas);
- } catch (Exception e) {
- Log.e("MapsforgeMapView024.draw", e);
- }
- }
-
- @Override
- public void displayZoomControls(boolean takeFocus) {
- // nothing to do here
- }
-
- @Override
- public MapControllerImpl getMapController() {
- return mapController;
- }
-
- @Override
- @NonNull
- public GeoPointImpl getMapViewCenter() {
- GeoPoint point = getMapCenter();
- return new MapsforgeGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
- }
-
- @Override
- public Viewport getViewport() {
- return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6);
- }
-
- @Override
- public void clearOverlays() {
- getOverlays().clear();
- }
-
- @Override
- public MapProjectionImpl getMapProjection() {
- return new MapsforgeMapProjection(getProjection());
- }
-
- @Override
- public CachesOverlay createAddMapOverlay(Context context, Drawable drawable) {
-
- MapsforgeCacheOverlay ovl = new MapsforgeCacheOverlay(context, drawable);
- getOverlays().add(ovl);
- return ovl.getBase();
- }
-
- @Override
- public PositionAndScaleOverlay createAddPositionAndScaleOverlay() {
- MapsforgeOverlay ovl = new MapsforgeOverlay();
- getOverlays().add(ovl);
- return (PositionAndScaleOverlay) ovl.getBase();
- }
-
- @Override
- public int getLatitudeSpan() {
-
- int span = 0;
-
- Projection projection = getProjection();
-
- if (projection != null && getHeight() > 0) {
-
- GeoPoint low = projection.fromPixels(0, 0);
- GeoPoint high = projection.fromPixels(0, getHeight());
-
- if (low != null && high != null) {
- span = Math.abs(high.getLatitudeE6() - low.getLatitudeE6());
- }
- }
-
- return span;
- }
-
- @Override
- public int getLongitudeSpan() {
-
- int span = 0;
-
- Projection projection = getProjection();
-
- if (projection != null && getWidth() > 0) {
- GeoPoint low = projection.fromPixels(0, 0);
- GeoPoint high = projection.fromPixels(getWidth(), 0);
-
- if (low != null && high != null) {
- span = Math.abs(high.getLongitudeE6() - low.getLongitudeE6());
- }
- }
-
- return span;
- }
-
- @Override
- public void preLoad() {
- // Nothing to do here
- }
-
- /**
- * Get the map zoom level which is compatible with Google Maps.
- *
- * @return the current map zoom level +1
- */
- @Override
- public int getMapZoomLevel() {
- // Google Maps and OSM Maps use different zoom levels for the same view.
- // All OSM Maps zoom levels are offset by 1 so they match Google Maps.
- return getZoomLevel() + 1;
- }
-
- /**
- * Get the actual map zoom level
- *
- * @return the current map zoom level with no adjustments
- */
- private int getActualMapZoomLevel() {
- return getZoomLevel();
- }
-
- @Override
- public void setMapSource() {
- setMapViewMode(MapViewMode.CANVAS_RENDERER);
- setMapFile(Settings.getMapFile());
- if (!MapDatabase.isValidMapFile(Settings.getMapFile())) {
- Log.e("MapsforgeMapView024: Invalid map file");
- }
- Toast.makeText(
- getContext(),
- getContext().getResources().getString(R.string.warn_deprecated_mapfile),
- Toast.LENGTH_LONG)
- .show();
- }
-
- @Override
- public void repaintRequired(GeneralOverlay overlay) {
-
- if (null == overlay) {
- invalidate();
- } else {
- try {
- Overlay ovl = (Overlay) overlay.getOverlayImpl();
-
- if (ovl != null) {
- ovl.requestRedraw();
- }
-
- } catch (Exception e) {
- Log.e("MapsforgeMapView024.repaintRequired", e);
- }
- }
- }
-
- @Override
- public void setOnDragListener(OnMapDragListener onDragListener) {
- this.onDragListener = onDragListener;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- gestureDetector.onTouchEvent(ev);
- return super.onTouchEvent(ev);
- }
-
- private class GestureListener extends SimpleOnGestureListener {
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- if (onDragListener != null) {
- onDragListener.onDrag();
- }
- return true;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- if (onDragListener != null) {
- onDragListener.onDrag();
- }
- return super.onScroll(e1, e2, distanceX, distanceY);
- }
- }
-
- @Override
- public boolean needsInvertedColors() {
- return false;
- }
-
- @Override
- public boolean hasMapThemes() {
- // not supported
- return false;
- }
-
- @Override
- public void setMapTheme() {
- // not supported
- }
-}
diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
deleted file mode 100644
index bfb3548..0000000
--- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package cgeo.geocaching.maps.mapsforge.v024;
-
-import cgeo.geocaching.maps.PositionAndScaleOverlay;
-import cgeo.geocaching.maps.interfaces.GeneralOverlay;
-import cgeo.geocaching.maps.interfaces.MapViewImpl;
-import cgeo.geocaching.maps.interfaces.OverlayImpl;
-
-import org.mapsforge.android.mapsold.Overlay;
-import org.mapsforge.android.mapsold.Projection;
-
-import android.graphics.Canvas;
-import android.graphics.Point;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class MapsforgeOverlay extends Overlay implements OverlayImpl {
-
- private PositionAndScaleOverlay overlayBase = null;
- private Lock lock = new ReentrantLock();
-
- public MapsforgeOverlay() {
- overlayBase = new PositionAndScaleOverlay(this);
- }
-
- @Override
- protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
- Projection projection, byte drawZoomLevel) {
-
- if (overlayBase != null) {
- overlayBase.drawOverlayBitmap(canvas, drawPosition, new MapsforgeMapProjection(projection), drawZoomLevel);
- }
- }
-
- public GeneralOverlay getBase() {
- return overlayBase;
- }
-
- @Override
- public void lock() {
- lock.lock();
- }
-
- @Override
- public void unlock() {
- lock.unlock();
- }
-
- @Override
- public MapViewImpl getMapViewImpl() {
- return (MapViewImpl) internalMapView;
- }
-
-}
diff --git a/main/src/cgeo/geocaching/network/AndroidBeam.java b/main/src/cgeo/geocaching/network/AndroidBeam.java
new file mode 100644
index 0000000..68b8f94
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/AndroidBeam.java
@@ -0,0 +1,93 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.CgeoApplication;
+
+import org.apache.commons.io.Charsets;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+import android.nfc.NfcAdapter.CreateNdefMessageCallback;
+import android.nfc.NfcEvent;
+import android.os.Build;
+
+/**
+ * utility class managing all NFC related tasks
+ */
+public class AndroidBeam {
+
+ private AndroidBeam() {
+ // utility class
+ }
+
+ /**
+ * returns the URI transmitted via Android Beam, or the URI contained in the data of the intent
+ */
+ @Nullable
+ public static Uri getUri(final Intent intent) {
+ if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
+ final NdefMessage msg = (NdefMessage) intent.getExtras().getParcelableArray(NfcAdapter.EXTRA_NDEF_MESSAGES)[0];
+ return Uri.parse("http://" + new String(msg.getRecords()[0].getPayload(), Charsets.UTF_8));
+ }
+ return intent.getData();
+ }
+
+ // Do not support older devices than Android 4.0
+ // Although there even are 2.3 devices (Nexus S)
+ // these are so few that we don't want to deal with the older (non Android Beam) API
+
+ public interface ActivitySharingInterface {
+ /** Return an URL that represent the current activity for sharing or null for no sharing. */
+ @Nullable
+ public String getAndroidBeamUri();
+ }
+
+ public static void enable(final Activity activity, final ActivitySharingInterface sharingInterface) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ initializeICSAndroidBeam(activity, createMessageCallback(sharingInterface));
+ }
+ }
+
+ public static void disable(final Activity activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ initializeICSAndroidBeam(activity, null);
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private static void initializeICSAndroidBeam(final Activity activity, final CreateNdefMessageCallback messageCallback) {
+ final NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
+ if (nfcAdapter == null) {
+ return;
+ }
+ nfcAdapter.setNdefPushMessageCallback(messageCallback, activity);
+
+ }
+
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+ private static CreateNdefMessageCallback createMessageCallback(final ActivitySharingInterface sharingInterface) {
+ return new NfcAdapter.CreateNdefMessageCallback() {
+ @Override
+ public NdefMessage createNdefMessage(final NfcEvent event) {
+ String uri = sharingInterface.getAndroidBeamUri();
+ if (uri == null) {
+ return null;
+ }
+ // normalize our modified URLs for beaming
+ uri = StringUtils.replace(uri, "geocaching.com//", "geocaching.com/");
+ final NdefRecord[] records = {
+ NdefRecord.createUri(uri),
+ NdefRecord.createApplicationRecord(CgeoApplication.getInstance().getPackageName())
+ };
+ return new NdefMessage(records);
+ }
+ };
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/network/Cookies.java b/main/src/cgeo/geocaching/network/Cookies.java
index bcfc893..27013ba 100644
--- a/main/src/cgeo/geocaching/network/Cookies.java
+++ b/main/src/cgeo/geocaching/network/Cookies.java
@@ -29,7 +29,7 @@ public abstract class Cookies {
}
public static String dumpCookieStore() {
- StringBuilder cookies = new StringBuilder();
+ final StringBuilder cookies = new StringBuilder();
for (final Cookie cookie : cookieStore.getCookies()) {
cookies.append(cookie.getName());
cookies.append('=');
diff --git a/main/src/cgeo/geocaching/network/DownloadProgress.java b/main/src/cgeo/geocaching/network/DownloadProgress.java
new file mode 100644
index 0000000..e0f20dc
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/DownloadProgress.java
@@ -0,0 +1,15 @@
+package cgeo.geocaching.network;
+
+public class DownloadProgress {
+
+ private DownloadProgress() {
+ // Do not instantiate
+ }
+
+ public static final int MSG_DONE = -1;
+ public static final int MSG_SERVER_FAIL = -2;
+ public static final int MSG_NO_REGISTRATION = -3;
+ public static final int MSG_WAITING = 0;
+ public static final int MSG_LOADING = 1;
+ public static final int MSG_LOADED = 2;
+}
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 31edc9f..fe67af4 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -12,13 +12,13 @@ import cgeo.geocaching.utils.ImageUtils;
import cgeo.geocaching.utils.ImageUtils.ContainerDrawable;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.RxUtils;
+import cgeo.geocaching.utils.RxUtils.ObservableCache;
import ch.boye.httpclientandroidlib.HttpResponse;
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;
@@ -44,22 +44,14 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
-public class HtmlImage implements Html.ImageGetter {
+/**
+ * All-purpose image getter that can also be used as a ImageGetter interface when displaying caches.
+ */
- // 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, unless a view has been provided. If it has, then a dummy drawable is returned
- // and is updated when the image is available, possibly several times if we had a stale copy of the image
- // and then got a new one from the network.
+public class HtmlImage implements Html.ImageGetter {
private static final String[] BLOCKED = new String[] {
"gccounter.de",
@@ -79,9 +71,9 @@ public class HtmlImage implements Html.ImageGetter {
};
public static final String SHARED = "shared";
- final private String geocode;
+ @NonNull final private String geocode;
/**
- * on error: return large error image, if <code>true</code>, otherwise empty 1x1 image
+ * on error: return large error image, if {@code true}, otherwise empty 1x1 image
*/
final private boolean returnErrorImage;
final private int listId;
@@ -89,25 +81,57 @@ public class HtmlImage implements Html.ImageGetter {
final private int maxWidth;
final private int maxHeight;
final private Resources resources;
- final private TextView view;
+ protected final TextView view;
+ final private Map<String, BitmapDrawable> cache = new HashMap<>();
+
+ final private ObservableCache<String, BitmapDrawable> observableCache = new ObservableCache<>(new Func1<String, Observable<BitmapDrawable>>() {
+ @Override
+ public Observable<BitmapDrawable> call(final String url) {
+ return fetchDrawableUncached(url);
+ }
+ });
// Background loading
final private PublishSubject<Observable<String>> loading = PublishSubject.create();
- final private Observable<String> waitForEnd = Observable.merge(loading).publish().refCount();
- final CompositeSubscription subscription = new CompositeSubscription(waitForEnd.subscribe());
+ final private Observable<String> waitForEnd = Observable.merge(loading).cache();
+ final private CompositeSubscription subscription = new CompositeSubscription(waitForEnd.subscribe());
/**
- * Create a new HtmlImage object with different behaviours depending on <tt>onlySave</tt> and <tt>view</tt> values.
+ * Create a new HtmlImage object with different behaviors depending on <tt>onlySave</tt> and <tt>view</tt> values.
+ * There are the three possible use cases:
+ * <ul>
+ * <li>If onlySave is true, {@link #getDrawable(String)} will return <tt>null</tt> immediately and will queue the
+ * image retrieval and saving in the loading subject. Downloads will start in parallel when the blocking
+ * {@link #waitForEndObservable(cgeo.geocaching.utils.CancellableHandler)} method is called, and they can be
+ * cancelled through the given handler.</li>
+ * <li>If <tt>onlySave</tt> is <tt>false</tt> and the instance is called through {@link #fetchDrawable(String)},
+ * 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.</li>
+ * <li>If <tt>onlySave</tt> is <tt>false</tt> and the instance is used as an {@link android.text.Html.ImageGetter},
+ * only the final version of the image will be returned, unless a view has been provided. If it has, then a dummy
+ * drawable is returned and is updated when the image is available, possibly several times if we had a stale copy of
+ * the image and then got a new one from the network.</li>
+ * </ul>
*
- * @param geocode the geocode of the item for which we are requesting the image
- * @param returnErrorImage set to <tt>true</tt> if an error image should be returned in case of a problem,
- * <tt>false</tt> to get a transparent 1x1 image instead
- * @param listId the list this cache belongs to, used to determine if an older image for the offline case can be used or not
- * @param onlySave if set to <tt>true</tt>, {@link #getDrawable(String)} will only fetch and store the image, not return it
- * @param view if non-null, {@link #getDrawable(String)} will return an initially empty drawable which will be redrawn when
- * the image is ready through an invalidation of the given view
+ * @param geocode
+ * the geocode of the item for which we are requesting the image, or {@link #SHARED} to use the shared
+ * cache directory
+ * @param returnErrorImage
+ * set to <tt>true</tt> if an error image should be returned in case of a problem, <tt>false</tt> to get
+ * a transparent 1x1 image instead
+ * @param listId
+ * the list this cache belongs to, used to determine if an older image for the offline case can be used
+ * or not
+ * @param onlySave
+ * if set to <tt>true</tt>, {@link #getDrawable(String)} will only fetch and store the image, not return
+ * it
+ * @param view
+ * if non-null, {@link #getDrawable(String)} will return an initially empty drawable which will be
+ * redrawn when
+ * the image is ready through an invalidation of the given view
*/
- public HtmlImage(final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave, final TextView view) {
+ public HtmlImage(@NonNull final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave, final TextView view) {
this.geocode = geocode;
this.returnErrorImage = returnErrorImage;
this.listId = listId;
@@ -121,12 +145,12 @@ public class HtmlImage implements Html.ImageGetter {
}
/**
- * Create a new HtmlImage object with different behaviours depending on <tt>onlySave</tt> value. No view object
+ * Create a new HtmlImage object with different behaviors depending on <tt>onlySave</tt> value. No view object
* will be tied to this HtmlImage.
*
* For documentation, see {@link #HtmlImage(String, boolean, int, boolean, TextView)}.
*/
- public HtmlImage(final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave) {
+ public HtmlImage(@NonNull final String geocode, final boolean returnErrorImage, final int listId, final boolean onlySave) {
this(geocode, returnErrorImage, listId, onlySave, null);
}
@@ -141,6 +165,9 @@ public class HtmlImage implements Html.ImageGetter {
@Nullable
@Override
public BitmapDrawable getDrawable(final String url) {
+ if (cache.containsKey(url)) {
+ return cache.get(url);
+ }
final Observable<BitmapDrawable> drawable = fetchDrawable(url);
if (onlySave) {
loading.onNext(drawable.map(new Func1<BitmapDrawable, String>() {
@@ -149,30 +176,37 @@ public class HtmlImage implements Html.ImageGetter {
return url;
}
}));
+ cache.put(url, null);
return null;
}
- if (view == null) {
- return drawable.toBlocking().lastOrDefault(null);
- }
+ final BitmapDrawable result = view == null ? drawable.toBlocking().lastOrDefault(null) : getContainerDrawable(drawable);
+ cache.put(url, result);
+ return result;
+ }
+
+ protected BitmapDrawable getContainerDrawable(final Observable<BitmapDrawable> drawable) {
return new ContainerDrawable(view, drawable);
}
- // Caches are loaded from disk on a computation scheduler to avoid using more threads than cores while decoding
- // the image. Downloads happen on downloadScheduler, in parallel with image decoding.
public Observable<BitmapDrawable> fetchDrawable(final String url) {
+ return observableCache.get(url);
+ }
+ // Caches are loaded from disk on a computation scheduler to avoid using more threads than cores while decoding
+ // the image. Downloads happen on downloadScheduler, in parallel with image decoding.
+ private Observable<BitmapDrawable> fetchDrawableUncached(final String url) {
if (StringUtils.isBlank(url) || ImageUtils.containsPattern(url, BLOCKED)) {
- return Observable.from(ImageUtils.getTransparent1x1Drawable(resources));
+ return Observable.just(ImageUtils.getTransparent1x1Drawable(resources));
}
// Explicit local file URLs are loaded from the filesystem regardless of their age. The IO part is short
// enough to make the whole operation on the computation scheduler.
if (FileUtils.isFileUrl(url)) {
- return Observable.defer(new Func0<Observable<? extends BitmapDrawable>>() {
+ return Observable.defer(new Func0<Observable<BitmapDrawable>>() {
@Override
- public Observable<? extends BitmapDrawable> call() {
- final Bitmap bitmap = loadCachedImage(FileUtils.urlToFile(url), true).getLeft();
- return bitmap != null ? Observable.from(ImageUtils.scaleBitmapToFitDisplay(bitmap)) : Observable.<BitmapDrawable>empty();
+ public Observable<BitmapDrawable> call() {
+ final Bitmap bitmap = loadCachedImage(FileUtils.urlToFile(url), true).left;
+ return bitmap != null ? Observable.just(ImageUtils.scaleBitmapToFitDisplay(bitmap)) : Observable.<BitmapDrawable>empty();
}
}).subscribeOn(RxUtils.computationScheduler);
}
@@ -187,9 +221,9 @@ public class HtmlImage implements Html.ImageGetter {
subscriber.add(RxUtils.computationScheduler.createWorker().schedule(new Action0() {
@Override
public void call() {
- final Pair<BitmapDrawable, Boolean> loaded = loadFromDisk();
- final BitmapDrawable bitmap = loaded.getLeft();
- if (loaded.getRight()) {
+ final ImmutablePair<BitmapDrawable, Boolean> loaded = loadFromDisk();
+ final BitmapDrawable bitmap = loaded.left;
+ if (loaded.right) {
subscriber.onNext(bitmap);
subscriber.onCompleted();
return;
@@ -206,14 +240,9 @@ public class HtmlImage implements Html.ImageGetter {
}));
}
- private Pair<BitmapDrawable, Boolean> loadFromDisk() {
- final Pair<Bitmap, Boolean> loadResult = loadImageFromStorage(url, pseudoGeocode, shared);
- final Bitmap bitmap = loadResult.getLeft();
- return new ImmutablePair<>(bitmap != null ?
- ImageUtils.scaleBitmapToFitDisplay(bitmap) :
- null,
- loadResult.getRight()
- );
+ private ImmutablePair<BitmapDrawable, Boolean> loadFromDisk() {
+ final ImmutablePair<Bitmap, Boolean> loadResult = loadImageFromStorage(url, pseudoGeocode, shared);
+ return scaleImage(loadResult);
}
private void downloadAndSave(final Subscriber<? super BitmapDrawable> subscriber) {
@@ -233,27 +262,33 @@ public class HtmlImage implements Html.ImageGetter {
}
if (onlySave) {
subscriber.onCompleted();
- } else {
- RxUtils.computationScheduler.createWorker().schedule(new Action0() {
- @Override
- public void call() {
- final Pair<BitmapDrawable, Boolean> loaded = loadFromDisk();
- final BitmapDrawable image = loaded.getLeft();
- if (image != null) {
- subscriber.onNext(image);
- } else {
- subscriber.onNext(returnErrorImage ?
- new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded)) :
- ImageUtils.getTransparent1x1Drawable(resources));
- }
- subscriber.onCompleted();
- }
- });
+ return;
}
+ RxUtils.computationScheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ final ImmutablePair<BitmapDrawable, Boolean> loaded = loadFromDisk();
+ final BitmapDrawable image = loaded.left;
+ if (image != null) {
+ subscriber.onNext(image);
+ } else {
+ subscriber.onNext(returnErrorImage ?
+ new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, R.drawable.image_not_loaded)) :
+ ImageUtils.getTransparent1x1Drawable(resources));
+ }
+ subscriber.onCompleted();
+ }
+ });
}
});
}
+ @SuppressWarnings("static-method")
+ protected ImmutablePair<BitmapDrawable, Boolean> scaleImage(final ImmutablePair<Bitmap, Boolean> loadResult) {
+ final Bitmap bitmap = loadResult.left;
+ return ImmutablePair.of(bitmap != null ? ImageUtils.scaleBitmapToFitDisplay(bitmap) : null, loadResult.right);
+ }
+
public Observable<String> waitForEndObservable(@Nullable final CancellableHandler handler) {
if (handler != null) {
handler.unsubscribeIfCancelled(subscription);
@@ -319,14 +354,14 @@ public class HtmlImage implements Html.ImageGetter {
* @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
+ * @return A pair whose first element is the bitmap if available, and the second one is <code>true</code> if the image is present and fresh enough.
*/
@NonNull
- private Pair<Bitmap, Boolean> loadImageFromStorage(final String url, final String pseudoGeocode, final boolean forceKeep) {
+ private ImmutablePair<Bitmap, Boolean> loadImageFromStorage(final String url, @NonNull final String pseudoGeocode, final boolean forceKeep) {
try {
final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, false);
- final Pair<Bitmap, Boolean> image = loadCachedImage(file, forceKeep);
- if (image.getRight() || image.getLeft() != null) {
+ final ImmutablePair<Bitmap, Boolean> image = loadCachedImage(file, forceKeep);
+ if (image.right || image.left != null) {
return image;
}
final File fileSec = LocalStorage.getStorageSecFile(pseudoGeocode, url, true);
@@ -334,7 +369,7 @@ public class HtmlImage implements Html.ImageGetter {
} catch (final Exception e) {
Log.w("HtmlImage.loadImageFromStorage", e);
}
- return new ImmutablePair<>(null, false);
+ return ImmutablePair.of((Bitmap) null, false);
}
@Nullable
@@ -366,17 +401,17 @@ public class HtmlImage implements Html.ImageGetter {
*
* @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
+ * @return a pair with <code>true</code> in the second component if the image was there and is fresh enough or <code>false</code> otherwise,
+ * and the image (possibly <code>null</code> if the second component is <code>false</code> and the image
+ * could not be loaded, or if the second 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) {
+ private ImmutablePair<Bitmap, Boolean> loadCachedImage(final File file, final boolean forceKeep) {
if (file.exists()) {
- final boolean freshEnough = listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep;
- if (onlySave) {
- return new ImmutablePair<>(null, true);
+ final boolean freshEnough = listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (System.currentTimeMillis() - (24 * 60 * 60 * 1000)) || forceKeep;
+ if (freshEnough && onlySave) {
+ return ImmutablePair.of((Bitmap) null, true);
}
final BitmapFactory.Options bfOptions = new BitmapFactory.Options();
bfOptions.inTempStorage = new byte[16 * 1024];
@@ -385,12 +420,11 @@ public class HtmlImage implements Html.ImageGetter {
final Bitmap image = BitmapFactory.decodeFile(file.getPath(), bfOptions);
if (image == null) {
Log.e("Cannot decode bitmap from " + file.getPath());
- return new ImmutablePair<>(null, false);
+ return ImmutablePair.of((Bitmap) null, false);
}
- return new ImmutablePair<>(image,
- freshEnough);
+ return ImmutablePair.of(image, freshEnough);
}
- return new ImmutablePair<>(null, false);
+ return ImmutablePair.of((Bitmap) null, false);
}
private void setSampleSize(final File file, final BitmapFactory.Options bfOptions) {
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
index a49b302..7eb6f61 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -1,7 +1,9 @@
package cgeo.geocaching.network;
+import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.files.LocalStorage;
import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.JsonUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.TextUtils;
@@ -26,11 +28,12 @@ import ch.boye.httpclientandroidlib.params.CoreConnectionPNames;
import ch.boye.httpclientandroidlib.params.CoreProtocolPNames;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.util.EntityUtils;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
-import org.json.JSONException;
-import org.json.JSONObject;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -43,6 +46,7 @@ import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
+import java.util.regex.Pattern;
public abstract class Network {
@@ -51,25 +55,25 @@ public abstract class Network {
/** Native user agent, taken from a Android 2.2 Nexus **/
private final static String NATIVE_USER_AGENT = "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
- private static final String PATTERN_PASSWORD = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+";
+ private static final Pattern PATTERN_PASSWORD = Pattern.compile("(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+");
- private final static HttpParams clientParams = new BasicHttpParams();
+ private final static HttpParams CLIENT_PARAMS = new BasicHttpParams();
static {
- clientParams.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, CharEncoding.UTF_8);
- clientParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
- clientParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 90000);
- clientParams.setParameter(ClientPNames.HANDLE_REDIRECTS, true);
+ CLIENT_PARAMS.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, CharEncoding.UTF_8);
+ CLIENT_PARAMS.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
+ CLIENT_PARAMS.setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);
+ CLIENT_PARAMS.setParameter(ClientPNames.HANDLE_REDIRECTS, true);
}
private static String hidePassword(final String message) {
- return message.replaceAll(PATTERN_PASSWORD, "password=***");
+ return PATTERN_PASSWORD.matcher(message).replaceAll("password=***");
}
private static HttpClient getHttpClient() {
final DefaultHttpClient client = new DefaultHttpClient();
client.setCookieStore(Cookies.cookieStore);
- client.setParams(clientParams);
+ client.setParams(CLIENT_PARAMS);
client.setRedirectStrategy(new LaxRedirectStrategy());
return new DecompressingHttpClient(client);
}
@@ -91,7 +95,7 @@ public abstract class Network {
*
* @param uri the URI to request
* @param params the parameters to add to the POST request
- * @params headers the headers to add to the request
+ * @param headers the headers to add to the request
* @return the HTTP response, or null in case of an encoding error params
*/
@Nullable
@@ -107,14 +111,14 @@ public abstract class Network {
* @return the HTTP response, or null in case of an encoding error params
*/
@Nullable
- public static HttpResponse postJsonRequest(final String uri, final JSONObject json) {
- HttpPost request = new HttpPost(uri);
+ public static HttpResponse postJsonRequest(final String uri, final ObjectNode json) {
+ final HttpPost request = new HttpPost(uri);
request.addHeader("Content-Type", "application/json; charset=utf-8");
if (json != null) {
try {
request.setEntity(new StringEntity(json.toString(), CharEncoding.UTF_8));
- } catch (UnsupportedEncodingException e) {
- Log.e("postJsonRequest:JSON Entity: UnsupportedEncodingException");
+ } catch (final UnsupportedEncodingException e) {
+ Log.e("postJsonRequest:JSON Entity: UnsupportedEncodingException", e);
return null;
}
}
@@ -170,7 +174,7 @@ public abstract class Network {
@Nullable
private static HttpResponse request(final String method, final String uri,
@Nullable final Parameters params, @Nullable final Parameters headers, @Nullable final File cacheFile) {
- HttpRequestBase request;
+ final HttpRequestBase request;
if (method.equals("GET")) {
final String fullUri = params == null ? uri : Uri.parse(uri).buildUpon().encodedQuery(params.toString()).build().toString();
request = new HttpGet(fullUri);
@@ -221,6 +225,10 @@ public abstract class Network {
*/
@Nullable
private static HttpResponse doLogRequest(final HttpRequestBase request) {
+ if (!isNetworkConnected()) {
+ return null;
+ }
+
final String reqLogStr = request.getMethod() + " " + hidePassword(request.getURI().toString());
Log.d(reqLogStr);
@@ -228,7 +236,7 @@ public abstract class Network {
final long before = System.currentTimeMillis();
try {
final HttpResponse response = client.execute(request);
- int status = response.getStatusLine().getStatusCode();
+ final int status = response.getStatusLine().getStatusCode();
if (status == 200) {
Log.d(status + formatTimeSpan(before) + reqLogStr);
} else {
@@ -344,14 +352,14 @@ public abstract class Network {
* @return a JSON object if the request was successful and the body could be decoded, <code>null</code> otherwise
*/
@Nullable
- public static JSONObject requestJSON(final String uri, @Nullable final Parameters params) {
+ public static ObjectNode requestJSON(final String uri, @Nullable final Parameters params) {
final HttpResponse response = request("GET", uri, params, new Parameters("Accept", "application/json, text/javascript, */*; q=0.01"), null);
final String responseData = getResponseData(response, false);
if (responseData != null) {
try {
- return new JSONObject(responseData);
- } catch (final JSONException e) {
- Log.w("Network.requestJSON", e);
+ return (ObjectNode) JsonUtils.reader.readTree(responseData);
+ } catch (final IOException e) {
+ Log.w("requestJSON", e);
}
}
@@ -369,7 +377,7 @@ public abstract class Network {
if (!isSuccess(response)) {
return null;
}
- assert(response != null);
+ assert response != null;
final HttpEntity entity = response.getEntity();
if (entity == null) {
return null;
@@ -383,11 +391,11 @@ public abstract class Network {
}
@Nullable
- private static String getResponseDataNoError(final HttpResponse response, boolean replaceWhitespace) {
+ private static String getResponseDataNoError(final HttpResponse response, final boolean replaceWhitespace) {
try {
- String data = EntityUtils.toString(response.getEntity(), CharEncoding.UTF_8);
+ final String data = EntityUtils.toString(response.getEntity(), CharEncoding.UTF_8);
return replaceWhitespace ? TextUtils.replaceWhitespace(data) : data;
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("getResponseData", e);
return null;
}
@@ -420,7 +428,7 @@ public abstract class Network {
* @return the body if the response comes from a successful HTTP request, <code>null</code> otherwise
*/
@Nullable
- public static String getResponseData(@Nullable final HttpResponse response, boolean replaceWhitespace) {
+ public static String getResponseData(@Nullable final HttpResponse response, final boolean replaceWhitespace) {
if (!isSuccess(response)) {
return null;
}
@@ -429,7 +437,7 @@ public abstract class Network {
}
@Nullable
- public static String rfc3986URLEncode(String text) {
+ public static String rfc3986URLEncode(final String text) {
final String encoded = encode(text);
return encoded != null ? StringUtils.replace(encoded.replace("+", "%20"), "%7E", "~") : null;
}
@@ -438,7 +446,7 @@ public abstract class Network {
public static String decode(final String text) {
try {
return URLDecoder.decode(text, CharEncoding.UTF_8);
- } catch (UnsupportedEncodingException e) {
+ } catch (final UnsupportedEncodingException e) {
Log.e("Network.decode", e);
}
return null;
@@ -448,25 +456,26 @@ public abstract class Network {
public static String encode(final String text) {
try {
return URLEncoder.encode(text, CharEncoding.UTF_8);
- } catch (UnsupportedEncodingException e) {
+ } catch (final UnsupportedEncodingException e) {
Log.e("Network.encode", e);
}
return null;
}
+ private static ConnectivityManager connectivityManager = null;
+
/**
* Checks if the device has network connection.
*
- * @param context
- * context of the application, cannot be null
- *
* @return <code>true</code> if the device is connected to the network.
*/
- public static boolean isNetworkConnected(Context context) {
- ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeNetwork = conMan.getActiveNetworkInfo();
-
- return activeNetwork != null && activeNetwork.isConnected();
+ public static boolean isNetworkConnected() {
+ if (connectivityManager == null) {
+ // Concurrent assignment would not hurt
+ connectivityManager = (ConnectivityManager) CgeoApplication.getInstance().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+ final NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+ return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}
diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java
index cfc62fc..4f1fcc0 100644
--- a/main/src/cgeo/geocaching/network/OAuth.java
+++ b/main/src/cgeo/geocaching/network/OAuth.java
@@ -6,10 +6,8 @@ import ch.boye.httpclientandroidlib.NameValuePair;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
public class OAuth {
@@ -18,16 +16,15 @@ public class OAuth {
final String method,
final boolean https,
final Parameters params,
- @Nullable final String token,
- @Nullable final String tokenSecret,
+ final OAuthTokens tokens,
final String consumerKey,
final String consumerSecret) {
params.put(
"oauth_consumer_key", consumerKey,
"oauth_nonce", CryptUtils.md5(Long.toString(System.currentTimeMillis())),
"oauth_signature_method", "HMAC-SHA1",
- "oauth_timestamp", Long.toString(new Date().getTime() / 1000),
- "oauth_token", StringUtils.defaultString(token),
+ "oauth_timestamp", Long.toString(System.currentTimeMillis() / 1000),
+ "oauth_token", StringUtils.defaultString(tokens.getTokenPublic()),
"oauth_version", "1.0");
params.sort();
@@ -36,19 +33,16 @@ public class OAuth {
paramsEncoded.add(nameValue.getName() + "=" + OAuth.percentEncode(nameValue.getValue()));
}
- final String keysPacked = consumerSecret + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them!
+ final String keysPacked = consumerSecret + "&" + StringUtils.defaultString(tokens.getTokenSecret()); // both even if empty some of them!
final @NonNull String joinedParams = StringUtils.join(paramsEncoded.toArray(), '&');
final String requestPacked = method + "&" + OAuth.percentEncode((https ? "https" : "http") + "://" + host + path) + "&" + OAuth.percentEncode(joinedParams);
params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked)));
}
/**
- * percent encode following http://tools.ietf.org/html/rfc5849#section-3.6
- *
- * @param url
- * @return
+ * Percent encode following http://tools.ietf.org/html/rfc5849#section-3.6
*/
- static String percentEncode(@NonNull String url) {
+ static String percentEncode(@NonNull final String url) {
return StringUtils.replace(Network.rfc3986URLEncode(url), "*", "%2A");
}
}
diff --git a/main/src/cgeo/geocaching/network/OAuthTokens.java b/main/src/cgeo/geocaching/network/OAuthTokens.java
new file mode 100644
index 0000000..9f45e7f
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/OAuthTokens.java
@@ -0,0 +1,38 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.connector.oc.OCApiConnector;
+import cgeo.geocaching.settings.Settings;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.util.Pair;
+
+public class OAuthTokens extends Pair<String, String> {
+
+ public OAuthTokens(@NonNull final OCApiConnector connector) {
+ this(Settings.getTokenPair(connector.getTokenPublicPrefKeyId(), connector.getTokenSecretPrefKeyId()));
+ }
+
+ public OAuthTokens(final ImmutablePair<String, String> tokenPair) {
+ this(tokenPair.left, tokenPair.right);
+ }
+
+ public OAuthTokens(final String pub, final String secret) {
+ super(pub, secret);
+ }
+
+ public boolean isValid() {
+ return StringUtils.isNotBlank(getTokenPublic()) && StringUtils.isNotBlank(getTokenSecret());
+ }
+
+ public String getTokenPublic() {
+ return first;
+ }
+
+ public String getTokenSecret() {
+ return second;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/network/Parameters.java b/main/src/cgeo/geocaching/network/Parameters.java
index 9cb0da5..d6285da 100644
--- a/main/src/cgeo/geocaching/network/Parameters.java
+++ b/main/src/cgeo/geocaching/network/Parameters.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.network;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.client.utils.URLEncodedUtils;
import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
+
import org.apache.commons.lang3.CharEncoding;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/network/Send2CgeoDownloader.java b/main/src/cgeo/geocaching/network/Send2CgeoDownloader.java
new file mode 100644
index 0000000..5f5be56
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/Send2CgeoDownloader.java
@@ -0,0 +1,70 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.CancellableHandler;
+import cgeo.geocaching.utils.RxUtils;
+
+import ch.boye.httpclientandroidlib.HttpResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+import rx.Scheduler.Worker;
+import rx.functions.Action0;
+
+import java.util.concurrent.TimeUnit;
+
+public class Send2CgeoDownloader {
+
+ private Send2CgeoDownloader() {
+ // Do not instantiate
+ }
+
+ /**
+ * Asynchronously load caches from the send2cgeo server.
+ *
+ * @param handler the handler to which progress information will be sent
+ * @param listId the list into which caches will be stored
+ */
+ public static void loadFromWeb(final CancellableHandler handler, final int listId) {
+ final Worker worker = RxUtils.networkScheduler.createWorker();
+ handler.unsubscribeIfCancelled(worker);
+ worker.schedule(new Action0() {
+ private final Parameters PARAMS = new Parameters("code", StringUtils.defaultString(Settings.getWebDeviceCode()));
+ private long baseTime = System.currentTimeMillis();
+
+ @Override
+ public void call() {
+ if (System.currentTimeMillis() - baseTime >= 3 * 60000) { // maximum: 3 minutes
+ handler.sendEmptyMessage(DownloadProgress.MSG_DONE);
+ return;
+ }
+
+ // Download new code
+ final HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", PARAMS);
+
+ if (responseFromWeb != null && responseFromWeb.getStatusLine().getStatusCode() == 200) {
+ final String response = Network.getResponseData(responseFromWeb);
+ if (response != null && response.length() > 2) {
+ handler.sendMessage(handler.obtainMessage(DownloadProgress.MSG_LOADING, response));
+ Geocache.storeCache(null, response, listId, false, null);
+ handler.sendMessage(handler.obtainMessage(DownloadProgress.MSG_LOADED, response));
+ baseTime = System.currentTimeMillis();
+ worker.schedule(this);
+ } else if ("RG".equals(response)) {
+ //Server returned RG (registration) and this device no longer registered.
+ Settings.setWebNameCode(null, null);
+ handler.sendEmptyMessage(DownloadProgress.MSG_NO_REGISTRATION);
+ handler.cancel();
+ } else {
+ worker.schedule(this, 5, TimeUnit.SECONDS);
+ handler.sendEmptyMessage(DownloadProgress.MSG_WAITING);
+ }
+ } else {
+ handler.sendEmptyMessage(DownloadProgress.MSG_SERVER_FAIL);
+ handler.cancel();
+ }
+ }
+ });
+ }
+}
diff --git a/main/src/cgeo/geocaching/network/SmileyImage.java b/main/src/cgeo/geocaching/network/SmileyImage.java
new file mode 100644
index 0000000..9bb811e
--- /dev/null
+++ b/main/src/cgeo/geocaching/network/SmileyImage.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching.network;
+
+import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.utils.ImageUtils;
+import cgeo.geocaching.utils.ImageUtils.LineHeightContainerDrawable;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import rx.Observable;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.widget.TextView;
+
+/**
+ * Specialized image class for fetching and displaying smileys in the log book.
+ */
+public class SmileyImage extends HtmlImage {
+
+ public SmileyImage(final String geocode, final TextView view) {
+ super(geocode, false, StoredList.STANDARD_LIST_ID, false, view);
+ }
+
+ @Override
+ protected ImmutablePair<BitmapDrawable, Boolean> scaleImage(final ImmutablePair<Bitmap, Boolean> loadResult) {
+ final Bitmap bitmap = loadResult.left;
+ if (bitmap == null) {
+ return ImmutablePair.of((BitmapDrawable) null, loadResult.right);
+ }
+ final BitmapDrawable drawable = new BitmapDrawable(view.getResources(), bitmap);
+ drawable.setBounds(ImageUtils.scaleImageToLineHeight(drawable, view));
+ return ImmutablePair.of(drawable, loadResult.right);
+ }
+
+ @Override
+ protected BitmapDrawable getContainerDrawable(final Observable<BitmapDrawable> drawable) {
+ return new LineHeightContainerDrawable(view, drawable);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java
index 82650d1..bc4a5db 100644
--- a/main/src/cgeo/geocaching/network/StatusUpdater.java
+++ b/main/src/cgeo/geocaching/network/StatusUpdater.java
@@ -4,8 +4,7 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.utils.RxUtils;
import cgeo.geocaching.utils.Version;
-import org.json.JSONException;
-import org.json.JSONObject;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import rx.functions.Action0;
import rx.subjects.BehaviorSubject;
@@ -31,11 +30,11 @@ public class StatusUpdater {
this.url = url;
}
- Status(final JSONObject response) {
- message = get(response, "message");
- messageId = get(response, "message_id");
- icon = get(response, "icon");
- url = get(response, "url");
+ Status(final ObjectNode response) {
+ message = response.path("message").asText(null);
+ messageId = response.path("message_id").asText(null);
+ icon = response.path("icon").asText(null);
+ url = response.path("url").asText(null);
}
final static public Status closeoutStatus =
@@ -55,7 +54,7 @@ public class StatusUpdater {
RxUtils.networkScheduler.createWorker().schedulePeriodically(new Action0() {
@Override
public void call() {
- final JSONObject response =
+ final ObjectNode 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()),
@@ -67,12 +66,4 @@ public class StatusUpdater {
}, 0, 1800, TimeUnit.SECONDS);
}
- private static String get(final JSONObject json, final String key) {
- try {
- return json.getString(key);
- } catch (final JSONException e) {
- return null;
- }
- }
-
}
diff --git a/main/src/cgeo/geocaching/playservices/LocationProvider.java b/main/src/cgeo/geocaching/playservices/LocationProvider.java
new file mode 100644
index 0000000..027ae29
--- /dev/null
+++ b/main/src/cgeo/geocaching/playservices/LocationProvider.java
@@ -0,0 +1,160 @@
+package cgeo.geocaching.playservices;
+
+import cgeo.geocaching.sensors.GeoData;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.location.LocationListener;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationServices;
+
+import rx.Observable;
+import rx.Observable.OnSubscribe;
+import rx.Subscriber;
+import rx.functions.Action0;
+import rx.functions.Func1;
+import rx.observers.Subscribers;
+import rx.subjects.ReplaySubject;
+import rx.subscriptions.Subscriptions;
+
+import android.content.Context;
+import android.location.Location;
+import android.os.Bundle;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class LocationProvider implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
+
+ private static final LocationRequest LOCATION_REQUEST =
+ LocationRequest.create().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(2000).setFastestInterval(250);
+ private static final LocationRequest LOCATION_REQUEST_LOW_POWER =
+ LocationRequest.create().setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY).setInterval(10000).setFastestInterval(5000);
+ private static final AtomicInteger mostPreciseCount = new AtomicInteger(0);
+ private static final AtomicInteger lowPowerCount = new AtomicInteger(0);
+ private static LocationProvider instance = null;
+ private static final ReplaySubject<GeoData> subject = ReplaySubject.createWithSize(1);
+ private final GoogleApiClient locationClient;
+
+ private static synchronized LocationProvider getInstance(final Context context) {
+ if (instance == null) {
+ instance = new LocationProvider(context);
+ }
+ return instance;
+ }
+
+ private synchronized void updateRequest() {
+ if (locationClient.isConnected()) {
+ if (mostPreciseCount.get() > 0) {
+ Log.d("LocationProvider: requesting most precise locations");
+ LocationServices.FusedLocationApi.requestLocationUpdates(locationClient, LOCATION_REQUEST, this, RxUtils.looperCallbacksLooper);
+ } else if (lowPowerCount.get() > 0) {
+ Log.d("LocationProvider: requesting low-power locations");
+ LocationServices.FusedLocationApi.requestLocationUpdates(locationClient, LOCATION_REQUEST_LOW_POWER, this, RxUtils.looperCallbacksLooper);
+ } else {
+ Log.d("LocationProvider: stopping location requests");
+ LocationServices.FusedLocationApi.removeLocationUpdates(locationClient, this);
+ }
+ }
+ }
+
+ private static Observable<GeoData> get(final Context context, final AtomicInteger reference) {
+ final LocationProvider instance = getInstance(context);
+ return Observable.create(new OnSubscribe<GeoData>() {
+ @Override
+ public void call(final Subscriber<? super GeoData> subscriber) {
+ if (reference.incrementAndGet() == 1) {
+ instance.updateRequest();
+ }
+ subscriber.add(Subscriptions.create(new Action0() {
+ @Override
+ public void call() {
+ RxUtils.looperCallbacksWorker.schedule(new Action0() {
+ @Override
+ public void call() {
+ if (reference.decrementAndGet() == 0) {
+ instance.updateRequest();
+ }
+ }
+ }, 2500, TimeUnit.MILLISECONDS);
+ }
+ }));
+ subscriber.add(subject.subscribe(Subscribers.from(subscriber)));
+ }
+ });
+ }
+
+ public static Observable<GeoData> getMostPrecise(final Context context) {
+ return get(context, mostPreciseCount).onBackpressureDrop();
+ }
+
+ public static Observable<GeoData> getLowPower(final Context context) {
+ // Low-power location without the last stored location
+ final Observable<GeoData> lowPowerObservable = get(context, lowPowerCount).skip(1);
+
+ // High-power location without the last stored location
+ final Observable<GeoData> highPowerObservable = get(context, mostPreciseCount).skip(1);
+
+ // Use either low-power (with a 6 seconds head start) or high-power observables to obtain a location
+ // no less precise than 20 meters.
+ final Observable<GeoData> untilPreciseEnoughObservable =
+ lowPowerObservable.mergeWith(highPowerObservable.delaySubscription(6, TimeUnit.SECONDS))
+ .takeUntil(new Func1<GeoData, Boolean>() {
+ @Override
+ public Boolean call(final GeoData geoData) {
+ return geoData.getAccuracy() <= 20;
+ }
+ });
+
+ // After sending the last known location, try to get a precise location then use the low-power mode. If no
+ // location information is given for 25 seconds (if the network location is turned off for example), get
+ // back to the precise location and try again.
+ return subject.first().concatWith(untilPreciseEnoughObservable.concatWith(lowPowerObservable).timeout(25, TimeUnit.SECONDS).retry()).onBackpressureDrop();
+ }
+
+ /**
+ * Build a new geo data provider object.
+ * <p/>
+ * There is no need to instantiate more than one such object in an application, as observers can be added
+ * at will.
+ *
+ * @param context the context used to retrieve the system services
+ */
+ private LocationProvider(final Context context) {
+ final GeoData initialLocation = GeoData.getInitialLocation(context);
+ subject.onNext(initialLocation != null ? initialLocation : GeoData.DUMMY_LOCATION);
+ locationClient = new GoogleApiClient.Builder(context)
+ .addApi(LocationServices.API)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .build();
+ locationClient.connect();
+ }
+
+ @Override
+ public void onConnected(final Bundle bundle) {
+ updateRequest();
+ }
+
+ @Override
+ public void onConnectionFailed(final ConnectionResult connectionResult) {
+ Log.e("cannot connect to Google Play location service: " + connectionResult);
+ subject.onError(new RuntimeException("Connection failed: " + connectionResult));
+ }
+
+ @Override
+ public void onLocationChanged(final Location location) {
+ if (Settings.useLowPowerMode()) {
+ location.setProvider(GeoData.LOW_POWER_PROVIDER);
+ }
+ subject.onNext(new GeoData(location));
+ }
+
+ @Override
+ public void onConnectionSuspended(final int arg0) {
+ // empty
+ }
+}
diff --git a/main/src/cgeo/geocaching/sensors/DirectionProvider.java b/main/src/cgeo/geocaching/sensors/DirectionProvider.java
deleted file mode 100644
index ed5d76a..0000000
--- a/main/src/cgeo/geocaching/sensors/DirectionProvider.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package cgeo.geocaching.sensors;
-
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.utils.AngleUtils;
-import cgeo.geocaching.utils.StartableHandlerThread;
-
-import rx.Observable;
-import rx.Observable.OnSubscribe;
-import rx.Subscriber;
-import rx.subjects.BehaviorSubject;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Handler;
-import android.os.Process;
-import android.view.Surface;
-import android.view.WindowManager;
-
-public class DirectionProvider {
-
- private static final BehaviorSubject<Float> SUBJECT = BehaviorSubject.create(0.0f);
-
- private static final WindowManager WINDOW_MANAGER = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
-
- private DirectionProvider() {
- // utility class
- }
-
- static class Listener implements SensorEventListener, StartableHandlerThread.Callback {
-
- private int count = 0;
-
- private SensorManager sensorManager;
-
- @Override
- public void onSensorChanged(final SensorEvent event) {
- SUBJECT.onNext(event.values[0]);
- }
-
- @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. Do not have any code in here.
- *
- * See for example https://code.google.com/p/android/issues/detail?id=14792
- */
- }
-
- @Override
- public void start(final Context context, final Handler handler) {
- if (!hasSensor(context)) {
- return;
- }
- if (++count == 1) {
- Sensor orientationSensor = getOrientationSensor(context);
- sensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL, handler);
- }
- }
-
- @Override
- public void stop() {
- if (!hasSensor) {
- return;
- }
- if (--count == 0) {
- sensorManager.unregisterListener(this);
- }
- }
-
- /**
- * Assume that there is an orientation sensor, unless we have really checked that
- */
- private boolean hasSensor = true;
-
- /**
- * Flag for one time check if there is a sensor.
- */
- private boolean hasSensorChecked = false;
-
- public boolean hasSensor(Context context) {
- if (!hasSensorChecked) {
- hasSensor = getOrientationSensor(context) != null;
- hasSensorChecked = true;
- }
- return hasSensor;
- }
-
- // This will be removed when using a new location service. Until then, it is okay to be used.
- @SuppressWarnings("deprecation")
- private Sensor getOrientationSensor(final Context context) {
- sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
- return sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- }
-
- }
-
- private static final StartableHandlerThread HANDLER_THREAD =
- new StartableHandlerThread("DirectionProvider thread", Process.THREAD_PRIORITY_BACKGROUND, new Listener());
-
- static {
- HANDLER_THREAD.start();
- }
-
- public static Observable<Float> create(final Context context) {
- return Observable.create(new OnSubscribe<Float>() {
- @Override
- public void call(final Subscriber<? super Float> subscriber) {
- HANDLER_THREAD.start(subscriber, context);
- SUBJECT.subscribe(subscriber);
- }
- });
- }
-
- /**
- * Take the phone rotation (through a given activity) in account and adjust the direction.
- *
- * @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 float direction) {
- return AngleUtils.normalize(direction + getRotationOffset());
- }
-
- static float reverseDirectionNow(final float direction) {
- return AngleUtils.normalize(direction - getRotationOffset());
- }
-
- private static int getRotationOffset() {
- switch (WINDOW_MANAGER.getDefaultDisplay().getRotation()) {
- case Surface.ROTATION_90:
- return 90;
- case Surface.ROTATION_180:
- return 180;
- case Surface.ROTATION_270:
- return 270;
- default:
- return 0;
- }
- }
-
-}
diff --git a/main/src/cgeo/geocaching/sensors/GeoData.java b/main/src/cgeo/geocaching/sensors/GeoData.java
index c0b3974..b8b16fd 100644
--- a/main/src/cgeo/geocaching/sensors/GeoData.java
+++ b/main/src/cgeo/geocaching/sensors/GeoData.java
@@ -1,67 +1,109 @@
package cgeo.geocaching.sensors;
-import cgeo.geocaching.enumerations.LocationProviderType;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
-class GeoData extends Location implements IGeoData {
- private final boolean gpsEnabled;
- private final int satellitesVisible;
- private final int satellitesFixed;
- private final boolean pseudoLocation;
+public class GeoData extends Location {
- GeoData(final Location location, final boolean gpsEnabled, final int satellitesVisible, final int satellitesFixed, final boolean pseudoLocation) {
- super(location);
- this.gpsEnabled = gpsEnabled;
- this.satellitesVisible = satellitesVisible;
- this.satellitesFixed = satellitesFixed;
- this.pseudoLocation = pseudoLocation;
+ public static final String INITIAL_PROVIDER = "initial";
+ public static final String HOME_PROVIDER = "home";
+ public static final String FUSED_PROVIDER = "fused";
+ public static final String LOW_POWER_PROVIDER = "low-power";
+
+ // Some devices will not have the last position available (for example the emulator). In this case,
+ // rather than waiting forever for a position update which might never come, we emulate it by placing
+ // the user arbitrarly at Paris Notre-Dame, one of the most visited free tourist attractions in the world.
+ final public static GeoData DUMMY_LOCATION = new GeoData(new Location(INITIAL_PROVIDER));
+
+ static {
+ DUMMY_LOCATION.setLatitude(48.85308);
+ DUMMY_LOCATION.setLongitude(2.34962);
}
- @Override
- public Location getLocation() {
- return this;
+ public GeoData(final Location location) {
+ super(location);
}
- private static LocationProviderType getLocationProviderType(final String provider) {
- if (provider.equals(LocationManager.GPS_PROVIDER)) {
- return LocationProviderType.GPS;
+ @Nullable
+ static Location best(@Nullable final Location gpsLocation, @Nullable final Location netLocation) {
+ if (netLocation == null || (gpsLocation != null && System.currentTimeMillis() <= gpsLocation.getTime() + 30000)) {
+ return gpsLocation;
}
- if (provider.equals(LocationManager.NETWORK_PROVIDER)) {
- return LocationProviderType.NETWORK;
+ if (gpsLocation == null) {
+ return netLocation;
}
- return LocationProviderType.LAST;
+ return gpsLocation.getTime() >= netLocation.getTime() ? gpsLocation : netLocation;
}
- @Override
public LocationProviderType getLocationProvider() {
- return getLocationProviderType(getProvider());
+ switch (getProvider()) {
+ case LocationManager.GPS_PROVIDER:
+ return LocationProviderType.GPS;
+ case LocationManager.NETWORK_PROVIDER:
+ return LocationProviderType.NETWORK;
+ case FUSED_PROVIDER:
+ // LocationManager.FUSED_PROVIDER constant is not available at API level 9
+ return LocationProviderType.FUSED;
+ case LOW_POWER_PROVIDER:
+ return LocationProviderType.LOW_POWER;
+ case HOME_PROVIDER:
+ return LocationProviderType.HOME;
+ default:
+ return LocationProviderType.LAST;
+ }
}
- @Override
+ @NonNull
public Geopoint getCoords() {
return new Geopoint(this);
}
- @Override
- public boolean getGpsEnabled() {
- return gpsEnabled;
- }
-
- @Override
- public int getSatellitesVisible() {
- return satellitesVisible;
- }
-
- @Override
- public int getSatellitesFixed() {
- return satellitesFixed;
+ @Nullable
+ public static GeoData getInitialLocation(final Context context) {
+ final LocationManager geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ if (geoManager != null) {
+ try {
+ // Try to find a sensible initial location from the last locations known to Android.
+ final Location lastGpsLocation = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+ final Location lastNetworkLocation = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+ final Location bestLocation = best(lastGpsLocation, lastNetworkLocation);
+ if (bestLocation != null) {
+ bestLocation.setProvider(INITIAL_PROVIDER);
+ return new GeoData(bestLocation);
+ }
+ } catch (final Exception e) {
+ // This error is non-fatal as its only consequence is that we will start with a dummy location
+ // instead of a previously known one.
+ Log.e("Error when retrieving last known location", e);
+ }
+ } else {
+ Log.w("No LocationManager available");
+ }
+ final String homeLocationStr = Settings.getHomeLocation();
+ if (StringUtils.isNotBlank(homeLocationStr)) {
+ try {
+ assert homeLocationStr != null;
+ final Geopoint homeLocation = new Geopoint(homeLocationStr);
+ Log.i("No last known location available, using home location");
+ final Location initialLocation = new Location(HOME_PROVIDER);
+ initialLocation.setLatitude(homeLocation.getLatitude());
+ initialLocation.setLongitude(homeLocation.getLongitude());
+ return new GeoData(initialLocation);
+ } catch (final Geopoint.ParseException e) {
+ Log.w("Unable to parse home location " + homeLocationStr, e);
+ }
+ }
+ Log.i("No last known location nor home location available");
+ return null;
}
- @Override
- public boolean isPseudoLocation() {
- return pseudoLocation;
- }
-}
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
index a4799cb..dab05d0 100644
--- a/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
+++ b/main/src/cgeo/geocaching/sensors/GeoDataProvider.java
@@ -1,25 +1,13 @@
package cgeo.geocaching.sensors;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.StartableHandlerThread;
+import cgeo.geocaching.utils.RxUtils.LooperCallbacks;
import org.apache.commons.lang3.StringUtils;
import rx.Observable;
-import rx.Observable.OnSubscribe;
-import rx.Subscriber;
-import rx.Subscription;
-import rx.android.schedulers.AndroidSchedulers;
-import rx.functions.Action0;
-import rx.functions.Action1;
-import rx.observables.ConnectableObservable;
-import rx.subjects.BehaviorSubject;
-import rx.subscriptions.CompositeSubscription;
-import rx.subscriptions.Subscriptions;
import android.content.Context;
-import android.location.GpsSatellite;
-import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
@@ -27,40 +15,13 @@ import android.os.Bundle;
import java.util.concurrent.TimeUnit;
-public class GeoDataProvider implements OnSubscribe<IGeoData> {
+public class GeoDataProvider extends LooperCallbacks<GeoData> {
- private static final String LAST_LOCATION_PSEUDO_PROVIDER = "last";
+ private final Context context;
private final LocationManager geoManager;
- private final LocationData gpsLocation = new LocationData();
- private final LocationData netLocation = new LocationData();
- private final BehaviorSubject<IGeoData> subject;
- private static final StartableHandlerThread handlerThread =
- new StartableHandlerThread("GeoDataProvider thread", android.os.Process.THREAD_PRIORITY_BACKGROUND);
- static {
- handlerThread.start();
- }
-
- public boolean gpsEnabled = false;
- public int satellitesVisible = 0;
- public int satellitesFixed = 0;
-
- private static class LocationData {
- public Location location;
- public long timestamp = 0;
-
- public void update(final Location location) {
- this.location = location;
- timestamp = System.currentTimeMillis();
- }
-
- public boolean isRecent() {
- return isValid() && System.currentTimeMillis() < timestamp + 30000;
- }
-
- public boolean isValid() {
- return location != null;
- }
- }
+ private Location latestGPSLocation = null;
+ private final Listener networkListener = new Listener();
+ private final Listener gpsListener = new Listener();
/**
* Build a new geo data provider object.
@@ -71,117 +32,51 @@ public class GeoDataProvider implements OnSubscribe<IGeoData> {
* @param context the context used to retrieve the system services
*/
protected GeoDataProvider(final Context context) {
- geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- subject = BehaviorSubject.create(findInitialLocation());
+ super(2500, TimeUnit.MILLISECONDS);
+ this.context = context.getApplicationContext();
+ geoManager = (LocationManager) this.context.getSystemService(Context.LOCATION_SERVICE);
}
- public static Observable<IGeoData> create(final Context context) {
- final GeoDataProvider provider = new GeoDataProvider(context);
- return provider.worker.refCount();
+ public static Observable<GeoData> create(final Context context) {
+ return Observable.create(new GeoDataProvider(context)).onBackpressureDrop();
}
@Override
- public void call(final Subscriber<? super IGeoData> subscriber) {
- subject.subscribe(subscriber);
- }
-
- final ConnectableObservable<IGeoData> worker = new ConnectableObservable<IGeoData>(this) {
- private int debugSessionCounter = 0;
-
- private final Object lock = new Object();
- private int count = 0;
-
- final private GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
- final private Listener networkListener = new Listener(LocationManager.NETWORK_PROVIDER, netLocation);
- final private Listener gpsListener = new Listener(LocationManager.GPS_PROVIDER, gpsLocation);
-
- @Override
- public void connect(Action1<? super Subscription> connection) {
- final CompositeSubscription subscription = new CompositeSubscription();
- AndroidSchedulers.handlerThread(handlerThread.getHandler()).createWorker().schedule(new Action0() {
- @Override
- public void call() {
- synchronized(lock) {
- if (count++ == 0) {
- Log.d("GeoDataProvider: starting the GPS and network listeners" + " (" + ++debugSessionCounter + ")");
- 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);
- }
- }
- }
- }
-
- subscription.add(Subscriptions.create(new Action0() {
- @Override
- public void call() {
- AndroidSchedulers.handlerThread(handlerThread.getHandler()).createWorker().schedule(new Action0() {
- @Override
- public void call() {
- synchronized (lock) {
- if (--count == 0) {
- Log.d("GeoDataProvider: stopping the GPS and network listeners" + " (" + debugSessionCounter + ")");
- geoManager.removeUpdates(networkListener);
- geoManager.removeUpdates(gpsListener);
- geoManager.removeGpsStatusListener(gpsStatusListener);
- }
- }
- }
- }, 2500, TimeUnit.MILLISECONDS);
- }
- }));
- }
- });
- connection.call(subscription);
+ public void onStart() {
+ final GeoData initialLocation = GeoData.getInitialLocation(context);
+ if (initialLocation != null) {
+ subject.onNext(initialLocation);
}
- };
-
- private IGeoData findInitialLocation() {
- final Location initialLocation = new Location(LAST_LOCATION_PSEUDO_PROVIDER);
+ Log.d("GeoDataProvider: starting the GPS and network listeners");
try {
- // Try to find a sensible initial location from the last locations known to Android.
- final Location lastGpsLocation = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
- final Location lastNetworkLocation = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
-
- // If both providers are non-null, take the most recent one
- if (lastGpsLocation != null && lastNetworkLocation != null) {
- if (lastGpsLocation.getTime() >= lastNetworkLocation.getTime()) {
- copyCoords(initialLocation, lastGpsLocation);
- } else {
- copyCoords(initialLocation, lastNetworkLocation);
- }
- } else if (lastGpsLocation != null) {
- copyCoords(initialLocation, lastGpsLocation);
- } else if (lastNetworkLocation != null) {
- copyCoords(initialLocation, lastNetworkLocation);
- } else {
- Log.i("GeoDataProvider: no last known location available");
- }
+ geoManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsListener);
+ } catch (final Exception e) {
+ Log.w("Unable to create GPS location provider: " + e.getMessage());
+ }
+ try {
+ geoManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
} catch (final Exception e) {
- // This error is non-fatal as its only consequence is that we will start with a dummy location
- // instead of a previously known one.
- Log.e("GeoDataProvider: error when retrieving last known location", e);
+ Log.w("Unable to create network location provider: " + e.getMessage());
}
- // Start with an historical GeoData just in case someone queries it before we get
- // a chance to get any information.
- return new GeoData(initialLocation, false, 0, 0, true);
}
- private static void copyCoords(final Location target, final Location source) {
- target.setLatitude(source.getLatitude());
- target.setLongitude(source.getLongitude());
+ @Override
+ protected void onStop() {
+ Log.d("GeoDataProvider: stopping the GPS and network listeners");
+ geoManager.removeUpdates(networkListener);
+ geoManager.removeUpdates(gpsListener);
}
private class Listener implements LocationListener {
- private final String locationProvider;
- private final LocationData locationData;
- Listener(final String locationProvider, final LocationData locationData) {
- this.locationProvider = locationProvider;
- this.locationData = locationData;
+ @Override
+ public void onLocationChanged(final Location location) {
+ if (StringUtils.equals(location.getProvider(), LocationManager.GPS_PROVIDER)) {
+ latestGPSLocation = location;
+ assign(latestGPSLocation);
+ } else {
+ assign(GeoData.best(latestGPSLocation, location));
+ }
}
@Override
@@ -198,85 +93,11 @@ public class GeoDataProvider implements OnSubscribe<IGeoData> {
public void onProviderEnabled(final String provider) {
// nothing
}
-
- @Override
- public void onLocationChanged(final Location location) {
- locationData.update(location);
- selectBest();
- }
- }
-
- private final class GpsStatusListener implements GpsStatus.Listener {
-
- @Override
- public void onGpsStatusChanged(final int event) {
- boolean changed = false;
- switch (event) {
- case GpsStatus.GPS_EVENT_FIRST_FIX:
- case GpsStatus.GPS_EVENT_SATELLITE_STATUS: {
- final GpsStatus status = geoManager.getGpsStatus(null);
- int visible = 0;
- int fixed = 0;
- for (final GpsSatellite satellite : status.getSatellites()) {
- if (satellite.usedInFix()) {
- fixed++;
- }
- visible++;
- }
- if (visible != satellitesVisible || fixed != satellitesFixed) {
- satellitesVisible = visible;
- satellitesFixed = fixed;
- changed = true;
- }
- break;
- }
- case GpsStatus.GPS_EVENT_STARTED:
- if (!gpsEnabled) {
- gpsEnabled = true;
- changed = true;
- }
- break;
- case GpsStatus.GPS_EVENT_STOPPED:
- if (gpsEnabled) {
- gpsEnabled = false;
- satellitesFixed = 0;
- satellitesVisible = 0;
- changed = true;
- }
- break;
- default:
- throw new IllegalStateException();
- }
-
- if (changed) {
- selectBest();
- }
- }
- }
-
- private LocationData best() {
- if (gpsLocation.isRecent() || !netLocation.isValid()) {
- return gpsLocation.isValid() ? gpsLocation : null;
- }
- if (!gpsLocation.isValid()) {
- return netLocation;
- }
- return gpsLocation.timestamp > netLocation.timestamp ? gpsLocation : netLocation;
- }
-
- private void selectBest() {
- assign(best());
}
- private void assign(final LocationData locationData) {
- if (locationData == null) {
- return;
- }
-
+ private void assign(final Location location) {
// We do not necessarily get signalled when satellites go to 0/0.
- final int visible = gpsLocation.isRecent() ? satellitesVisible : 0;
- final boolean pseudoLocation = StringUtils.equals(locationData.location.getProvider(), LAST_LOCATION_PSEUDO_PROVIDER);
- final IGeoData current = new GeoData(locationData.location, gpsEnabled, visible, satellitesFixed, pseudoLocation);
+ final GeoData current = new GeoData(location);
subject.onNext(current);
}
diff --git a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
index 0f30142..4743140 100644
--- a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
+++ b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java
@@ -1,27 +1,25 @@
package cgeo.geocaching.sensors;
-import cgeo.geocaching.CgeoApplication;
-import cgeo.geocaching.settings.Settings;
-
import org.apache.commons.lang3.tuple.ImmutablePair;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
-import rx.functions.Func1;
import rx.functions.Func2;
import rx.subscriptions.CompositeSubscription;
+import java.util.concurrent.TimeUnit;
+
/**
* GeoData and Direction handler.
* <p>
- * To use this class, override {@link #updateGeoDir(IGeoData, float)}. You need to start the handler using
+ * To use this class, override {@link #updateGeoDir(cgeo.geocaching.sensors.GeoData, float)}. You need to start the handler using
* {@link #start(int)}. A good place to do so might be the {@code onResume} method of the Activity. Stop the Handler
* accordingly in {@code onPause}.
*
* The direction is always relative to the top of the device (natural direction), and that it must
- * be fixed using {@link DirectionProvider#getDirectionNow(float)}. When the direction is derived from the GPS,
+ * be fixed using {@link cgeo.geocaching.utils.AngleUtils#getDirectionNow(float)}. When the direction is derived from the GPS,
* it is altered so that the fix can still be applied as if the information came from the compass.
*/
public abstract class GeoDirHandler {
@@ -29,8 +27,7 @@ public abstract class GeoDirHandler {
public static final int UPDATE_GEODATA = 1 << 1;
public static final int UPDATE_DIRECTION = 1 << 2;
public static final int UPDATE_GEODIR = 1 << 3;
-
- private static final CgeoApplication app = CgeoApplication.getInstance();
+ public static final int LOW_POWER = 1 << 4;
/**
* Update method called when new geodata is available. This method is called on the UI thread.
@@ -38,7 +35,7 @@ public abstract class GeoDirHandler {
*
* @param geoData the new geographical data
*/
- public void updateGeoData(final IGeoData geoData) {
+ public void updateGeoData(final GeoData geoData) {
}
/**
@@ -60,41 +57,46 @@ public abstract class GeoDirHandler {
* If the device goes fast enough, or if the compass use is not enabled in the settings,
* the GPS direction information will be used instead of the compass one.
*/
- public void updateGeoDir(final IGeoData geoData, final float direction) {
+ public void updateGeoDir(final GeoData geoData, final float direction) {
}
- private static Observable<Float> fixedDirection() {
- return app.directionObservable().map(new Func1<Float, Float>() {
- @Override
- public Float call(final Float direction) {
- final IGeoData geoData = app.currentGeo();
- return fixDirection(geoData, direction);
- }
- });
-
+ private static <T> Observable<T> throttleIfNeeded(final Observable<T> observable, final long windowDuration, final TimeUnit unit) {
+ return windowDuration > 0 ? observable.throttleFirst(windowDuration, unit) : observable;
}
- private static float fixDirection(final IGeoData geoData, final float direction) {
- final boolean useGPSBearing = !Settings.isUseCompass() || geoData.getSpeed() > 5;
- return useGPSBearing ? DirectionProvider.reverseDirectionNow(geoData.getBearing()) : direction;
+ /**
+ * Register the current GeoDirHandler for GeoData and direction information (if the preferences allow it).
+ *
+ * @param flags a combination of UPDATE_GEODATA, UPDATE_DIRECTION, UPDATE_GEODIR, and LOW_POWER
+ * @return a subscription which can be used to stop the handler
+ */
+ public Subscription start(final int flags) {
+ return start(flags, 0, TimeUnit.SECONDS);
}
/**
- * Register the current GeoDirHandler for GeoData and direction information (if the
- * preferences allow it).
+ * Register the current GeoDirHandler for GeoData and direction information (if the preferences allow it).
+ *
+ * @param flags a combination of UPDATE_GEODATA, UPDATE_DIRECTION, UPDATE_GEODIR, and LOW_POWER
+ * @param windowDuration if greater than 0, the size of the window duration during which no new value will be presented
+ * @param unit the unit for the windowDuration
+ * @return a subscription which can be used to stop the handler
*/
- public Subscription start(final int flags) {
+ public Subscription start(final int flags, final long windowDuration, final TimeUnit unit) {
final CompositeSubscription subscriptions = new CompositeSubscription();
+ final boolean lowPower = (flags & LOW_POWER) != 0;
+ final Sensors sensors = Sensors.getInstance();
+
if ((flags & UPDATE_GEODATA) != 0) {
- subscriptions.add(app.geoDataObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<IGeoData>() {
+ subscriptions.add(throttleIfNeeded(sensors.geoDataObservable(lowPower), windowDuration, unit).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<GeoData>() {
@Override
- public void call(final IGeoData geoData) {
+ public void call(final GeoData geoData) {
updateGeoData(geoData);
}
}));
}
if ((flags & UPDATE_DIRECTION) != 0) {
- subscriptions.add(fixedDirection().observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Float>() {
+ subscriptions.add(throttleIfNeeded(sensors.directionObservable(), windowDuration, unit).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<Float>() {
@Override
public void call(final Float direction) {
updateDirection(direction);
@@ -102,14 +104,15 @@ public abstract class GeoDirHandler {
}));
}
if ((flags & UPDATE_GEODIR) != 0) {
- subscriptions.add(Observable.combineLatest(app.geoDataObservable(), app.directionObservable(), new Func2<IGeoData, Float, ImmutablePair<IGeoData, Float>>() {
+ // combineOnLatest() does not implement backpressure handling, so we need to explicitely use a backpressure operator there.
+ subscriptions.add(throttleIfNeeded(Observable.combineLatest(sensors.geoDataObservable(lowPower), sensors.directionObservable(), new Func2<GeoData, Float, ImmutablePair<GeoData, Float>>() {
@Override
- public ImmutablePair<IGeoData, Float> call(final IGeoData geoData, final Float direction) {
- return ImmutablePair.of(geoData, fixDirection(geoData, direction));
+ public ImmutablePair<GeoData, Float> call(final GeoData geoData, final Float direction) {
+ return ImmutablePair.of(geoData, direction);
}
- }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<ImmutablePair<IGeoData, Float>>() {
+ }), windowDuration, unit).onBackpressureDrop().observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<ImmutablePair<GeoData, Float>>() {
@Override
- public void call(final ImmutablePair<IGeoData, Float> geoDir) {
+ public void call(final ImmutablePair<GeoData, Float> geoDir) {
updateGeoDir(geoDir.left, geoDir.right);
}
}));
diff --git a/main/src/cgeo/geocaching/sensors/GpsStatusProvider.java b/main/src/cgeo/geocaching/sensors/GpsStatusProvider.java
new file mode 100644
index 0000000..d7aa113
--- /dev/null
+++ b/main/src/cgeo/geocaching/sensors/GpsStatusProvider.java
@@ -0,0 +1,99 @@
+package cgeo.geocaching.sensors;
+
+import cgeo.geocaching.sensors.GpsStatusProvider.Status;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils.LooperCallbacks;
+
+import rx.Observable;
+
+import android.content.Context;
+import android.location.GpsSatellite;
+import android.location.GpsStatus;
+import android.location.LocationManager;
+
+public class GpsStatusProvider extends LooperCallbacks<Status> {
+
+ public static class Status {
+ final public boolean gpsEnabled;
+ final public int satellitesVisible;
+ final public int satellitesFixed;
+
+ public Status(final boolean gpsEnabled, final int satellitesVisible, final int satellitesFixed) {
+ this.gpsEnabled = gpsEnabled;
+ this.satellitesVisible = satellitesVisible;
+ this.satellitesFixed = satellitesFixed;
+ }
+ }
+
+ private final LocationManager geoManager;
+ private final GpsStatus.Listener gpsStatusListener = new GpsStatusListener();
+ private Status latest = new Status(false, 0, 0);
+
+ private static final Status NO_GPS = new Status(false, 0, 0);
+
+ /**
+ * Build a new gps status provider object.
+ * <p/>
+ * There is no need to instantiate more than one such object in an application, as observers can be added
+ * at will.
+ *
+ * @param context the context used to retrieve the system services
+ */
+ protected GpsStatusProvider(final Context context) {
+ geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ public static Observable<Status> create(final Context context) {
+ return Observable.create(new GpsStatusProvider(context));
+ }
+
+ @Override
+ protected void onStart() {
+ Log.d("GpsStatusProvider: starting the GPS status listener");
+ subject.onNext(NO_GPS);
+ geoManager.addGpsStatusListener(gpsStatusListener);
+ }
+
+ @Override
+ protected void onStop() {
+ Log.d("GpsStatusProvider: stopping the GPS status listener");
+ geoManager.removeGpsStatusListener(gpsStatusListener);
+ }
+
+ private final class GpsStatusListener implements GpsStatus.Listener {
+
+ @Override
+ public void onGpsStatusChanged(final int event) {
+ switch (event) {
+ case GpsStatus.GPS_EVENT_FIRST_FIX:
+ case GpsStatus.GPS_EVENT_SATELLITE_STATUS: {
+ final GpsStatus status = geoManager.getGpsStatus(null);
+ int visible = 0;
+ int fixed = 0;
+ for (final GpsSatellite satellite : status.getSatellites()) {
+ if (satellite.usedInFix()) {
+ fixed++;
+ }
+ visible++;
+ }
+ if (visible == latest.satellitesVisible && fixed == latest.satellitesFixed) {
+ return;
+ }
+ latest = new Status(true, visible, fixed);
+ break;
+ }
+ case GpsStatus.GPS_EVENT_STARTED:
+ latest = new Status(true, 0, 0);
+ break;
+ case GpsStatus.GPS_EVENT_STOPPED:
+ latest = new Status(false, 0, 0);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+
+ subject.onNext(latest);
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/sensors/IGeoData.java b/main/src/cgeo/geocaching/sensors/IGeoData.java
deleted file mode 100644
index 5b4f046..0000000
--- a/main/src/cgeo/geocaching/sensors/IGeoData.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package cgeo.geocaching.sensors;
-
-import cgeo.geocaching.enumerations.LocationProviderType;
-import cgeo.geocaching.geopoint.Geopoint;
-
-import android.location.Location;
-
-public interface IGeoData {
-
- public Location getLocation();
- public LocationProviderType getLocationProvider();
-
- public boolean isPseudoLocation();
-
- public Geopoint getCoords();
- public float getBearing();
- public float getSpeed();
- public float getAccuracy();
- public boolean getGpsEnabled();
- public int getSatellitesVisible();
- public int getSatellitesFixed();
-}
diff --git a/main/src/cgeo/geocaching/enumerations/LocationProviderType.java b/main/src/cgeo/geocaching/sensors/LocationProviderType.java
index f2c79fe..16a50b8 100644
--- a/main/src/cgeo/geocaching/enumerations/LocationProviderType.java
+++ b/main/src/cgeo/geocaching/sensors/LocationProviderType.java
@@ -1,10 +1,13 @@
-package cgeo.geocaching.enumerations;
+package cgeo.geocaching.sensors;
import cgeo.geocaching.R;
public enum LocationProviderType {
GPS(R.string.loc_gps),
NETWORK(R.string.loc_net),
+ FUSED(R.string.loc_fused),
+ LOW_POWER(R.string.loc_low_power),
+ HOME(R.string.loc_home),
LAST(R.string.loc_last);
public final int resourceId;
diff --git a/main/src/cgeo/geocaching/sensors/OrientationProvider.java b/main/src/cgeo/geocaching/sensors/OrientationProvider.java
new file mode 100644
index 0000000..ce84ffb
--- /dev/null
+++ b/main/src/cgeo/geocaching/sensors/OrientationProvider.java
@@ -0,0 +1,72 @@
+package cgeo.geocaching.sensors;
+
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils.LooperCallbacks;
+
+import rx.Observable;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class OrientationProvider extends LooperCallbacks<Float> implements SensorEventListener {
+
+ private final SensorManager sensorManager;
+ private final Sensor orientationSensor;
+
+ @SuppressWarnings("deprecation")
+ protected OrientationProvider(final Context context) {
+ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
+ if (orientationSensor != null) {
+ Log.d("OrientationProvider: sensor found");
+ } else {
+ Log.w("OrientationProvider: no orientation sensor on this device");
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public static boolean hasOrientationSensor(final Context context) {
+ return ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_ORIENTATION) != null;
+ }
+
+ @Override
+ public void onSensorChanged(final SensorEvent event) {
+ subject.onNext(event.values[0]);
+ }
+
+ @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. Do not have any code in here.
+ *
+ * See for example https://code.google.com/p/android/issues/detail?id=14792
+ */
+ }
+
+ @Override
+ public void onStart() {
+ if (orientationSensor != null) {
+ Log.d("OrientationProvider: starting the orientation provider");
+ sensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ } else {
+ subject.onError(new RuntimeException("orientation sensor is absent on this device"));
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (orientationSensor != null) {
+ Log.d("OrientationProvider: stopping the orientation provider");
+ sensorManager.unregisterListener(this);
+ }
+ }
+
+ public static Observable<Float> create(final Context context) {
+ return Observable.create(new OrientationProvider(context)).onBackpressureDrop();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/sensors/RotationProvider.java b/main/src/cgeo/geocaching/sensors/RotationProvider.java
new file mode 100644
index 0000000..c63e39f
--- /dev/null
+++ b/main/src/cgeo/geocaching/sensors/RotationProvider.java
@@ -0,0 +1,97 @@
+package cgeo.geocaching.sensors;
+
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils.LooperCallbacks;
+
+import rx.Observable;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+
+public class RotationProvider extends LooperCallbacks<Float> implements SensorEventListener {
+
+ private final SensorManager sensorManager;
+ private final Sensor rotationSensor;
+ private final float[] rotationMatrix = new float[16];
+ private final float[] orientation = new float[4];
+ private final float[] values = new float[4];
+
+ @TargetApi(19)
+ protected RotationProvider(final Context context, final boolean lowPower) {
+ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ // The geomagnetic rotation vector introduced in Android 4.4 (API 19) requires less power. Favour it
+ // even if it is more sensible to noise in low-power settings.
+ final Sensor sensor = lowPower ? sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR) : null;
+ if (sensor != null) {
+ rotationSensor = sensor;
+ Log.d("RotationProvider: geomagnetic (low-power) sensor found");
+ } else {
+ rotationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
+ if (rotationSensor != null) {
+ Log.d("RotationProvider: sensor found");
+ } else {
+ Log.w("RotationProvider: no rotation sensor on this device");
+ }
+ }
+ }
+
+ public static boolean hasRotationSensor(final Context context) {
+ return ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) != null;
+ }
+
+ @TargetApi(19)
+ public static boolean hasGeomagneticRotationSensor(final Context context) {
+ return ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR) != null;
+ }
+
+ @Override
+ public void onSensorChanged(final SensorEvent event) {
+ // On some Samsung devices, SensorManager#getRotationMatrixFromVector throws an exception if the rotation
+ // vector has more than 4 elements. Since only the four first elements are used, we can truncate the vector
+ // without losing precision.
+ if (event.values.length > 4) {
+ System.arraycopy(event.values, 0, values, 0, 4);
+ SensorManager.getRotationMatrixFromVector(rotationMatrix, values);
+ } else {
+ SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values);
+ }
+ SensorManager.getOrientation(rotationMatrix, orientation);
+ subject.onNext((float) (orientation[0] * 180 / Math.PI));
+ }
+
+ @Override
+ public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
+ }
+
+ @Override
+ public void onStart() {
+ if (rotationSensor != null) {
+ Log.d("RotationProvider: starting the rotation provider");
+ try {
+ sensorManager.registerListener(this, rotationSensor, SensorManager.SENSOR_DELAY_NORMAL);
+ } catch (final Exception e) {
+ Log.w("RotationProvider: unable to register listener", e);
+ subject.onError(e);
+ }
+ } else {
+ subject.onError(new RuntimeException("rotation sensor is absent on this device"));
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (rotationSensor != null) {
+ Log.d("RotationProvider: stopping the rotation provider");
+ sensorManager.unregisterListener(this);
+ }
+ }
+
+ public static Observable<Float> create(final Context context, final boolean lowPower) {
+ return Observable.create(new RotationProvider(context, lowPower)).onBackpressureDrop();
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/sensors/Sensors.java b/main/src/cgeo/geocaching/sensors/Sensors.java
new file mode 100644
index 0000000..c3f6ce7
--- /dev/null
+++ b/main/src/cgeo/geocaching/sensors/Sensors.java
@@ -0,0 +1,165 @@
+package cgeo.geocaching.sensors;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.playservices.LocationProvider;
+import cgeo.geocaching.sensors.GpsStatusProvider.Status;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.AngleUtils;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import rx.Observable;
+import rx.functions.Action1;
+import rx.functions.Func1;
+
+import android.content.Context;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class Sensors {
+
+ private Observable<GeoData> geoDataObservable;
+ private Observable<GeoData> geoDataObservableLowPower;
+ private Observable<Float> directionObservable;
+ private Observable<Status> gpsStatusObservable;
+ @NonNull private volatile GeoData currentGeo = GeoData.DUMMY_LOCATION;
+ private volatile float currentDirection = 0.0f;
+ private volatile boolean hasValidLocation = false;
+ private final boolean hasCompassCapabilities;
+ private final CgeoApplication app = CgeoApplication.getInstance();
+
+ private static class InstanceHolder {
+ static final Sensors INSTANCE = new Sensors();
+ }
+
+ private final Action1<GeoData> rememberGeodataAction = new Action1<GeoData>() {
+ @Override
+ public void call(final GeoData geoData) {
+ currentGeo = geoData;
+ hasValidLocation = true;
+ }
+ };
+
+ private final Action1<Float> onNextrememberDirectionAction = new Action1<Float>() {
+ @Override
+ public void call(final Float direction) {
+ currentDirection = direction;
+ }
+ };
+
+ private Sensors() {
+ gpsStatusObservable = GpsStatusProvider.create(app).replay(1).refCount();
+ final Context context = CgeoApplication.getInstance().getApplicationContext();
+ hasCompassCapabilities = RotationProvider.hasRotationSensor(context) || OrientationProvider.hasOrientationSensor(context);
+ }
+
+ public static final Sensors getInstance() {
+ return InstanceHolder.INSTANCE;
+ }
+
+ private final Func1<Throwable, Observable<GeoData>> fallbackToGeodataProvider = new Func1<Throwable, Observable<GeoData>>() {
+ @Override
+ public Observable<GeoData> call(final Throwable throwable) {
+ Log.e("Cannot use Play Services location provider, falling back to GeoDataProvider", throwable);
+ Settings.setUseGooglePlayServices(false);
+ return GeoDataProvider.create(app);
+ }
+ };
+
+ public void setupGeoDataObservables(final boolean useGooglePlayServices, final boolean useLowPowerLocation) {
+ if (useGooglePlayServices) {
+ geoDataObservable = LocationProvider.getMostPrecise(app).onErrorResumeNext(fallbackToGeodataProvider).doOnNext(rememberGeodataAction);
+ if (useLowPowerLocation) {
+ geoDataObservableLowPower = LocationProvider.getLowPower(app).doOnNext(rememberGeodataAction).onErrorResumeNext(geoDataObservable);
+ } else {
+ geoDataObservableLowPower = geoDataObservable;
+ }
+ } else {
+ geoDataObservable = RxUtils.rememberLast(GeoDataProvider.create(app).doOnNext(rememberGeodataAction), null);
+ geoDataObservableLowPower = geoDataObservable;
+ }
+ }
+
+ private static final Func1<GeoData, Float> GPS_TO_DIRECTION = new Func1<GeoData, Float>() {
+ @Override
+ public Float call(final GeoData geoData) {
+ return AngleUtils.reverseDirectionNow(geoData.getBearing());
+ }
+ };
+
+ public void setupDirectionObservable(final boolean useLowPower) {
+ // If we have no magnetic sensor, there is no point in trying to setup any, we will always get the direction from the GPS.
+ if (!hasCompassCapabilities) {
+ Log.i("No compass capabilities, using only the GPS for the orientation");
+ directionObservable = RxUtils.rememberLast(geoDataObservableLowPower.map(GPS_TO_DIRECTION).doOnNext(onNextrememberDirectionAction), 0f);
+ return;
+ }
+
+ // Combine the magnetic direction observable with the GPS when compass is disabled or speed is high enough.
+ final AtomicBoolean useDirectionFromGps = new AtomicBoolean(false);
+
+ // The rotation sensor seems to be bogus on some devices. We should start with the orientation one, except when we explicitely
+ // want to use the low-power geomagnetic rotation sensor or when we do not have an orientation sensor.
+ final boolean useRotationSensor = (useLowPower && RotationProvider.hasGeomagneticRotationSensor(app)) || !OrientationProvider.hasOrientationSensor(app);
+ final Observable<Float> sensorDirectionObservable = useRotationSensor ? RotationProvider.create(app, useLowPower) : OrientationProvider.create(app);
+ final Observable<Float> magneticDirectionObservable = sensorDirectionObservable.onErrorResumeNext(new Func1<Throwable, Observable<? extends Float>>() {
+ @Override
+ public Observable<? extends Float> call(final Throwable throwable) {
+ Log.e("Device orientation is not available due to sensors error, disabling compass", throwable);
+ Settings.setUseCompass(false);
+ return Observable.<Float>never().startWith(0.0f);
+ }
+ }).filter(new Func1<Float, Boolean>() {
+ @Override
+ public Boolean call(final Float aFloat) {
+ return Settings.isUseCompass() && !useDirectionFromGps.get();
+ }
+ });
+
+ final Observable<Float> directionFromGpsObservable = geoDataObservableLowPower.filter(new Func1<GeoData, Boolean>() {
+ @Override
+ public Boolean call(final GeoData geoData) {
+ final boolean useGps = geoData.getSpeed() > 5.0f;
+ useDirectionFromGps.set(useGps);
+ return useGps || !Settings.isUseCompass();
+ }
+ }).map(GPS_TO_DIRECTION);
+
+ directionObservable = RxUtils.rememberLast(Observable.merge(magneticDirectionObservable, directionFromGpsObservable).doOnNext(onNextrememberDirectionAction), 0f);
+ }
+
+ public Observable<GeoData> geoDataObservable(final boolean lowPower) {
+ return lowPower ? geoDataObservableLowPower : geoDataObservable;
+ }
+
+ public Observable<Float> directionObservable() {
+ return directionObservable;
+ }
+
+ public Observable<Status> gpsStatusObservable() {
+ if (gpsStatusObservable == null) {
+ gpsStatusObservable = GpsStatusProvider.create(app).share();
+ }
+ return gpsStatusObservable;
+ }
+
+ @NonNull
+ public GeoData currentGeo() {
+ return currentGeo;
+ }
+
+ public boolean hasValidLocation() {
+ return hasValidLocation;
+ }
+
+ public float currentDirection() {
+ return currentDirection;
+ }
+
+ public boolean hasCompassCapabilities() {
+ return hasCompassCapabilities;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java b/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java
index 1930c17..aeeef9f 100644
--- a/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java
+++ b/main/src/cgeo/geocaching/settings/AbstractAttributeBasedPrefence.java
@@ -13,25 +13,25 @@ import android.util.AttributeSet;
*/
public abstract class AbstractAttributeBasedPrefence extends Preference {
- public AbstractAttributeBasedPrefence(Context context) {
+ public AbstractAttributeBasedPrefence(final Context context) {
super(context);
}
- public AbstractAttributeBasedPrefence(Context context, AttributeSet attrs) {
+ public AbstractAttributeBasedPrefence(final Context context, final AttributeSet attrs) {
super(context, attrs);
processAttributes(context, attrs, 0);
}
- public AbstractAttributeBasedPrefence(Context context, AttributeSet attrs, int defStyle) {
+ public AbstractAttributeBasedPrefence(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
processAttributes(context, attrs, defStyle);
}
- private void processAttributes(Context context, @Nullable AttributeSet attrs, int defStyle) {
+ private void processAttributes(final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
if (attrs == null) {
return;
}
- TypedArray types = context.obtainStyledAttributes(attrs, getAttributeNames(),
+ final TypedArray types = context.obtainStyledAttributes(attrs, getAttributeNames(),
defStyle, 0);
processAttributeValues(types);
@@ -42,7 +42,6 @@ public abstract class AbstractAttributeBasedPrefence extends Preference {
/**
* Evaluate the attributes which where requested in {@link AbstractAttributeBasedPrefence#getAttributeNames()}.
*
- * @param values
*/
protected abstract void processAttributeValues(TypedArray values);
diff --git a/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java
index 2f83028..7978d76 100644
--- a/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java
+++ b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java
@@ -11,10 +11,9 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import rx.Observable;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
import rx.functions.Func0;
-import rx.util.async.Async;
import android.app.ProgressDialog;
import android.content.Context;
@@ -25,11 +24,11 @@ import android.util.AttributeSet;
public abstract class AbstractCheckCredentialsPreference extends AbstractClickablePreference {
- public AbstractCheckCredentialsPreference(Context context, AttributeSet attrs) {
+ public AbstractCheckCredentialsPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public AbstractCheckCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ public AbstractCheckCredentialsPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@@ -57,7 +56,7 @@ public abstract class AbstractCheckCredentialsPreference extends AbstractClickab
}
@Override
- public boolean onPreferenceClick(Preference preference) {
+ public boolean onPreferenceClick(final Preference preference) {
final Resources res = settingsActivity.getResources();
final ImmutablePair<String, String> credentials = getCredentials();
@@ -74,10 +73,10 @@ public abstract class AbstractCheckCredentialsPreference extends AbstractClickab
loginDialog.setCancelable(false);
Cookies.clearCookies();
- AndroidObservable.bindActivity(settingsActivity, Async.start(new Func0<ImmutablePair<StatusCode, Observable<Drawable>>>() {
+ AppObservable.bindActivity(settingsActivity, Observable.defer(new Func0<Observable<ImmutablePair<StatusCode, Observable<Drawable>>>>() {
@Override
- public ImmutablePair<StatusCode, Observable<Drawable>> call() {
- return login();
+ public Observable<ImmutablePair<StatusCode, Observable<Drawable>>> call() {
+ return Observable.just(login());
}
})).subscribeOn(RxUtils.networkScheduler).subscribe(new Action1<ImmutablePair<StatusCode, Observable<Drawable>>>() {
@Override
diff --git a/main/src/cgeo/geocaching/settings/AbstractClickablePreference.java b/main/src/cgeo/geocaching/settings/AbstractClickablePreference.java
index f4080cd..57fdf36 100644
--- a/main/src/cgeo/geocaching/settings/AbstractClickablePreference.java
+++ b/main/src/cgeo/geocaching/settings/AbstractClickablePreference.java
@@ -10,18 +10,18 @@ abstract class AbstractClickablePreference extends Preference {
final SettingsActivity activity;
- public AbstractClickablePreference(Context context, AttributeSet attrs) {
+ public AbstractClickablePreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
activity = (SettingsActivity) context;
}
- public AbstractClickablePreference(Context context, AttributeSet attrs, int defStyle) {
+ public AbstractClickablePreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
activity = (SettingsActivity) context;
}
@Override
- protected View onCreateView(ViewGroup parent) {
+ protected View onCreateView(final ViewGroup parent) {
setOnPreferenceClickListener(getOnPreferenceClickListener(activity));
return super.onCreateView(parent);
}
diff --git a/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java b/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java
index 7091f01..afb0b7f 100644
--- a/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java
+++ b/main/src/cgeo/geocaching/settings/CapabilitiesPreference.java
@@ -23,20 +23,20 @@ public class CapabilitiesPreference extends AbstractAttributeBasedPrefence {
private String connectorCode;
- public CapabilitiesPreference(Context context) {
+ public CapabilitiesPreference(final Context context) {
super(context);
}
- public CapabilitiesPreference(Context context, AttributeSet attrs) {
+ public CapabilitiesPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public CapabilitiesPreference(Context context, AttributeSet attrs, int defStyle) {
+ public CapabilitiesPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@Override
- public View getView(View convertView, ViewGroup parent) {
+ public View getView(final View convertView, final ViewGroup parent) {
setOnPreferenceClickListener(new ClickListener());
return super.getView(convertView, parent);
}
@@ -44,15 +44,15 @@ public class CapabilitiesPreference extends AbstractAttributeBasedPrefence {
private final class ClickListener implements OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(final Preference preference) {
- WebView htmlView = new WebView(preference.getContext());
+ final WebView htmlView = new WebView(preference.getContext());
htmlView.loadDataWithBaseURL(null, createCapabilitiesMessage(), "text/html", "utf-8", null);
- AlertDialog.Builder builder = new AlertDialog.Builder(preference.getContext());
+ final AlertDialog.Builder builder = new AlertDialog.Builder(preference.getContext());
builder.setView(htmlView)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(R.string.settings_features)
.setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int id) {
+ public void onClick(final DialogInterface dialog, final int id) {
dialog.cancel();
}
});
@@ -63,11 +63,11 @@ public class CapabilitiesPreference extends AbstractAttributeBasedPrefence {
public String createCapabilitiesMessage() {
// TODO: this needs a better key for the connectors
- IConnector connector = ConnectorFactory.getConnector(connectorCode + "1234");
- StringBuilder builder = new StringBuilder("<p>"
+ final IConnector connector = ConnectorFactory.getConnector(connectorCode + "1234");
+ final StringBuilder builder = new StringBuilder("<p>"
+ TextUtils.htmlEncode(CgeoApplication.getInstance().getString(R.string.feature_description)) + "</p><ul>");
- for (String capability : connector.getCapabilities()) {
+ for (final String capability : connector.getCapabilities()) {
builder.append("<li>").append(TextUtils.htmlEncode(capability)).append("</li>");
}
@@ -76,7 +76,7 @@ public class CapabilitiesPreference extends AbstractAttributeBasedPrefence {
}
@Override
- protected void processAttributeValues(TypedArray values) {
+ protected void processAttributeValues(final TypedArray values) {
connectorCode = values.getString(0);
}
diff --git a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
index 35df787..00b46cc 100644
--- a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
+++ b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java
@@ -20,26 +20,26 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference {
private String urlButton;
private OnPreferenceChangeListener baseOnPrefChangeListener = null;
- public CheckBoxWithPopupPreference(Context context) {
+ public CheckBoxWithPopupPreference(final Context context) {
super(context);
}
- public CheckBoxWithPopupPreference(Context context, AttributeSet attrs) {
+ public CheckBoxWithPopupPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
processAttributes(context, attrs, 0);
}
- public CheckBoxWithPopupPreference(Context context, AttributeSet attrs, int defStyle) {
+ public CheckBoxWithPopupPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
processAttributes(context, attrs, defStyle);
}
- private void processAttributes(Context context, AttributeSet attrs, int defStyle) {
+ private void processAttributes(final Context context, final AttributeSet attrs, final int defStyle) {
if (attrs == null) {
return; // coward's retreat
}
- TypedArray types = context.obtainStyledAttributes(attrs, new int[] {
+ final TypedArray types = context.obtainStyledAttributes(attrs, new int[] {
R.attr.title, R.attr.text, R.attr.url, R.attr.urlButton },
defStyle, 0);
@@ -52,7 +52,7 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference {
}
@Override
- protected View onCreateView(ViewGroup parent) {
+ protected View onCreateView(final ViewGroup parent) {
if (baseOnPrefChangeListener == null) {
baseOnPrefChangeListener = getOnPreferenceChangeListener();
@@ -61,7 +61,7 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference {
// show dialog when checkbox enabled
setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
- public boolean onPreferenceChange(final Preference preference, Object newValue) {
+ public boolean onPreferenceChange(final Preference preference, final Object newValue) {
if (baseOnPrefChangeListener != null) {
baseOnPrefChangeListener.onPreferenceChange(preference, newValue);
}
diff --git a/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
index f5d9ab5..8f7da2c 100644
--- a/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
+++ b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
@@ -14,11 +14,11 @@ import android.util.AttributeSet;
public class CheckECCredentialsPreference extends AbstractCheckCredentialsPreference {
- public CheckECCredentialsPreference(Context context, AttributeSet attrs) {
+ public CheckECCredentialsPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public CheckECCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ public CheckECCredentialsPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
diff --git a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
index 0269f3b..04f406f 100644
--- a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
+++ b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java
@@ -13,11 +13,11 @@ import android.util.AttributeSet;
public class CheckGcCredentialsPreference extends AbstractCheckCredentialsPreference {
- public CheckGcCredentialsPreference(Context context, AttributeSet attrs) {
+ public CheckGcCredentialsPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public CheckGcCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ public CheckGcCredentialsPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@@ -31,8 +31,7 @@ public class CheckGcCredentialsPreference extends AbstractCheckCredentialsPrefer
final StatusCode loginResult = GCLogin.getInstance().login();
switch (loginResult) {
case NO_ERROR:
- GCLogin.detectGcCustomDate();
- return ImmutablePair.of(StatusCode.NO_ERROR, GCLogin.getInstance().downloadAvatarAndGetMemberStatus());
+ return ImmutablePair.of(StatusCode.NO_ERROR, GCLogin.getInstance().downloadAvatar());
default:
return ImmutablePair.of(loginResult, null);
}
diff --git a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
index af07041..267a0b3 100644
--- a/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
+++ b/main/src/cgeo/geocaching/settings/EditPasswordPreference.java
@@ -14,20 +14,20 @@ import android.util.AttributeSet;
*/
public class EditPasswordPreference extends EditTextPreference {
- public EditPasswordPreference(Context context) {
+ public EditPasswordPreference(final Context context) {
super(context);
}
- public EditPasswordPreference(Context context, AttributeSet attrs) {
+ public EditPasswordPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public EditPasswordPreference(Context context, AttributeSet attrs, int defStyle) {
+ public EditPasswordPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@Override
- public void setSummary(CharSequence summary) {
+ public void setSummary(final CharSequence summary) {
if (StringUtils.isBlank(summary)) {
super.setSummary(StringUtils.EMPTY);
} else {
diff --git a/main/src/cgeo/geocaching/settings/InfoPreference.java b/main/src/cgeo/geocaching/settings/InfoPreference.java
index 8040a62..d1ece92 100644
--- a/main/src/cgeo/geocaching/settings/InfoPreference.java
+++ b/main/src/cgeo/geocaching/settings/InfoPreference.java
@@ -39,22 +39,22 @@ public class InfoPreference extends AbstractAttributeBasedPrefence {
private LayoutInflater inflater;
- public InfoPreference(Context context) {
+ public InfoPreference(final Context context) {
super(context);
init(context);
}
- public InfoPreference(Context context, AttributeSet attrs) {
+ public InfoPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context);
}
- public InfoPreference(Context context, AttributeSet attrs, int defStyle) {
+ public InfoPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init(context);
}
- private void init(Context context) {
+ private void init(final Context context) {
inflater = ((Activity) context).getLayoutInflater();
setPersistent(false);
}
@@ -65,14 +65,14 @@ public class InfoPreference extends AbstractAttributeBasedPrefence {
}
@Override
- protected void processAttributeValues(TypedArray values) {
+ protected void processAttributeValues(final TypedArray values) {
text = values.getString(0);
url = values.getString(1);
urlButton = values.getString(2);
}
@Override
- protected View onCreateView(ViewGroup parent) {
+ protected View onCreateView(final ViewGroup parent) {
// show popup when clicked
setOnPreferenceClickListener(new OnPreferenceClickListener() {
@@ -91,14 +91,12 @@ public class InfoPreference extends AbstractAttributeBasedPrefence {
/**
* Add an info icon at the left hand side of the preference.
*
- * @param parent
- * @return
*/
- private View addInfoIcon(ViewGroup parent) {
- View preferenceView = super.onCreateView(parent);
+ private View addInfoIcon(final ViewGroup parent) {
+ final View preferenceView = super.onCreateView(parent);
- ImageView iconView = (ImageView) inflater.inflate(R.layout.preference_info_icon, parent, false);
- LinearLayout frame = (LinearLayout) preferenceView.findViewById(android.R.id.widget_frame);
+ final ImageView iconView = (ImageView) inflater.inflate(R.layout.preference_info_icon, parent, false);
+ final LinearLayout frame = (LinearLayout) preferenceView.findViewById(android.R.id.widget_frame);
frame.setVisibility(View.VISIBLE);
frame.addView(iconView);
diff --git a/main/src/cgeo/geocaching/settings/OAuthPreference.java b/main/src/cgeo/geocaching/settings/OAuthPreference.java
index 54bad6d..23f3a12 100644
--- a/main/src/cgeo/geocaching/settings/OAuthPreference.java
+++ b/main/src/cgeo/geocaching/settings/OAuthPreference.java
@@ -2,9 +2,9 @@ package cgeo.geocaching.settings;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
+import cgeo.geocaching.activity.OAuthAuthorizationActivity.OAuthParameters;
import cgeo.geocaching.connector.oc.OCAuthParams;
import cgeo.geocaching.connector.oc.OCAuthorizationActivity;
-import cgeo.geocaching.network.OAuthAuthorizationActivity.OAuthParameters;
import cgeo.geocaching.twitter.TwitterAuthorizationActivity;
import android.content.Context;
diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
index 84c343a..da20039 100644
--- a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
+++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java
@@ -13,7 +13,7 @@ import ch.boye.httpclientandroidlib.HttpResponse;
import org.apache.commons.lang3.StringUtils;
import rx.Observable;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action1;
import rx.functions.Func0;
@@ -24,11 +24,11 @@ import android.util.AttributeSet;
public class RegisterSend2CgeoPreference extends AbstractClickablePreference {
- public RegisterSend2CgeoPreference(Context context, AttributeSet attrs) {
+ public RegisterSend2CgeoPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public RegisterSend2CgeoPreference(Context context, AttributeSet attrs, int defStyle) {
+ public RegisterSend2CgeoPreference(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@@ -36,7 +36,7 @@ public class RegisterSend2CgeoPreference extends AbstractClickablePreference {
protected OnPreferenceClickListener getOnPreferenceClickListener(final SettingsActivity activity) {
return new OnPreferenceClickListener() {
@Override
- public boolean onPreferenceClick(Preference preference) {
+ public boolean onPreferenceClick(final Preference preference) {
// satisfy static code analysis
if (activity == null) {
return true;
@@ -55,23 +55,25 @@ public class RegisterSend2CgeoPreference extends AbstractClickablePreference {
activity.getString(R.string.init_sendToCgeo_registering), true);
progressDialog.setCancelable(false);
- AndroidObservable.bindActivity(activity, Observable.defer(new Func0<Observable<Integer>>() {
+ AppObservable.bindActivity(activity, Observable.defer(new Func0<Observable<Integer>>() {
@Override
public Observable<Integer> call() {
final String nam = StringUtils.defaultString(deviceName);
final String cod = StringUtils.defaultString(deviceCode);
final Parameters params = new Parameters("name", nam, "code", cod);
- HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params);
+ final HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params);
if (response != null && response.getStatusLine().getStatusCode() == 200) {
//response was OK
final String[] strings = StringUtils.split(Network.getResponseData(response), ',');
- Settings.setWebNameCode(nam, strings[0]);
- try {
- return Observable.from(Integer.parseInt(strings[1].trim()));
- } catch (final Exception e) {
- Log.e("RegisterSend2CgeoPreference", e);
+ if (strings != null) {
+ Settings.setWebNameCode(nam, strings[0]);
+ try {
+ return Observable.just(Integer.parseInt(strings[1].trim()));
+ } catch (final Exception e) {
+ Log.e("RegisterSend2CgeoPreference", e);
+ }
}
}
diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java
index d93f83f..c15bc1b 100644
--- a/main/src/cgeo/geocaching/settings/Settings.java
+++ b/main/src/cgeo/geocaching/settings/Settings.java
@@ -6,12 +6,11 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum;
import cgeo.geocaching.connector.capability.ICredentials;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.gc.GCConstants;
-import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.enumerations.CacheType;
-import cgeo.geocaching.enumerations.LiveMapStrategy.Strategy;
import cgeo.geocaching.enumerations.LogType;
-import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.maps.CGeoMap.MapMode;
import cgeo.geocaching.maps.MapProviderFactory;
//import cgeo.geocaching.maps.google.v1.GoogleMapProvider;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
@@ -35,6 +34,8 @@ import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
import android.os.Environment;
import android.preference.PreferenceManager;
@@ -49,6 +50,10 @@ import java.util.Locale;
*/
public class Settings {
+ /**
+ * On opening a map, we limit the _initial_ zoom. The user can still zoom out afterwards.
+ */
+ private static final int INITIAL_MAP_ZOOM_LIMIT = 16;
private static final char HISTORY_SEPARATOR = ',';
public static final int SHOW_WP_THRESHOLD_DEFAULT = 10;
public static final int SHOW_WP_THRESHOLD_MAX = 50;
@@ -66,11 +71,11 @@ public class Settings {
StringUtils.equals(Build.MODEL, "ST25i") || // Sony Xperia U
StringUtils.equals(Build.MODEL, "bq Aquaris 5"); // bq Aquaris 5
- private final static int unitsMetric = 1;
-
// twitter api keys
- private final static @NonNull String keyConsumerPublic = CryptUtils.rot13("ESnsCvAv3kEupF1GCR3jGj");
- private final static @NonNull String keyConsumerSecret = CryptUtils.rot13("7vQWceACV9umEjJucmlpFe9FCMZSeqIqfkQ2BnhV9x");
+ private final static @NonNull String TWITTER_KEY_CONSUMER_PUBLIC = CryptUtils.rot13("ESnsCvAv3kEupF1GCR3jGj");
+ private final static @NonNull String TWITTER_KEY_CONSUMER_SECRET = CryptUtils.rot13("7vQWceACV9umEjJucmlpFe9FCMZSeqIqfkQ2BnhV9x");
+
+ private static boolean useCompass = true;
public enum CoordInputFormatEnum {
Plain,
@@ -78,7 +83,7 @@ public class Settings {
Min,
Sec;
- static int DEFAULT_INT_VALUE = Min.ordinal();
+ static final int DEFAULT_INT_VALUE = Min.ordinal();
public static CoordInputFormatEnum fromInt(final int id) {
final CoordInputFormatEnum[] values = CoordInputFormatEnum.values();
@@ -109,13 +114,29 @@ public class Settings {
}
private static void migrateSettings() {
- // migrate from non standard file location and integer based boolean types
- final int oldVersion = getInt(R.string.pref_settingsversion, 0);
- if (oldVersion < 1) {
- final String oldPreferencesName = "cgeo.pref";
- final SharedPreferences old = CgeoApplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE);
+ final int LATEST_PREFERENCES_VERSION = 2;
+ final int currentVersion = getInt(R.string.pref_settingsversion, 0);
+
+ // No need to migrate if we are up to date.
+ if (currentVersion == LATEST_PREFERENCES_VERSION) {
+ return;
+ }
+
+ // No need to migrate if we don't have older settings, defaults will be used instead.
+ final String preferencesNameV0 = "cgeo.pref";
+ final SharedPreferences prefsV0 = CgeoApplication.getInstance().getSharedPreferences(preferencesNameV0, Context.MODE_PRIVATE);
+ if (currentVersion == 0 && prefsV0.getAll().isEmpty()) {
+ final Editor e = sharedPrefs.edit();
+ e.putInt(getKey(R.string.pref_settingsversion), LATEST_PREFERENCES_VERSION);
+ e.apply();
+ return;
+ }
+
+ if (currentVersion < 1) {
+ // migrate from non standard file location and integer based boolean types
final Editor e = sharedPrefs.edit();
+<<<<<<< HEAD
e.putString(getKey(R.string.pref_temp_twitter_token_secret), old.getString(getKey(R.string.pref_temp_twitter_token_secret), null));
e.putString(getKey(R.string.pref_temp_twitter_token_public), old.getString(getKey(R.string.pref_temp_twitter_token_public), null));
e.putBoolean(getKey(R.string.pref_help_shown), old.getInt(getKey(R.string.pref_help_shown), 0) != 0);
@@ -171,16 +192,72 @@ public class Settings {
e.putBoolean(getKey(R.string.pref_debug), old.getBoolean(getKey(R.string.pref_debug), false));
e.putBoolean(getKey(R.string.pref_hidelivemaphint), old.getInt(getKey(R.string.pref_hidelivemaphint), 0) != 0);
e.putInt(getKey(R.string.pref_livemaphintshowcount), old.getInt(getKey(R.string.pref_livemaphintshowcount), 0));
+=======
+ e.putString(getKey(R.string.pref_temp_twitter_token_secret), prefsV0.getString(getKey(R.string.pref_temp_twitter_token_secret), null));
+ e.putString(getKey(R.string.pref_temp_twitter_token_public), prefsV0.getString(getKey(R.string.pref_temp_twitter_token_public), null));
+ e.putBoolean(getKey(R.string.pref_help_shown), prefsV0.getInt(getKey(R.string.pref_help_shown), 0) != 0);
+ e.putFloat(getKey(R.string.pref_anylongitude), prefsV0.getFloat(getKey(R.string.pref_anylongitude), 0));
+ e.putFloat(getKey(R.string.pref_anylatitude), prefsV0.getFloat(getKey(R.string.pref_anylatitude), 0));
+ e.putBoolean(getKey(R.string.pref_offlinemaps), 0 != prefsV0.getInt(getKey(R.string.pref_offlinemaps), 1));
+ e.putBoolean(getKey(R.string.pref_offlinewpmaps), 0 != prefsV0.getInt(getKey(R.string.pref_offlinewpmaps), 0));
+ e.putString(getKey(R.string.pref_webDeviceCode), prefsV0.getString(getKey(R.string.pref_webDeviceCode), null));
+ e.putString(getKey(R.string.pref_webDeviceName), prefsV0.getString(getKey(R.string.pref_webDeviceName), null));
+ e.putBoolean(getKey(R.string.pref_maplive), prefsV0.getInt(getKey(R.string.pref_maplive), 1) != 0);
+ e.putInt(getKey(R.string.pref_mapsource), prefsV0.getInt(getKey(R.string.pref_mapsource), MAP_SOURCE_DEFAULT));
+ e.putBoolean(getKey(R.string.pref_twitter), 0 != prefsV0.getInt(getKey(R.string.pref_twitter), 0));
+ e.putBoolean(getKey(R.string.pref_showaddress), 0 != prefsV0.getInt(getKey(R.string.pref_showaddress), 1));
+ e.putBoolean(getKey(R.string.pref_showcaptcha), prefsV0.getBoolean(getKey(R.string.pref_showcaptcha), false));
+ e.putBoolean(getKey(R.string.pref_maptrail), prefsV0.getInt(getKey(R.string.pref_maptrail), 1) != 0);
+ e.putInt(getKey(R.string.pref_lastmapzoom), prefsV0.getInt(getKey(R.string.pref_lastmapzoom), 14));
+ e.putBoolean(getKey(R.string.pref_livelist), 0 != prefsV0.getInt(getKey(R.string.pref_livelist), 1));
+ e.putBoolean(getKey(R.string.pref_units_imperial), prefsV0.getInt(getKey(R.string.pref_units_imperial), 1) != 1);
+ e.putBoolean(getKey(R.string.pref_skin), prefsV0.getInt(getKey(R.string.pref_skin), 0) != 0);
+ e.putInt(getKey(R.string.pref_lastusedlist), prefsV0.getInt(getKey(R.string.pref_lastusedlist), StoredList.STANDARD_LIST_ID));
+ e.putString(getKey(R.string.pref_cachetype), prefsV0.getString(getKey(R.string.pref_cachetype), CacheType.ALL.id));
+ e.putString(getKey(R.string.pref_twitter_token_secret), prefsV0.getString(getKey(R.string.pref_twitter_token_secret), null));
+ e.putString(getKey(R.string.pref_twitter_token_public), prefsV0.getString(getKey(R.string.pref_twitter_token_public), null));
+ e.putInt(getKey(R.string.pref_version), prefsV0.getInt(getKey(R.string.pref_version), 0));
+ e.putBoolean(getKey(R.string.pref_autoloaddesc), 0 != prefsV0.getInt(getKey(R.string.pref_autoloaddesc), 1));
+ e.putBoolean(getKey(R.string.pref_ratingwanted), prefsV0.getBoolean(getKey(R.string.pref_ratingwanted), true));
+ e.putBoolean(getKey(R.string.pref_friendlogswanted), prefsV0.getBoolean(getKey(R.string.pref_friendlogswanted), true));
+ e.putBoolean(getKey(R.string.pref_useenglish), prefsV0.getBoolean(getKey(R.string.pref_useenglish), false));
+ e.putBoolean(getKey(R.string.pref_usecompass), 0 != prefsV0.getInt(getKey(R.string.pref_usecompass), 1));
+ e.putBoolean(getKey(R.string.pref_trackautovisit), prefsV0.getBoolean(getKey(R.string.pref_trackautovisit), false));
+ e.putBoolean(getKey(R.string.pref_sigautoinsert), prefsV0.getBoolean(getKey(R.string.pref_sigautoinsert), false));
+ e.putBoolean(getKey(R.string.pref_logimages), prefsV0.getBoolean(getKey(R.string.pref_logimages), false));
+ e.putBoolean(getKey(R.string.pref_excludedisabled), 0 != prefsV0.getInt(getKey(R.string.pref_excludedisabled), 0));
+ e.putBoolean(getKey(R.string.pref_excludemine), 0 != prefsV0.getInt(getKey(R.string.pref_excludemine), 0));
+ e.putString(getKey(R.string.pref_mapfile), prefsV0.getString(getKey(R.string.pref_mapfile), null));
+ e.putString(getKey(R.string.pref_signature), prefsV0.getString(getKey(R.string.pref_signature), null));
+ e.putString(getKey(R.string.pref_pass_vote), prefsV0.getString(getKey(R.string.pref_pass_vote), null));
+ e.putString(getKey(R.string.pref_password), prefsV0.getString(getKey(R.string.pref_password), null));
+ e.putString(getKey(R.string.pref_username), prefsV0.getString(getKey(R.string.pref_username), null));
+ e.putString(getKey(R.string.pref_memberstatus), prefsV0.getString(getKey(R.string.pref_memberstatus), ""));
+ e.putInt(getKey(R.string.pref_coordinputformat), prefsV0.getInt(getKey(R.string.pref_coordinputformat), CoordInputFormatEnum.DEFAULT_INT_VALUE));
+ e.putBoolean(getKey(R.string.pref_log_offline), prefsV0.getBoolean(getKey(R.string.pref_log_offline), false));
+ e.putBoolean(getKey(R.string.pref_choose_list), prefsV0.getBoolean(getKey(R.string.pref_choose_list), true));
+ e.putBoolean(getKey(R.string.pref_loaddirectionimg), prefsV0.getBoolean(getKey(R.string.pref_loaddirectionimg), true));
+ e.putString(getKey(R.string.pref_gccustomdate), prefsV0.getString(getKey(R.string.pref_gccustomdate), GCConstants.DEFAULT_GC_DATE));
+ e.putInt(getKey(R.string.pref_showwaypointsthreshold), prefsV0.getInt(getKey(R.string.pref_showwaypointsthreshold), SHOW_WP_THRESHOLD_DEFAULT));
+ e.putString(getKey(R.string.pref_cookiestore), prefsV0.getString(getKey(R.string.pref_cookiestore), null));
+ e.putBoolean(getKey(R.string.pref_opendetailslastpage), prefsV0.getBoolean(getKey(R.string.pref_opendetailslastpage), false));
+ e.putInt(getKey(R.string.pref_lastdetailspage), prefsV0.getInt(getKey(R.string.pref_lastdetailspage), 1));
+ e.putInt(getKey(R.string.pref_defaultNavigationTool), prefsV0.getInt(getKey(R.string.pref_defaultNavigationTool), NavigationAppsEnum.COMPASS.id));
+ e.putInt(getKey(R.string.pref_defaultNavigationTool2), prefsV0.getInt(getKey(R.string.pref_defaultNavigationTool2), NavigationAppsEnum.INTERNAL_MAP.id));
+ e.putInt(getKey(R.string.pref_livemapstrategy), prefsV0.getInt(getKey(R.string.pref_livemapstrategy), LivemapStrategy.AUTO.id));
+ e.putBoolean(getKey(R.string.pref_debug), prefsV0.getBoolean(getKey(R.string.pref_debug), false));
+ e.putInt(getKey(R.string.pref_livemaphintshowcount), prefsV0.getInt(getKey(R.string.pref_livemaphintshowcount), 0));
+>>>>>>> 59b8b2e26a7fff6072c4d5d96f51035dc900e0bc
e.putInt(getKey(R.string.pref_settingsversion), 1); // mark migrated
- e.commit();
+ e.apply();
}
// changes for new settings dialog
- if (oldVersion < 2) {
+ if (currentVersion < 2) {
final Editor e = sharedPrefs.edit();
- e.putBoolean(getKey(R.string.pref_units), !isUseImperialUnits());
+ e.putBoolean(getKey(R.string.pref_units_imperial), useImperialUnits());
// show waypoints threshold now as a slider
int wpThreshold = getWayPointsThreshold();
@@ -209,7 +286,7 @@ public class Settings {
e.putString(getKey(R.string.pref_gpxExportDir), getGpxExportDir());
e.putInt(getKey(R.string.pref_settingsversion), 2); // mark migrated
- e.commit();
+ e.apply();
}
}
@@ -237,40 +314,40 @@ public class Settings {
return sharedPrefs.getFloat(getKey(prefKeyId), defaultValue);
}
- protected static boolean putString(final int prefKeyId, final String value) {
+ protected static void putString(final int prefKeyId, final String value) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.putString(getKey(prefKeyId), value);
- return edit.commit();
+ edit.apply();
}
- protected static boolean putBoolean(final int prefKeyId, final boolean value) {
+ protected static void putBoolean(final int prefKeyId, final boolean value) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.putBoolean(getKey(prefKeyId), value);
- return edit.commit();
+ edit.apply();
}
- private static boolean putInt(final int prefKeyId, final int value) {
+ private static void putInt(final int prefKeyId, final int value) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.putInt(getKey(prefKeyId), value);
- return edit.commit();
+ edit.apply();
}
- private static boolean putLong(final int prefKeyId, final long value) {
+ private static void putLong(final int prefKeyId, final long value) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.putLong(getKey(prefKeyId), value);
- return edit.commit();
+ edit.apply();
}
- private static boolean putFloat(final int prefKeyId, final float value) {
+ private static void putFloat(final int prefKeyId, final float value) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.putFloat(getKey(prefKeyId), value);
- return edit.commit();
+ edit.apply();
}
- private static boolean remove(final int prefKeyId) {
+ private static void remove(final int prefKeyId) {
final SharedPreferences.Editor edit = sharedPrefs.edit();
edit.remove(getKey(prefKeyId));
- return edit.commit();
+ edit.apply();
}
private static boolean contains(final int prefKeyId) {
@@ -317,7 +394,7 @@ public class Settings {
}
public static String getUsername() {
- return getString(R.string.pref_username, null);
+ return getString(R.string.pref_username, StringUtils.EMPTY);
}
public static boolean isGCConnectorActive() {
@@ -333,19 +410,20 @@ public class Settings {
}
public static boolean isGCPremiumMember() {
- // Basic Member, Premium Member, ???
- return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getGCMemberStatus());
+ final String memberStatus = Settings.getGCMemberStatus();
+ return StringUtils.equalsIgnoreCase(memberStatus, GCConstants.MEMBER_STATUS_PREMIUM) ||
+ StringUtils.equalsIgnoreCase(memberStatus, GCConstants.MEMBER_STATUS_CHARTER);
}
public static String getGCMemberStatus() {
return getString(R.string.pref_memberstatus, "");
}
- public static boolean setGCMemberStatus(final String memberStatus) {
+ public static void setGCMemberStatus(final String memberStatus) {
if (StringUtils.isBlank(memberStatus)) {
- return remove(R.string.pref_memberstatus);
+ remove(R.string.pref_memberstatus);
}
- return putString(R.string.pref_memberstatus, memberStatus);
+ putString(R.string.pref_memberstatus, memberStatus);
}
public static ImmutablePair<String, String> getTokenPair(final int tokenPublicPrefKey, final int tokenSecretPrefKey) {
@@ -375,10 +453,7 @@ public class Settings {
}
public static boolean isGCvoteLogin() {
- final String preUsername = getString(R.string.pref_username, null);
- final String prePassword = getString(R.string.pref_pass_vote, null);
-
- return !StringUtils.isBlank(preUsername) && !StringUtils.isBlank(prePassword);
+ return getGCvoteLogin() != null;
}
public static ImmutablePair<String, String> getGCvoteLogin() {
@@ -396,19 +471,33 @@ public class Settings {
return getString(R.string.pref_signature, StringUtils.EMPTY);
}
- public static boolean setCookieStore(final String cookies) {
+ public static void setCookieStore(final String cookies) {
if (StringUtils.isBlank(cookies)) {
// erase cookies
- return remove(R.string.pref_cookiestore);
+ remove(R.string.pref_cookiestore);
}
// save cookies
- return putString(R.string.pref_cookiestore, cookies);
+ putString(R.string.pref_cookiestore, cookies);
}
public static String getCookieStore() {
return getString(R.string.pref_cookiestore, null);
}
+ public static void setUseGooglePlayServices(final boolean value) {
+ putBoolean(R.string.pref_googleplayservices, value);
+ }
+
+ public static boolean useGooglePlayServices() {
+ // By defaut, enable play services starting from ICS.
+ return CgeoApplication.getInstance().isGooglePlayServicesAvailable() &&
+ getBoolean(R.string.pref_googleplayservices, VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH);
+ }
+
+ public static boolean useLowPowerMode() {
+ return getBoolean(R.string.pref_lowpowermode, false);
+ }
+
/**
* @param cacheType
* The cache type used for future filtering
@@ -442,12 +531,11 @@ public class Settings {
return getString(R.string.pref_mapfile, null);
}
- public static boolean setMapFile(final String mapFile) {
- final boolean result = putString(R.string.pref_mapfile, mapFile);
+ public static void setMapFile(final String mapFile) {
+ putString(R.string.pref_mapfile, mapFile);
if (mapFile != null) {
setMapFileDirectory(new File(mapFile).getParent());
}
- return result;
}
public static String getMapFileDirectory() {
@@ -462,10 +550,9 @@ public class Settings {
return null;
}
- public static boolean setMapFileDirectory(final String mapFileDirectory) {
- final boolean result = putString(R.string.pref_mapDirectory, mapFileDirectory);
+ public static void setMapFileDirectory(final String mapFileDirectory) {
+ putString(R.string.pref_mapDirectory, mapFileDirectory);
MapsforgeMapProvider.getInstance().updateOfflineMaps();
- return result;
}
public static boolean isValidMapFile() {
@@ -506,10 +593,11 @@ public class Settings {
/**
* @return User selected date format on GC.com
- * @see GCLogin#GC_CUSTOM_DATE_FORMATS
*/
public static String getGcCustomDate() {
- return getString(R.string.pref_gccustomdate, null);
+ // We might have some users whose stored value is null, which is invalid. In this case, we use the default.
+ return StringUtils.defaultString(getString(R.string.pref_gccustomdate, GCConstants.DEFAULT_GC_DATE),
+ GCConstants.DEFAULT_GC_DATE);
}
public static boolean isExcludeMyCaches() {
@@ -572,11 +660,15 @@ public class Settings {
return getBoolean(R.string.pref_sigautoinsert, false);
}
- public static boolean isUseImperialUnits() {
- return getBoolean(R.string.pref_units, getImperialUnitsDefault());
+ public static void setUseImperialUnits(final boolean useImperialUnits) {
+ putBoolean(R.string.pref_units_imperial, useImperialUnits);
+ }
+
+ public static boolean useImperialUnits() {
+ return getBoolean(R.string.pref_units_imperial, useImperialUnitsByDefault());
}
- static boolean getImperialUnitsDefault() {
+ static boolean useImperialUnitsByDefault() {
final String countryCode = Locale.getDefault().getCountry();
return "US".equals(countryCode) // USA
|| "LR".equals(countryCode) // Liberia
@@ -592,21 +684,55 @@ public class Settings {
}
public static boolean isMapTrail() {
- return getBoolean(R.string.pref_maptrail, true);
+ return getBoolean(R.string.pref_maptrail, false);
}
public static void setMapTrail(final boolean showTrail) {
putBoolean(R.string.pref_maptrail, showTrail);
}
- public static int getMapZoom() {
- return getInt(R.string.pref_lastmapzoom, 14);
+ /**
+ * Get last used zoom of the internal map. Differentiate between two use cases for a map of multiple caches (e.g.
+ * live map) and the map of a single cache (which is often zoomed in more deep).
+ */
+ public static int getMapZoom(final MapMode mapMode) {
+ if (mapMode == MapMode.SINGLE || mapMode == MapMode.COORDS) {
+ return getCacheZoom();
+ }
+ return getMapZoom();
}
- public static void setMapZoom(final int mapZoomLevel) {
+ public static void setMapZoom(final MapMode mapMode, final int zoomLevel) {
+ if (mapMode == MapMode.SINGLE || mapMode == MapMode.COORDS) {
+ setCacheZoom(zoomLevel);
+ }
+ else {
+ setMapZoom(zoomLevel);
+ }
+ }
+
+ /**
+ * @return zoom used for the (live) map
+ */
+ private static int getMapZoom() {
+ return Math.max(getInt(R.string.pref_lastmapzoom, 14), INITIAL_MAP_ZOOM_LIMIT);
+ }
+
+ private static void setMapZoom(final int mapZoomLevel) {
putInt(R.string.pref_lastmapzoom, mapZoomLevel);
}
+ /**
+ * @return zoom used for the map of a single cache
+ */
+ private static int getCacheZoom() {
+ return Math.max(getInt(R.string.pref_cache_zoom, 14), INITIAL_MAP_ZOOM_LIMIT);
+ }
+
+ private static void setCacheZoom(final int zoomLevel) {
+ putInt(R.string.pref_cache_zoom, zoomLevel);
+ }
+
public static GeoPointImpl getMapCenter() {
return getMapProvider().getMapItemFactory()
.getGeoPointBase(new Geopoint(getInt(R.string.pref_lastmaplat, 0) / 1e6,
@@ -627,7 +753,7 @@ public class Settings {
// mapSource = MapProviderFactory.getMapSource(id);
if (mapSource != null) {
// don't use offline maps if the map file is not valid
- if ((!(mapSource instanceof OfflineMapSource)) || (isValidMapFile())) {
+ if (!(mapSource instanceof OfflineMapSource) || isValidMapFile()) {
return mapSource;
}
}
@@ -646,9 +772,7 @@ public class Settings {
private static final int HISTORY_SIZE = 10;
/**
- * convert old preference ids for maps (based on constant values) into new hash based ids
- *
- * @return
+ * Convert old preference ids for maps (based on constant values) into new hash based ids.
*/
// private static int getConvertedMapId() {
// final int id = Integer.parseInt(getString(R.string.pref_mapsource,
@@ -675,7 +799,7 @@ public class Settings {
// return id;
// }
- public static void setMapSource(final MapSource newMapSource) {
+ public static synchronized void setMapSource(final MapSource newMapSource) {
putString(R.string.pref_mapsource, String.valueOf(newMapSource.getNumericalId()));
if (newMapSource instanceof OfflineMapSource) {
setMapFile(((OfflineMapSource) newMapSource).getFileName());
@@ -704,11 +828,11 @@ public class Settings {
}
public static boolean isUseCompass() {
- return getBoolean(R.string.pref_usecompass, true);
+ return useCompass;
}
- public static void setUseCompass(final boolean useCompass) {
- putBoolean(R.string.pref_usecompass, useCompass);
+ public static void setUseCompass(final boolean value) {
+ useCompass = value;
}
public static boolean isLightSkin() {
@@ -716,13 +840,13 @@ public class Settings {
}
@NonNull
- public static String getKeyConsumerPublic() {
- return keyConsumerPublic;
+ public static String getTwitterKeyConsumerPublic() {
+ return TWITTER_KEY_CONSUMER_PUBLIC;
}
@NonNull
- public static String getKeyConsumerSecret() {
- return keyConsumerSecret;
+ public static String getTwitterKeyConsumerSecret() {
+ return TWITTER_KEY_CONSUMER_SECRET;
}
public static String getWebDeviceCode() {
@@ -734,13 +858,14 @@ public class Settings {
}
public static String getWebDeviceName() {
- return getString(R.string.pref_webDeviceName, android.os.Build.MODEL);
+ return getString(R.string.pref_webDeviceName, Build.MODEL);
}
/**
* @return The cache type used for filtering or ALL if no filter is active.
* Returns never null
*/
+ @NonNull
public static CacheType getCacheType() {
return CacheType.getById(getString(R.string.pref_cachetype, CacheType.ALL.id));
}
@@ -838,11 +963,11 @@ public class Settings {
String.valueOf(NavigationAppsEnum.INTERNAL_MAP.id)));
}
- public static Strategy getLiveMapStrategy() {
- return Strategy.getById(getInt(R.string.pref_livemapstrategy, Strategy.AUTO.id));
+ public static LivemapStrategy getLiveMapStrategy() {
+ return LivemapStrategy.getById(getInt(R.string.pref_livemapstrategy, LivemapStrategy.AUTO.id));
}
- public static void setLiveMapStrategy(final Strategy strategy) {
+ public static void setLiveMapStrategy(final LivemapStrategy strategy) {
putInt(R.string.pref_livemapstrategy, strategy.id);
}
@@ -850,14 +975,6 @@ public class Settings {
return Log.isDebug();
}
- public static boolean getHideLiveMapHint() {
- return getBoolean(R.string.pref_hidelivemaphint, false);
- }
-
- public static void setHideLiveHint(final boolean hide) {
- putBoolean(R.string.pref_hidelivemaphint, hide);
- }
-
public static int getLiveMapHintShowCount() {
return getInt(R.string.pref_livemaphintshowcount, 0);
}
@@ -986,9 +1103,7 @@ public class Settings {
}
/**
- * remember date of last field note export
- *
- * @param date
+ * Remember date of last field note export.
*/
public static void setFieldnoteExportDate(final long date) {
putLong(R.string.pref_fieldNoteExportDate, date);
@@ -999,9 +1114,7 @@ public class Settings {
}
/**
- * remember the state of the "Upload" checkbox in the field notes export dialog
- *
- * @param upload
+ * Remember the state of the "Upload" checkbox in the field notes export dialog.
*/
public static void setFieldNoteExportUpload(final boolean upload) {
putBoolean(R.string.pref_fieldNoteExportUpload, upload);
@@ -1012,9 +1125,7 @@ public class Settings {
}
/**
- * remember the state of the "Only new" checkbox in the field notes export dialog
- *
- * @param onlyNew
+ * Remember the state of the "Only new" checkbox in the field notes export dialog.
*/
public static void setFieldNoteExportOnlyNew(final boolean onlyNew) {
putBoolean(R.string.pref_fieldNoteExportOnlyNew, onlyNew);
@@ -1054,7 +1165,32 @@ public class Settings {
return getBoolean(R.string.pref_hardware_acceleration, !HW_ACCEL_DISABLED_BY_DEFAULT);
}
- public static boolean setUseHardwareAcceleration(final boolean useHardwareAcceleration) {
- return putBoolean(R.string.pref_hardware_acceleration, useHardwareAcceleration);
+ public static void setUseHardwareAcceleration(final boolean useHardwareAcceleration) {
+ putBoolean(R.string.pref_hardware_acceleration, useHardwareAcceleration);
+ }
+
+ public static String getLastCacheLog() {
+ return getString(R.string.pref_last_cache_log, StringUtils.EMPTY);
+ }
+
+ public static void setLastCacheLog(final String log) {
+ putString(R.string.pref_last_cache_log, log);
+ }
+
+ public static String getLastTrackableLog() {
+ return getString(R.string.pref_last_trackable_log, StringUtils.EMPTY);
+ }
+
+ public static void setLastTrackableLog(final String log) {
+ putString(R.string.pref_last_trackable_log, log);
+ }
+
+ @Nullable
+ public static String getHomeLocation() {
+ return getString(R.string.pref_home_location, null);
+ }
+
+ public static void setHomeLocation(@NonNull final String homeLocation) {
+ putString(R.string.pref_home_location, homeLocation);
}
}
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index df6e680..6e3ba0e 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -1,7 +1,5 @@
package cgeo.geocaching.settings;
-import butterknife.ButterKnife;
-
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.DataStore;
import cgeo.geocaching.Intents;
@@ -14,13 +12,19 @@ import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.files.SimpleDirChooser;
import cgeo.geocaching.maps.MapProviderFactory;
import cgeo.geocaching.maps.interfaces.MapSource;
+import cgeo.geocaching.network.AndroidBeam;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.utils.DatabaseBackupUtils;
import cgeo.geocaching.utils.DebugUtils;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.RxUtils;
import org.apache.commons.lang3.StringUtils;
import org.openintents.intents.FileManagerIntents;
+import rx.functions.Action0;
+import rx.schedulers.Schedulers;
+
import android.app.ProgressDialog;
import android.app.backup.BackupManager;
import android.content.ActivityNotFoundException;
@@ -90,12 +94,14 @@ public class SettingsActivity extends PreferenceActivity {
setTheme(Settings.isLightSkin() && Build.VERSION.SDK_INT > 10 ? R.style.settings_light : R.style.settings);
super.onCreate(savedInstanceState);
- initHardwareAccelerationPreferences();
+ initDeviceSpecificPreferences();
+ initUnitPreferences();
SettingsActivity.addPreferencesFromResource(this, R.xml.preferences);
initPreferences();
final Intent intent = getIntent();
openInitialScreen(intent.getIntExtra(INTENT_OPEN_SCREEN, 0));
+ AndroidBeam.disable(this);
}
private void openInitialScreen(final int initialScreen) {
@@ -126,6 +132,7 @@ public class SettingsActivity extends PreferenceActivity {
initDefaultNavigationPreferences();
initBackupButtons();
initDbLocationPreference();
+ initGeoDirPreferences();
initDebugPreference();
initBasicMemberPreferences();
initSend2CgeoPreferences();
@@ -143,7 +150,6 @@ public class SettingsActivity extends PreferenceActivity {
R.string.pref_ecusername, R.string.pref_ecpassword, R.string.pref_ec_icons }) {
bindSummaryToStringValue(k);
}
- getPreference(R.string.pref_units).setDefaultValue(Settings.getImperialUnitsDefault());
}
private void initNavigationMenuPreferences() {
@@ -278,7 +284,7 @@ public class SettingsActivity extends PreferenceActivity {
/**
* Fire up a directory chooser on click on the preference.
*
- * @see #onActivityResult() for processing of the selected directory
+ * The result can be processed using {@link android.app.Activity#onActivityResult}.
*
* @param dct
* type of directory to be selected
@@ -297,7 +303,7 @@ public class SettingsActivity extends PreferenceActivity {
dirChooser.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT,
getString(android.R.string.ok));
startActivityForResult(dirChooser, dct.requestCode);
- } catch (final android.content.ActivityNotFoundException ex) {
+ } catch (final ActivityNotFoundException ignored) {
// OI file manager not available
final Intent dirChooser = new Intent(this, SimpleDirChooser.class);
dirChooser.putExtra(Intents.EXTRA_START_DIR, startDirectory);
@@ -323,13 +329,14 @@ public class SettingsActivity extends PreferenceActivity {
backup.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
- return DatabaseBackupUtils.createBackup(SettingsActivity.this, new Runnable() {
+ DatabaseBackupUtils.createBackup(SettingsActivity.this, new Runnable() {
@Override
public void run() {
VALUE_CHANGE_LISTENER.onPreferenceChange(SettingsActivity.this.getPreference(R.string.pref_fakekey_preference_backup_info), "");
}
});
+ return true;
}
});
@@ -354,37 +361,41 @@ public class SettingsActivity extends PreferenceActivity {
final 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() {
+ RxUtils.andThenOnUi(Schedulers.io(), new Action0() {
@Override
- public void run() {
+ public void call() {
DataStore.removeObsoleteCacheDirectories();
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- dialog.dismiss();
- }
- });
}
- }.start();
-
+ }, new Action0() {
+ @Override
+ public void call() {
+ dialog.dismiss();
+ }
+ });
return true;
- }
- });
+ }
+ });
final Preference memoryDumpPref = getPreference(R.string.pref_memory_dump);
memoryDumpPref
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override public boolean onPreferenceClick(
- final Preference preference) {
- DebugUtils.createMemoryDump(SettingsActivity.this);
- return true;
- }
- });
+ @Override
+ public boolean onPreferenceClick(
+ final Preference preference) {
+ DebugUtils.createMemoryDump(SettingsActivity.this);
+ return true;
+ }
+ });
}
- public static void initHardwareAccelerationPreferences() {
- // We have to ensure that the preference is initialized so that devices with hardware acceleration disabled
- // get the appropriate value.
+ public static void initDeviceSpecificPreferences() {
+ // We have to ensure that those preferences are initialized so that devices with specific default values
+ // will get the appropriate ones.
Settings.setUseHardwareAcceleration(Settings.useHardwareAcceleration());
+ Settings.setUseGooglePlayServices(Settings.useGooglePlayServices());
+ }
+
+ private static void initUnitPreferences() {
+ Settings.setUseImperialUnits(Settings.useImperialUnits());
}
private void initDbLocationPreference() {
@@ -413,6 +424,28 @@ public class SettingsActivity extends PreferenceActivity {
});
}
+ private void initGeoDirPreferences() {
+ final Sensors sensors = Sensors.getInstance();
+ final Preference playServices = getPreference(R.string.pref_googleplayservices);
+ playServices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(final Preference preference, final Object newValue) {
+ sensors.setupGeoDataObservables((Boolean) newValue, Settings.useLowPowerMode());
+ return true;
+ }
+ });
+ playServices.setEnabled(CgeoApplication.getInstance().isGooglePlayServicesAvailable());
+ getPreference(R.string.pref_lowpowermode).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(final Preference preference, final Object newValue) {
+ final Boolean useLowPower = (Boolean) newValue;
+ sensors.setupGeoDataObservables(Settings.useGooglePlayServices(), useLowPower);
+ sensors.setupDirectionObservable(useLowPower);
+ return true;
+ }
+ });
+ }
+
void initBasicMemberPreferences() {
getPreference(R.string.preference_screen_basicmembers)
.setEnabled(!Settings.isGCPremiumMember());
@@ -570,7 +603,7 @@ public class SettingsActivity extends PreferenceActivity {
final int mapSourceId = Integer.parseInt(stringValue);
mapSource = MapProviderFactory.getMapSource(mapSourceId);
} catch (final NumberFormatException e) {
- Log.e("SettingsActivity.onPreferenceChange: bad source id '" + stringValue + "'");
+ Log.e("SettingsActivity.onPreferenceChange: bad source id '" + stringValue + "'", e);
mapSource = null;
}
// If there is no corresponding map source (because some map sources were
@@ -676,8 +709,6 @@ public class SettingsActivity extends PreferenceActivity {
/**
* auto-care for the summary of the preference of string type with this key
- *
- * @param key
*/
private void bindSummaryToStringValue(final int key) {
diff --git a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
index 968dce5..d7c46e1 100644
--- a/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
+++ b/main/src/cgeo/geocaching/sorting/AbstractCacheComparator.java
@@ -9,7 +9,7 @@ import org.apache.commons.lang3.StringUtils;
* abstract super implementation for all cache comparators
*
*/
-public abstract class AbstractCacheComparator implements CacheComparator {
+abstract class AbstractCacheComparator implements CacheComparator {
@Override
public final int compare(final Geocache cache1, final Geocache cache2) {
@@ -35,9 +35,11 @@ public abstract class AbstractCacheComparator implements CacheComparator {
* 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.
- *
+ * The default implementation returns <code>true</code> and can be overridden if needed in sub classes.
+ *
* @param cache
+ * the cache to be sorted
+ *
* @return <code>true</code> if the cache holds the necessary data to be compared meaningfully
*/
@SuppressWarnings("static-method")
@@ -51,8 +53,6 @@ public abstract class AbstractCacheComparator implements CacheComparator {
* A cache is smaller than another cache if it is desirable to show it first when presented to the user.
* For example, a highly rated cache must be considered smaller than a poorly rated one.
*
- * @param cache1
- * @param cache2
* @return an integer < 0 if cache1 is less than cache2, 0 if they are equal, and > 0 if cache1 is greater than
* cache2.
*/
diff --git a/main/src/cgeo/geocaching/sorting/DateComparator.java b/main/src/cgeo/geocaching/sorting/DateComparator.java
index 7913941..347eb44 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.CgeoApplication;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.sensors.Sensors;
import java.util.ArrayList;
import java.util.Date;
@@ -9,21 +9,16 @@ import java.util.Date;
/**
* compares caches by date
*/
-public class DateComparator extends AbstractCacheComparator {
+class DateComparator extends AbstractCacheComparator {
@Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
+ protected int compareCaches(final Geocache cache1, final Geocache cache2) {
final Date date1 = cache1.getHiddenDate();
final Date date2 = cache2.getHiddenDate();
if (date1 != null && date2 != null) {
final int dateDifference = date1.compareTo(date2);
- // for equal dates, sort by distance
if (dateDifference == 0) {
- final ArrayList<Geocache> list = new ArrayList<>();
- list.add(cache1);
- list.add(cache2);
- final DistanceComparator distanceComparator = new DistanceComparator(CgeoApplication.getInstance().currentGeo().getCoords(), list);
- return distanceComparator.compare(cache1, cache2);
+ return sortSameDate(cache1, cache2);
}
return dateDifference;
}
@@ -35,4 +30,13 @@ public class DateComparator extends AbstractCacheComparator {
}
return 0;
}
+
+ @SuppressWarnings("static-method")
+ protected int sortSameDate(final Geocache cache1, final Geocache cache2) {
+ final ArrayList<Geocache> list = new ArrayList<>();
+ list.add(cache1);
+ list.add(cache2);
+ final DistanceComparator distanceComparator = new DistanceComparator(Sensors.getInstance().currentGeo().getCoords(), list);
+ return distanceComparator.compare(cache1, cache2);
+ }
}
diff --git a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
index 459f38d..10463c8 100644
--- a/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DifficultyComparator.java
@@ -6,10 +6,10 @@ import cgeo.geocaching.Geocache;
* sorts caches by difficulty
*
*/
-public class DifficultyComparator extends AbstractCacheComparator {
+class DifficultyComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache) {
+ protected boolean canCompare(final Geocache cache) {
return cache.getDifficulty() != 0.0;
}
diff --git a/main/src/cgeo/geocaching/sorting/DistanceComparator.java b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
index b3b751b..f400583 100644
--- a/main/src/cgeo/geocaching/sorting/DistanceComparator.java
+++ b/main/src/cgeo/geocaching/sorting/DistanceComparator.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import java.util.ArrayList;
import java.util.List;
@@ -28,7 +28,8 @@ public class DistanceComparator extends AbstractCacheComparator {
public DistanceComparator(final Geopoint coords, final List<Geocache> list) {
this.coords = coords;
- this.list = list;
+ // create new list so we can iterate over the list in parallel with the cache list adapter
+ this.list = new ArrayList<>(list);
}
/**
diff --git a/main/src/cgeo/geocaching/sorting/EventDateComparator.java b/main/src/cgeo/geocaching/sorting/EventDateComparator.java
index 197946a..efeeb5d 100644
--- a/main/src/cgeo/geocaching/sorting/EventDateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/EventDateComparator.java
@@ -1,5 +1,7 @@
package cgeo.geocaching.sorting;
+import cgeo.geocaching.Geocache;
+
/**
* Compares caches by date. Used only for event caches.
*/
@@ -7,4 +9,16 @@ public class EventDateComparator extends DateComparator {
final static public EventDateComparator singleton = new EventDateComparator();
+ @Override
+ protected int sortSameDate(final Geocache left, final Geocache right) {
+ return compare(left.guessEventTimeMinutes(), right.guessEventTimeMinutes());
+ }
+
+ /**
+ * copy of {@link Integer#compare(int, int)}, as that is not available on lower API levels
+ *
+ */
+ private static int compare(final int left, final int right) {
+ return left < right ? -1 : (left == right ? 0 : 1);
+ }
}
diff --git a/main/src/cgeo/geocaching/sorting/FindsComparator.java b/main/src/cgeo/geocaching/sorting/FindsComparator.java
index 7f2ef50..a4c0686 100644
--- a/main/src/cgeo/geocaching/sorting/FindsComparator.java
+++ b/main/src/cgeo/geocaching/sorting/FindsComparator.java
@@ -2,17 +2,17 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
-public class FindsComparator extends AbstractCacheComparator {
+class FindsComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache) {
+ protected boolean canCompare(final Geocache cache) {
return cache.getLogCounts() != null;
}
@Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
- int finds1 = cache1.getFindsCount();
- int finds2 = cache2.getFindsCount();
+ protected int compareCaches(final Geocache cache1, final Geocache cache2) {
+ final int finds1 = cache1.getFindsCount();
+ final int finds2 = cache2.getFindsCount();
return finds2 - finds1;
}
diff --git a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
index e700f13..30a2fc8 100644
--- a/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/GeocodeComparator.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.Geocache;
* sorts caches by geo code, therefore effectively sorting by cache age
*
*/
-public class GeocodeComparator extends AbstractCacheComparator {
+class GeocodeComparator extends AbstractCacheComparator {
@Override
protected boolean canCompare(final Geocache cache) {
diff --git a/main/src/cgeo/geocaching/sorting/InventoryComparator.java b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
index 9d19b64..13eadcc 100644
--- a/main/src/cgeo/geocaching/sorting/InventoryComparator.java
+++ b/main/src/cgeo/geocaching/sorting/InventoryComparator.java
@@ -5,7 +5,7 @@ import cgeo.geocaching.Geocache;
/**
* sorts caches by number of items in inventory
*/
-public class InventoryComparator extends AbstractCacheComparator {
+class InventoryComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
diff --git a/main/src/cgeo/geocaching/sorting/InverseComparator.java b/main/src/cgeo/geocaching/sorting/InverseComparator.java
index 1dc76e2..0da351f 100644
--- a/main/src/cgeo/geocaching/sorting/InverseComparator.java
+++ b/main/src/cgeo/geocaching/sorting/InverseComparator.java
@@ -10,12 +10,12 @@ public class InverseComparator implements CacheComparator {
private final CacheComparator originalComparator;
- public InverseComparator(CacheComparator comparator) {
+ public InverseComparator(final CacheComparator comparator) {
this.originalComparator = comparator;
}
@Override
- public int compare(Geocache lhs, Geocache rhs) {
+ public int compare(final Geocache lhs, final Geocache rhs) {
return originalComparator.compare(rhs, lhs);
}
diff --git a/main/src/cgeo/geocaching/sorting/NameComparator.java b/main/src/cgeo/geocaching/sorting/NameComparator.java
index 2941b1c..ab7bbcb 100644
--- a/main/src/cgeo/geocaching/sorting/NameComparator.java
+++ b/main/src/cgeo/geocaching/sorting/NameComparator.java
@@ -1,22 +1,27 @@
package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.utils.TextUtils;
import org.apache.commons.lang3.StringUtils;
+import java.text.Collator;
+
/**
* sorts caches by name
*
*/
-public class NameComparator extends AbstractCacheComparator {
+class NameComparator extends AbstractCacheComparator {
+
+ private final Collator collator = TextUtils.getCollator();
@Override
- protected boolean canCompare(Geocache cache) {
+ protected boolean canCompare(final Geocache cache) {
return StringUtils.isNotBlank(cache.getName());
}
@Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
- return cache1.getNameForSorting().compareToIgnoreCase(cache2.getNameForSorting());
+ protected int compareCaches(final Geocache cache1, final Geocache cache2) {
+ return collator.compare(cache1.getNameForSorting(), cache2.getNameForSorting());
}
}
diff --git a/main/src/cgeo/geocaching/sorting/PopularityComparator.java b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
index 2dbee68..58b3b4c 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityComparator.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.Geocache;
* sorts caches by popularity (favorite count)
*
*/
-public class PopularityComparator extends AbstractCacheComparator {
+class PopularityComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
diff --git a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
index 57a69ee..4c2d914 100644
--- a/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
+++ b/main/src/cgeo/geocaching/sorting/PopularityRatioComparator.java
@@ -8,12 +8,12 @@ import cgeo.geocaching.Geocache;
/**
* sorts caches by popularity ratio (favorites per find in %).
*/
-public class PopularityRatioComparator extends AbstractCacheComparator {
+class PopularityRatioComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
- int finds1 = cache1.getFindsCount();
- int finds2 = cache2.getFindsCount();
+ final int finds1 = cache1.getFindsCount();
+ final int finds2 = cache2.getFindsCount();
float ratio1 = 0.0f;
if (finds1 != 0) {
@@ -26,7 +26,8 @@ public class PopularityRatioComparator extends AbstractCacheComparator {
if ((ratio2 - ratio1) > 0.0f) {
return 1;
- } else if ((ratio2 - ratio1) < 0.0f) {
+ }
+ if ((ratio2 - ratio1) < 0.0f) {
return -1;
}
diff --git a/main/src/cgeo/geocaching/sorting/RatingComparator.java b/main/src/cgeo/geocaching/sorting/RatingComparator.java
index 6f2c615..62854fe 100644
--- a/main/src/cgeo/geocaching/sorting/RatingComparator.java
+++ b/main/src/cgeo/geocaching/sorting/RatingComparator.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.Geocache;
* sorts caches by gcvote.com rating
*
*/
-public class RatingComparator extends AbstractCacheComparator {
+class RatingComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
diff --git a/main/src/cgeo/geocaching/sorting/SizeComparator.java b/main/src/cgeo/geocaching/sorting/SizeComparator.java
index c8de586..8cb5178 100644
--- a/main/src/cgeo/geocaching/sorting/SizeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/SizeComparator.java
@@ -6,15 +6,10 @@ import cgeo.geocaching.Geocache;
* sorts caches by size
*
*/
-public class SizeComparator extends AbstractCacheComparator {
+class SizeComparator extends AbstractCacheComparator {
@Override
- protected boolean canCompare(Geocache cache) {
- return cache.getSize() != null;
- }
-
- @Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
+ protected int compareCaches(final Geocache cache1, final Geocache cache2) {
return cache2.getSize().comparable - cache1.getSize().comparable;
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/sorting/SortActionProvider.java b/main/src/cgeo/geocaching/sorting/SortActionProvider.java
index 6251984..e6db330 100644
--- a/main/src/cgeo/geocaching/sorting/SortActionProvider.java
+++ b/main/src/cgeo/geocaching/sorting/SortActionProvider.java
@@ -136,9 +136,7 @@ public class SortActionProvider extends ActionProvider implements OnMenuItemClic
final CacheComparator comparator = cacheComparator.newInstance();
onClickListener.call(comparator);
}
- } catch (final InstantiationException e) {
- Log.e("selectComparator", e);
- } catch (final IllegalAccessException e) {
+ } catch (final InstantiationException | IllegalAccessException e) {
Log.e("selectComparator", e);
}
}
diff --git a/main/src/cgeo/geocaching/sorting/StateComparator.java b/main/src/cgeo/geocaching/sorting/StateComparator.java
index 9488bd9..e4403f8 100644
--- a/main/src/cgeo/geocaching/sorting/StateComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StateComparator.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.Geocache;
* sort caches by state (normal, disabled, archived)
*
*/
-public class StateComparator extends AbstractCacheComparator {
+class StateComparator extends AbstractCacheComparator {
@Override
protected int compareCaches(final Geocache cache1, final Geocache cache2) {
diff --git a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
index b718d3b..fbe3226 100644
--- a/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
+++ b/main/src/cgeo/geocaching/sorting/StorageTimeComparator.java
@@ -2,10 +2,10 @@ package cgeo.geocaching.sorting;
import cgeo.geocaching.Geocache;
-public class StorageTimeComparator extends AbstractCacheComparator {
+class StorageTimeComparator extends AbstractCacheComparator {
@Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
+ protected int compareCaches(final Geocache cache1, final 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 9bbb5f7..e882025 100644
--- a/main/src/cgeo/geocaching/sorting/TerrainComparator.java
+++ b/main/src/cgeo/geocaching/sorting/TerrainComparator.java
@@ -6,7 +6,7 @@ import cgeo.geocaching.Geocache;
* sorts caches by terrain rating
*
*/
-public class TerrainComparator extends AbstractCacheComparator {
+class TerrainComparator extends AbstractCacheComparator {
@Override
protected boolean canCompare(final Geocache cache) {
diff --git a/main/src/cgeo/geocaching/sorting/VoteComparator.java b/main/src/cgeo/geocaching/sorting/VoteComparator.java
index cd4ad7e..5cf39d7 100644
--- a/main/src/cgeo/geocaching/sorting/VoteComparator.java
+++ b/main/src/cgeo/geocaching/sorting/VoteComparator.java
@@ -5,10 +5,10 @@ import cgeo.geocaching.Geocache;
/**
* sorts caches by the users own voting (if available at all)
*/
-public class VoteComparator extends AbstractCacheComparator {
+class VoteComparator extends AbstractCacheComparator {
@Override
- protected int compareCaches(Geocache cache1, Geocache cache2) {
+ protected int compareCaches(final Geocache cache1, final 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 fbd2d7e..b22e061 100644
--- a/main/src/cgeo/geocaching/speech/SpeechService.java
+++ b/main/src/cgeo/geocaching/speech/SpeechService.java
@@ -1,10 +1,11 @@
package cgeo.geocaching.speech;
+import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.ActivityMixin;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.sensors.GeoDirHandler;
-import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -31,7 +32,6 @@ public class SpeechService extends Service implements OnInitListener {
private static final int SPEECH_MINPAUSE_SECONDS = 5;
private static final int SPEECH_MAXPAUSE_SECONDS = 30;
- private static final String EXTRA_TARGET_COORDS = "target";
private static Activity startingActivity;
private static boolean isRunning = false;
/**
@@ -47,7 +47,7 @@ public class SpeechService extends Service implements OnInitListener {
final GeoDirHandler geoDirHandler = new GeoDirHandler() {
@Override
- public void updateGeoDir(final IGeoData newGeo, final float newDirection) {
+ public void updateGeoDir(final GeoData newGeo, final float newDirection) {
position = newGeo.getCoords();
direction = newDirection;
// avoid any calculation, if the delay since the last output is not long enough
@@ -152,11 +152,12 @@ public class SpeechService extends Service implements OnInitListener {
@Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if (intent != null) {
- target = intent.getParcelableExtra(EXTRA_TARGET_COORDS);
+ target = intent.getParcelableExtra(Intents.EXTRA_COORDS);
}
return START_NOT_STICKY; // service can be stopped by system, if under memory pressure
}
+ @SuppressWarnings("deprecation")
private void speak(final String text) {
if (!initialized) {
return;
@@ -168,7 +169,7 @@ public class SpeechService extends Service implements OnInitListener {
isRunning = true;
startingActivity = activity;
final Intent talkingService = new Intent(activity, SpeechService.class);
- talkingService.putExtra(EXTRA_TARGET_COORDS, dstCoords);
+ talkingService.putExtra(Intents.EXTRA_COORDS, dstCoords);
activity.startService(talkingService);
}
diff --git a/main/src/cgeo/geocaching/speech/TextFactory.java b/main/src/cgeo/geocaching/speech/TextFactory.java
index eb780c6..3f1f142 100644
--- a/main/src/cgeo/geocaching/speech/TextFactory.java
+++ b/main/src/cgeo/geocaching/speech/TextFactory.java
@@ -2,8 +2,8 @@ package cgeo.geocaching.speech;
import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.IConversion;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.IConversion;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AngleUtils;
@@ -21,17 +21,17 @@ import java.util.Locale;
* on unit expressions.
*/
public class TextFactory {
- public static String getText(Geopoint position, Geopoint target, float direction) {
+ public static String getText(final Geopoint position, final Geopoint target, final float direction) {
if (position == null || target == null) {
return null;
}
return getDirection(position, target, direction) + ". " + getDistance(position, target);
}
- private static String getDistance(Geopoint position, Geopoint target) {
+ private static String getDistance(final Geopoint position, final Geopoint target) {
final float kilometers = position.distanceTo(target);
- if (Settings.isUseImperialUnits()) {
+ if (Settings.useImperialUnits()) {
return getDistance(kilometers / IConversion.MILES_TO_KILOMETER,
(int) (kilometers * 1000.0 * IConversion.METERS_TO_FEET),
3.0f, 0.2f, 300,
@@ -44,9 +44,9 @@ public class TextFactory {
R.plurals.tts_meters, R.string.tts_one_meter);
}
- private static String getDistance(float farDistance, int nearDistance,
- float farFarAway, float farNearAway, int nearFarAway,
- int farId, int farOneId, int nearId, int nearOneId) {
+ private static String getDistance(final float farDistance, final int nearDistance,
+ final float farFarAway, final float farNearAway, final int nearFarAway,
+ final int farId, final int farOneId, final int nearId, final int nearOneId) {
if (farDistance >= farFarAway) {
// example: "5 kilometers" - always without decimal digits
final int quantity = Math.round(farDistance);
@@ -84,15 +84,15 @@ public class TextFactory {
return getQuantityString(nearId, quantity, String.valueOf(quantity));
}
- private static String getString(int resourceId, Object... formatArgs) {
+ private static String getString(final int resourceId, final Object... formatArgs) {
return CgeoApplication.getInstance().getString(resourceId, formatArgs);
}
- private static String getQuantityString(int resourceId, int quantity, Object... formatArgs) {
+ private static String getQuantityString(final int resourceId, final int quantity, final Object... formatArgs) {
return CgeoApplication.getInstance().getResources().getQuantityString(resourceId, quantity, formatArgs);
}
- private static String getDirection(Geopoint position, Geopoint target, float direction) {
+ private static String getDirection(final Geopoint position, final Geopoint target, final float direction) {
final int bearing = (int) position.bearingTo(target);
final int degrees = (int) AngleUtils.normalize(bearing - direction);
diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java
index c89c0b6..0e5ebfa 100644
--- a/main/src/cgeo/geocaching/twitter/Twitter.java
+++ b/main/src/cgeo/geocaching/twitter/Twitter.java
@@ -6,10 +6,11 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.Trackable;
import cgeo.geocaching.enumerations.LoadFlags;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter.Format;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter.Format;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.network.OAuth;
+import cgeo.geocaching.network.OAuthTokens;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
@@ -17,6 +18,7 @@ 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;
@@ -25,7 +27,7 @@ public final class Twitter {
private static final String HASH_PREFIX_WITH_BLANK = " #";
private static final int MAX_TWEET_SIZE = 140;
- public static void postTweetCache(String geocode, final @Nullable LogEntry logEntry) {
+ public static void postTweetCache(final String geocode, final @Nullable LogEntry logEntry) {
final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
if (cache == null) {
return;
@@ -33,7 +35,7 @@ public final class Twitter {
postTweet(CgeoApplication.getInstance(), getStatusMessage(cache, logEntry), null);
}
- public static void postTweetTrackable(String geocode, final @Nullable LogEntry logEntry) {
+ public static void postTweetTrackable(final String geocode, final @Nullable LogEntry logEntry) {
final Trackable trackable = DataStore.loadTrackable(geocode);
if (trackable == null) {
return;
@@ -48,7 +50,7 @@ public final class Twitter {
try {
final String status = shortenToMaxSize(statusIn);
- Parameters parameters = new Parameters("status", status);
+ final Parameters parameters = new Parameters("status", status);
if (coords != null) {
parameters.put(
"lat", coords.format(Format.LAT_DECDEGREE_RAW),
@@ -56,7 +58,7 @@ public final class Twitter {
"display_coordinates", "true");
}
- OAuth.signOAuth("api.twitter.com", "/1.1/statuses/update.json", "POST", true, parameters, Settings.getTokenPublic(), Settings.getTokenSecret(), Settings.getKeyConsumerPublic(), Settings.getKeyConsumerSecret());
+ OAuth.signOAuth("api.twitter.com", "/1.1/statuses/update.json", "POST", true, parameters, new OAuthTokens(Settings.getTokenPublic(), Settings.getTokenSecret()), Settings.getTwitterKeyConsumerPublic(), Settings.getTwitterKeyConsumerSecret());
final HttpResponse httpResponse = Network.postRequest("https://api.twitter.com/1.1/statuses/update.json", parameters);
if (httpResponse != null) {
if (httpResponse.getStatusLine().getStatusCode() == 200) {
@@ -67,13 +69,13 @@ public final class Twitter {
} else {
Log.e("Tweet could not be posted. Reason: httpResponse Object is null");
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("Twitter.postTweet", e);
}
}
private static String shortenToMaxSize(final String status) {
- String result = StringUtils.trim(status);
+ final String result = StringUtils.trim(status);
if (StringUtils.length(result) > MAX_TWEET_SIZE) {
return StringUtils.substring(result, 0, MAX_TWEET_SIZE - 1) + '…';
}
@@ -98,7 +100,7 @@ public final class Twitter {
}
private static String appendHashTags(final String status) {
- StringBuilder builder = new StringBuilder(status);
+ final StringBuilder builder = new StringBuilder(status);
appendHashTag(builder, "cgeo");
appendHashTag(builder, "geocaching");
return builder.toString();
diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
index 97332d3..6df417b 100644
--- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
+++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.twitter;
import cgeo.geocaching.R;
-import cgeo.geocaching.network.OAuthAuthorizationActivity;
+import cgeo.geocaching.activity.OAuthAuthorizationActivity;
import cgeo.geocaching.settings.Settings;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -15,8 +15,8 @@ public class TwitterAuthorizationActivity extends OAuthAuthorizationActivity {
"/oauth/authorize",
"/oauth/access_token",
true,
- Settings.getKeyConsumerPublic(),
- Settings.getKeyConsumerSecret(),
+ Settings.getTwitterKeyConsumerPublic(),
+ Settings.getTwitterKeyConsumerSecret(),
"callback://www.cgeo.org/twitter/");
@Override
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java
index 06fa1fa..40d077e 100644
--- a/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingListViewPageViewCreator.java
@@ -30,10 +30,10 @@ public abstract class AbstractCachingListViewPageViewCreator extends AbstractCac
if (view == null) {
return null;
}
- int position = view.getFirstVisiblePosition();
- View child = view.getChildAt(0);
- int positionFromTop = (child == null) ? 0 : child.getTop();
- Bundle state = new Bundle();
+ final int position = view.getFirstVisiblePosition();
+ final View child = view.getChildAt(0);
+ final int positionFromTop = (child == null) ? 0 : child.getTop();
+ final Bundle state = new Bundle();
state.putInt(STATE_POSITION, position);
state.putInt(STATE_POSITION_FROM_TOP, positionFromTop);
return state;
@@ -44,12 +44,12 @@ public abstract class AbstractCachingListViewPageViewCreator extends AbstractCac
*
*/
@Override
- public void setViewState(@NonNull Bundle state) {
+ public void setViewState(@NonNull final Bundle state) {
if (view == null) {
return;
}
- int logViewPosition = state.getInt(STATE_POSITION);
- int logViewPositionFromTop = state.getInt(STATE_POSITION_FROM_TOP);
+ final int logViewPosition = state.getInt(STATE_POSITION);
+ final int logViewPositionFromTop = state.getInt(STATE_POSITION_FROM_TOP);
view.setSelectionFromTop(logViewPosition, logViewPositionFromTop);
}
diff --git a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
index 306c686..60e8b2d 100644
--- a/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/AbstractCachingPageViewCreator.java
@@ -14,7 +14,6 @@ import android.view.ViewGroup;
/**
* View creator which destroys the created view on every {@link #notifyDataSetChanged()}.
*
- * @param <ViewClass>
*/
public abstract class AbstractCachingPageViewCreator<ViewClass extends View> implements PageViewCreator {
diff --git a/main/src/cgeo/geocaching/ui/AbstractImageAdapter.java b/main/src/cgeo/geocaching/ui/AbstractImageAdapter.java
new file mode 100644
index 0000000..22ec603
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/AbstractImageAdapter.java
@@ -0,0 +1,66 @@
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.R;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ImageView;
+
+import java.util.List;
+
+public abstract class AbstractImageAdapter extends BaseAdapter {
+ private final Context context;
+ // references to our images
+ private final List<Integer> imageIds;
+ private final int imageWidth;
+
+ public AbstractImageAdapter(final Context context, final GridView gridView, final List<Integer> imageIds) {
+ this.context = context;
+ this.imageIds = imageIds;
+
+ final Drawable drawable = context.getResources().getDrawable(imageIds.get(0));
+ imageWidth = drawable.getIntrinsicWidth();
+
+ // fix the column width, now that we know the images
+ gridView.setColumnWidth(getImageWidth());
+ }
+
+ @Override
+ public int getCount() {
+ return imageIds.size();
+ }
+
+ @Override
+ public Object getItem(final int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(final int position) {
+ return 0;
+ }
+
+ // create a new ImageView for each item referenced by the Adapter
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+ final ImageView imageView;
+ if (convertView == null) { // if it's not recycled, initialize some attributes
+ imageView = (ImageView) LayoutInflater.from(context).inflate(R.layout.grid_image, null);
+ } else {
+ imageView = (ImageView) convertView;
+ }
+
+ imageView.setImageResource(imageIds.get(position));
+ return imageView;
+ }
+
+ int getImageWidth() {
+ return imageWidth;
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/ui/AbstractMenuActionProvider.java b/main/src/cgeo/geocaching/ui/AbstractMenuActionProvider.java
new file mode 100644
index 0000000..fbea675
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/AbstractMenuActionProvider.java
@@ -0,0 +1,24 @@
+package cgeo.geocaching.ui;
+
+import android.content.Context;
+import android.support.v4.view.ActionProvider;
+import android.view.View;
+
+public abstract class AbstractMenuActionProvider extends ActionProvider {
+
+ public AbstractMenuActionProvider(final Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean hasSubMenu() {
+ return true;
+ }
+
+ @Override
+ public View onCreateActionView() {
+ // must return null, otherwise the menu will not work
+ return null;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java
index f26cb53..1efa15e 100644
--- a/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java
+++ b/main/src/cgeo/geocaching/ui/AbstractUserClickListener.java
@@ -24,7 +24,7 @@ abstract class AbstractUserClickListener implements View.OnClickListener {
}
@Override
- public void onClick(View view) {
+ public void onClick(final View view) {
if (view == null) {
return;
}
@@ -45,8 +45,8 @@ abstract class AbstractUserClickListener implements View.OnClickListener {
final AbstractActivity activity = (AbstractActivity) view.getContext();
final Resources res = activity.getResources();
- ArrayList<String> labels = new ArrayList<>(userActions.size());
- for (UserAction action : userActions) {
+ final ArrayList<String> labels = new ArrayList<>(userActions.size());
+ for (final UserAction action : userActions) {
labels.add(res.getString(action.displayResourceId));
}
final CharSequence[] items = labels.toArray(new String[labels.size()]);
@@ -55,7 +55,7 @@ abstract class AbstractUserClickListener implements View.OnClickListener {
builder.setTitle(res.getString(R.string.user_menu_title) + " " + userName);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int item) {
+ public void onClick(final DialogInterface dialog, final int item) {
userActions.get(item).run(new Context(userName, activity));
}
});
diff --git a/main/src/cgeo/geocaching/ui/AbstractViewHolder.java b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java
index b1cb719..0233bf0 100644
--- a/main/src/cgeo/geocaching/ui/AbstractViewHolder.java
+++ b/main/src/cgeo/geocaching/ui/AbstractViewHolder.java
@@ -11,7 +11,7 @@ import android.view.View;
*/
public abstract class AbstractViewHolder {
- protected AbstractViewHolder(View view) {
+ protected AbstractViewHolder(final View view) {
ButterKnife.inject(this, view);
view.setTag(this);
}
diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
index 81b6c23..901bffc 100644
--- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java
@@ -3,12 +3,13 @@ package cgeo.geocaching.ui;
import butterknife.InjectView;
import cgeo.geocaching.CacheListActivity;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.sensors.Sensors;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.app.Activity;
import android.location.Address;
@@ -23,7 +24,7 @@ import java.util.ArrayList;
public class AddressListAdapter extends ArrayAdapter<Address> {
final private LayoutInflater inflater;
- final private Geopoint location;
+ @NonNull final private Geopoint location;
protected static final class ViewHolder extends AbstractViewHolder {
@InjectView(R.id.label) protected TextView label;
@@ -37,7 +38,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> {
public AddressListAdapter(final Activity context) {
super(context, 0);
inflater = context.getLayoutInflater();
- location = CgeoApplication.getInstance().currentGeo().getCoords();
+ location = Sensors.getInstance().currentGeo().getCoords();
}
@Override
@@ -72,7 +73,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> {
}
private CharSequence getDistanceText(final Address address) {
- if (location != null && address.hasLatitude() && address.hasLongitude()) {
+ if (address.hasLatitude() && address.hasLongitude()) {
return Units.getDistanceFromKilometers(location.distanceTo(new Geopoint(address.getLatitude(), address.getLongitude())));
}
diff --git a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
index d4c2e10..57c9db0 100644
--- a/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
+++ b/main/src/cgeo/geocaching/ui/AnchorAwareLinkMovementMethod.java
@@ -26,10 +26,10 @@ public class AnchorAwareLinkMovementMethod extends LinkMovementMethod {
}
@Override
- public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
+ public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) {
try {
return super.onTouchEvent(widget, buffer, event);
- } catch (Exception e) {
+ } catch (final Exception ignored) {
// local links to anchors don't work
}
return false;
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index 40cd726..e2af419 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -2,31 +2,29 @@ package cgeo.geocaching.ui;
import butterknife.ButterKnife;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
+import cgeo.geocaching.ICoordinates;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
import cgeo.geocaching.connector.ConnectorFactory;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Units;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.utils.Formatter;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Resources;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
// TODO The suppression of this lint finding is bad. But to fix it, someone needs to rework the layout of the cache
@@ -46,18 +44,20 @@ public final class CacheDetailsCreator {
}
/**
- * @param nameId
- * @param value
- * @return the view containing the displayed string (i.e. the right side one from the pair of "label": "value")
+ * Create a "name: value" line.
+ *
+ * @param nameId the resource of the name field
+ * @param value the initial value
+ * @return a pair made of the whole "name: value" line (to be able to hide it for example) and of the value (to update it)
*/
- public TextView add(final int nameId, final CharSequence value) {
+ public ImmutablePair<RelativeLayout, TextView> add(final int nameId, final CharSequence value) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null, false);
final TextView nameView = ButterKnife.findById(layout, R.id.name);
nameView.setText(res.getString(nameId));
lastValueView = ButterKnife.findById(layout, R.id.value);
lastValueView.setText(value);
parentView.addView(layout);
- return lastValueView;
+ return ImmutablePair.of(layout, lastValueView);
}
public TextView getValueView() {
@@ -72,41 +72,29 @@ public final class CacheDetailsCreator {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null, false);
final TextView nameView = ButterKnife.findById(layout, R.id.name);
lastValueView = ButterKnife.findById(layout, R.id.value);
- final LinearLayout layoutStars = ButterKnife.findById(layout, R.id.stars);
nameView.setText(activity.getResources().getString(nameId));
lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " " + String.format("%d", max));
- createStarImages(layoutStars, value, max);
+
+ final RatingBar layoutStars = ButterKnife.findById(layout, R.id.stars);
+ layoutStars.setRating(value);
layoutStars.setVisibility(View.VISIBLE);
parentView.addView(layout);
return layout;
}
- private void createStarImages(final ViewGroup starsContainer, final float value, final int max) {
- final LayoutInflater inflater = LayoutInflater.from(activity);
-
- for (int i = 0; i < max; i++) {
- final ImageView star = (ImageView) inflater.inflate(R.layout.star_image, starsContainer, false);
- if (value - i >= 0.75) {
- star.setImageResource(R.drawable.star_on);
- } else if (value - i >= 0.25) {
- star.setImageResource(R.drawable.star_half);
- } else {
- star.setImageResource(R.drawable.star_off);
- }
- starsContainer.addView(star);
- }
- }
-
public void addCacheState(final Geocache cache) {
if (cache.isLogOffline() || cache.isArchived() || cache.isDisabled() || cache.isPremiumMembersOnly() || cache.isFound()) {
final List<String> states = new ArrayList<>(5);
+ String date = getVisitedDate(cache);
if (cache.isLogOffline()) {
- states.add(res.getString(R.string.cache_status_offline_log));
+ states.add(res.getString(R.string.cache_status_offline_log) + date);
+ // reset the found date, to avoid showing it twice
+ date = "";
}
if (cache.isFound()) {
- states.add(res.getString(R.string.cache_status_found));
+ states.add(res.getString(R.string.cache_status_found) + date);
}
if (cache.isArchived()) {
states.add(res.getString(R.string.cache_status_archived));
@@ -121,19 +109,31 @@ public final class CacheDetailsCreator {
}
}
+ private static String getVisitedDate(final Geocache cache) {
+ final long visited = cache.getVisitedDate();
+ return visited != 0 ? " (" + Formatter.formatShortDate(visited) + ")" : "";
+ }
+
+ private static Float distanceNonBlocking(final ICoordinates target) {
+ if (target.getCoords() == null) {
+ return null;
+ }
+ return Sensors.getInstance().currentGeo().getCoords().distanceTo(target);
+ }
+
public void addRating(final Geocache cache) {
if (cache.getRating() > 0) {
final RelativeLayout itemLayout = addStars(R.string.cache_rating, cache.getRating());
if (cache.getVotes() > 0) {
final TextView itemAddition = ButterKnife.findById(itemLayout, R.id.addition);
- itemAddition.setText("(" + cache.getVotes() + ")");
+ itemAddition.setText(" (" + cache.getVotes() + ')');
itemAddition.setVisibility(View.VISIBLE);
}
}
}
public void addSize(final Geocache cache) {
- if (null != cache.getSize() && cache.showSize()) {
+ if (cache.showSize()) {
add(R.string.cache_size, cache.getSize().getL10n());
}
}
@@ -151,7 +151,7 @@ public final class CacheDetailsCreator {
}
public void addDistance(final Geocache cache, final TextView cacheDistanceView) {
- Float distance = CgeoApplication.getInstance().distanceNonBlocking(cache);
+ Float distance = distanceNonBlocking(cache);
if (distance == null) {
if (cache.getDistance() != null) {
distance = cache.getDistance();
@@ -170,7 +170,7 @@ public final class CacheDetailsCreator {
}
public void addDistance(final Waypoint wpt, final TextView waypointDistanceView) {
- Float distance = CgeoApplication.getInstance().distanceNonBlocking(wpt);
+ final Float distance = distanceNonBlocking(wpt);
String text = "--";
if (distance != null) {
text = Units.getDistanceFromKilometers(distance);
@@ -191,20 +191,12 @@ public final class CacheDetailsCreator {
}
public TextView addHiddenDate(final @NonNull Geocache cache) {
- final Date hiddenDate = cache.getHiddenDate();
- if (hiddenDate == null) {
+ final String dateString = Formatter.formatHiddenDate(cache);
+ if (StringUtils.isEmpty(dateString)) {
return 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;
- }
- final TextView view = add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString);
- view.setId(R.id.date);
- return view;
- }
- return null;
+ final TextView view = add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString).right;
+ view.setId(R.id.date);
+ return view;
}
}
diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java
index eaede2a..d9daa1d 100644
--- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java
@@ -3,14 +3,14 @@ package cgeo.geocaching.ui;
import butterknife.InjectView;
import cgeo.geocaching.CacheDetailActivity;
-import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.enumerations.CacheListType;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.filter.IFilter;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.sensors.GeoData;
+import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.sorting.CacheComparator;
import cgeo.geocaching.sorting.DistanceComparator;
@@ -18,7 +18,7 @@ import cgeo.geocaching.sorting.EventDateComparator;
import cgeo.geocaching.sorting.InverseComparator;
import cgeo.geocaching.sorting.VisitComparator;
import cgeo.geocaching.utils.AngleUtils;
-import cgeo.geocaching.utils.DateUtils;
+import cgeo.geocaching.utils.CalendarUtils;
import cgeo.geocaching.utils.Formatter;
import cgeo.geocaching.utils.Log;
@@ -27,9 +27,13 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.eclipse.jdt.annotation.NonNull;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.Spannable;
@@ -108,9 +112,10 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
@InjectView(R.id.distance) protected DistanceView distance;
@InjectView(R.id.favorite) protected TextView favorite;
@InjectView(R.id.info) protected TextView info;
- @InjectView(R.id.inventory) protected ImageView inventory;
+ @InjectView(R.id.inventory) protected TextView inventory;
@InjectView(R.id.direction) protected CompassMiniView direction;
@InjectView(R.id.dirimg) protected ImageView dirImg;
+ public Geocache cache = null;
public ViewHolder(final View view) {
super(view);
@@ -119,10 +124,8 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
public CacheListAdapter(final Activity activity, final List<Geocache> list, final CacheListType cacheListType) {
super(activity, 0, list);
- final IGeoData currentGeo = CgeoApplication.getInstance().currentGeo();
- if (currentGeo != null) {
- coords = currentGeo.getCoords();
- }
+ final GeoData currentGeo = Sensors.getInstance().currentGeo();
+ coords = currentGeo.getCoords();
this.res = activity.getResources();
this.list = list;
this.cacheListType = cacheListType;
@@ -157,7 +160,6 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
/**
* change the sort order
*
- * @param comparator
*/
public void setComparator(final CacheComparator comparator) {
cacheComparator = comparator;
@@ -380,6 +382,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
} else {
holder = (ViewHolder) v.getTag();
}
+ holder.cache = cache;
final boolean lightSkin = Settings.isLightSkin();
@@ -411,7 +414,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
}
Spannable spannable = null;
- if (cache.isDisabled() || cache.isArchived() || DateUtils.isPastEvent(cache)) { // strike
+ if (cache.isDisabled() || cache.isArchived() || CalendarUtils.isPastEvent(cache)) { // strike
spannable = Spannable.Factory.getInstance().newSpannable(cache.getName());
spannable.setSpan(new StrikethroughSpan(), 0, spannable.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@@ -430,7 +433,9 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
}
holder.text.setCompoundDrawablesWithIntrinsicBounds(getCacheIcon(cache), null, null, null);
- if (cache.getInventoryItems() > 0) {
+ final int inventorySize = cache.getInventoryItems();
+ if (inventorySize > 0) {
+ holder.inventory.setText(Integer.toString(inventorySize));
holder.inventory.setVisibility(View.VISIBLE);
} else {
holder.inventory.setVisibility(View.GONE);
@@ -459,9 +464,17 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> {
holder.direction.updateAzimuth(azimuth);
holder.direction.updateHeading(cache.getDirection());
} else if (StringUtils.isNotBlank(cache.getDirectionImg())) {
- holder.dirImg.setImageDrawable(DirectionImage.getDrawable(cache.getDirectionImg()));
- holder.dirImg.setVisibility(View.VISIBLE);
+ holder.dirImg.setVisibility(View.INVISIBLE);
holder.direction.setVisibility(View.GONE);
+ DirectionImage.fetchDrawable(cache.getDirectionImg()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<BitmapDrawable>() {
+ @Override
+ public void call(final BitmapDrawable bitmapDrawable) {
+ if (cache == holder.cache) {
+ holder.dirImg.setImageDrawable(bitmapDrawable);
+ holder.dirImg.setVisibility(View.VISIBLE);
+ }
+ }
+ });
} else {
holder.dirImg.setVisibility(View.GONE);
holder.direction.setVisibility(View.GONE);
diff --git a/main/src/cgeo/geocaching/ui/CompassMiniView.java b/main/src/cgeo/geocaching/ui/CompassMiniView.java
index 50823fd..d50d806 100644
--- a/main/src/cgeo/geocaching/ui/CompassMiniView.java
+++ b/main/src/cgeo/geocaching/ui/CompassMiniView.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.ui;
import cgeo.geocaching.R;
-import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.AngleUtils;
@@ -50,18 +50,19 @@ final public class CompassMiniView extends View {
private static final float MINIMUM_ROTATION_DEGREES_FOR_REPAINT = 5;
private float azimuthRelative;
- public CompassMiniView(Context context) {
+ public CompassMiniView(final Context context) {
super(context);
}
- public CompassMiniView(Context context, AttributeSet attrs) {
+ public CompassMiniView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onAttachedToWindow() {
if (instances++ == 0) {
- compassArrow = BitmapFactory.decodeResource(getResources(), Settings.isLightSkin() ? R.drawable.compass_arrow_mini_black : R.drawable.compass_arrow_mini_white);
+ final int drawable = isInEditMode() || !Settings.isLightSkin() ? R.drawable.compass_arrow_mini_white : R.drawable.compass_arrow_mini_black;
+ compassArrow = BitmapFactory.decodeResource(getResources(), drawable);
compassArrowWidth = compassArrow.getWidth();
compassArrowHeight = compassArrow.getWidth();
}
@@ -79,12 +80,12 @@ final public class CompassMiniView extends View {
targetCoords = point;
}
- public void updateAzimuth(float azimuth) {
+ public void updateAzimuth(final float azimuth) {
this.azimuth = azimuth;
updateDirection();
}
- public void updateHeading(float heading) {
+ public void updateHeading(final float heading) {
this.heading = heading;
updateDirection();
}
@@ -106,7 +107,7 @@ final public class CompassMiniView extends View {
azimuthRelative = AngleUtils.normalize(azimuth - heading);
// avoid updates on very small changes, which are not visible to the user
- float change = Math.abs(azimuthRelative - lastDrawnAzimuth);
+ final float change = Math.abs(azimuthRelative - lastDrawnAzimuth);
if (change < MINIMUM_ROTATION_DEGREES_FOR_REPAINT) {
return;
}
@@ -119,7 +120,7 @@ final public class CompassMiniView extends View {
}
@Override
- protected void onDraw(Canvas canvas) {
+ protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
lastDrawnAzimuth = azimuthRelative;
@@ -137,11 +138,11 @@ final public class CompassMiniView extends View {
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
- private int measureWidth(int measureSpec) {
+ private int measureWidth(final int measureSpec) {
final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);
@@ -158,7 +159,7 @@ final public class CompassMiniView extends View {
return result;
}
- private int measureHeight(int measureSpec) {
+ private int measureHeight(final int measureSpec) {
final int specMode = MeasureSpec.getMode(measureSpec);
final int specSize = MeasureSpec.getSize(measureSpec);
diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java
index 240afcf..a227770 100644
--- a/main/src/cgeo/geocaching/ui/CompassView.java
+++ b/main/src/cgeo/geocaching/ui/CompassView.java
@@ -81,8 +81,9 @@ public class CompassView extends View {
}
public void updateGraphics() {
- final float newAzimuthShown = smoothUpdate(northMeasured, azimuthShown);
- final float newCacheHeadingShown = smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
+ final float newAzimuthShown = initialDisplay ? northMeasured : smoothUpdate(northMeasured, azimuthShown);
+ final float newCacheHeadingShown = initialDisplay ? cacheHeadingMeasured : smoothUpdate(cacheHeadingMeasured, cacheHeadingShown);
+ initialDisplay = false;
if (Math.abs(AngleUtils.difference(azimuthShown, newAzimuthShown)) >= 2 ||
Math.abs(AngleUtils.difference(cacheHeadingShown, newCacheHeadingShown)) >= 2) {
azimuthShown = newAzimuthShown;
@@ -151,17 +152,6 @@ public class CompassView extends View {
* @param cacheHeading the cache direction (extra rotation of the needle)
*/
public void updateNorth(final float northHeading, final float cacheHeading) {
- if (initialDisplay) {
- // We will force the compass to move brutally if this is the first
- // update since it is visible.
- azimuthShown = northHeading;
- cacheHeadingShown = cacheHeading;
-
- // it may take some time to get an initial direction measurement for the device
- if (northHeading != 0.0) {
- initialDisplay = false;
- }
- }
northMeasured = northHeading;
cacheHeadingMeasured = cacheHeading;
}
diff --git a/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java
index 299256c..db299a2 100644
--- a/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java
+++ b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.ui;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.GeopointFormatter;
import android.view.View;
import android.view.View.OnClickListener;
@@ -13,7 +13,7 @@ import android.widget.TextView;
*/
public class CoordinatesFormatSwitcher implements OnClickListener {
- private static GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] {
+ private static final GeopointFormatter.Format[] availableFormats = new GeopointFormatter.Format[] {
GeopointFormatter.Format.LAT_LON_DECMINUTE,
GeopointFormatter.Format.LAT_LON_DECSECOND,
GeopointFormatter.Format.LAT_LON_DECDEGREE
@@ -28,10 +28,10 @@ public class CoordinatesFormatSwitcher implements OnClickListener {
}
@Override
- public void onClick(View view) {
+ public void onClick(final View view) {
assert view instanceof TextView;
position = (position + 1) % availableFormats.length;
- TextView textView = (TextView) view;
+ final TextView textView = (TextView) view;
// rotate coordinate formats on click
textView.setText(coordinates.format(availableFormats[position]));
}
diff --git a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
index e2e587e..30b0e5a 100644
--- a/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
+++ b/main/src/cgeo/geocaching/ui/DecryptTextClickListener.java
@@ -1,40 +1,37 @@
-package cgeo.geocaching.ui;
-
-import cgeo.geocaching.utils.CryptUtils;
-
-import org.eclipse.jdt.annotation.NonNull;
-
-import android.text.Spannable;
-import android.view.View;
-import android.widget.TextView;
-
-public class DecryptTextClickListener implements View.OnClickListener {
-
- @NonNull private final TextView targetView;
-
- public DecryptTextClickListener(@NonNull final TextView targetView) {
- this.targetView = targetView;
- }
-
- @Override
- public final void onClick(final View view) {
- try {
- // do not run the click listener if a link was clicked
- if (targetView.getSelectionStart() != -1 || targetView.getSelectionEnd() != -1) {
- return;
- }
-
- CharSequence text = targetView.getText();
- if (text instanceof Spannable) {
- Spannable span = (Spannable) text;
- targetView.setText(CryptUtils.rot13(span));
- }
- else {
- String string = (String) text;
- targetView.setText(CryptUtils.rot13(string));
- }
- } catch (RuntimeException e) {
- // nothing
- }
- }
-}
+package cgeo.geocaching.ui;
+
+import cgeo.geocaching.utils.CryptUtils;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+import android.text.Spannable;
+import android.view.View;
+import android.widget.TextView;
+
+public class DecryptTextClickListener implements View.OnClickListener {
+
+ @NonNull private final TextView targetView;
+
+ public DecryptTextClickListener(@NonNull final TextView targetView) {
+ this.targetView = targetView;
+ }
+
+ @Override
+ public final void onClick(final View view) {
+ try {
+ // do not run the click listener if a link was clicked
+ if (targetView.getSelectionStart() != -1 || targetView.getSelectionEnd() != -1) {
+ return;
+ }
+
+ final CharSequence text = targetView.getText();
+ if (text instanceof Spannable) {
+ targetView.setText(CryptUtils.rot13((Spannable) text));
+ } else {
+ targetView.setText(CryptUtils.rot13((String) text));
+ }
+ } catch (final RuntimeException ignored) {
+ // nothing
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/ui/DirectionImage.java b/main/src/cgeo/geocaching/ui/DirectionImage.java
index cd7695e..e08ff51 100644
--- a/main/src/cgeo/geocaching/ui/DirectionImage.java
+++ b/main/src/cgeo/geocaching/ui/DirectionImage.java
@@ -3,22 +3,22 @@ package cgeo.geocaching.ui;
import cgeo.geocaching.list.StoredList;
import cgeo.geocaching.network.HtmlImage;
-import org.apache.commons.lang3.StringUtils;
+import rx.Observable;
import android.graphics.drawable.BitmapDrawable;
public class DirectionImage {
- static private HtmlImage htmlImage = new HtmlImage(HtmlImage.SHARED, false, StoredList.STANDARD_LIST_ID, false);
+ static final private HtmlImage HTML_IMAGE = new HtmlImage(HtmlImage.SHARED, false, StoredList.STANDARD_LIST_ID, false);
/**
* Retrieve the direction image corresponding to the direction code.
*
* @param directionCode one of the eight cardinal points
- * @return a drawable with the arrow pointing into the right direction
+ * @return an observable containing zero or more drawables (the last one being the freshest image)
*/
- public static BitmapDrawable getDrawable(final String directionCode) {
- return StringUtils.isNotBlank(directionCode) ? htmlImage.getDrawable("http://www.geocaching.com/images/icons/compass/" + directionCode + ".gif") : null;
+ public static Observable<BitmapDrawable> fetchDrawable(final String directionCode) {
+ return HTML_IMAGE.fetchDrawable("https://www.geocaching.com/images/icons/compass/" + directionCode + ".gif");
}
}
diff --git a/main/src/cgeo/geocaching/ui/DistanceView.java b/main/src/cgeo/geocaching/ui/DistanceView.java
index a61fc4d..fb40ab4 100644
--- a/main/src/cgeo/geocaching/ui/DistanceView.java
+++ b/main/src/cgeo/geocaching/ui/DistanceView.java
@@ -1,7 +1,7 @@
package cgeo.geocaching.ui;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.Units;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Units;
import org.eclipse.jdt.annotation.NonNull;
@@ -12,15 +12,15 @@ import android.widget.TextView;
public class DistanceView extends TextView {
private Geopoint cacheCoords = null;
- public DistanceView(Context context) {
+ public DistanceView(final Context context) {
super(context);
}
- public DistanceView(Context context, AttributeSet attrs) {
+ public DistanceView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public DistanceView(Context context, AttributeSet attrs, int defStyle) {
+ public DistanceView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
@@ -35,7 +35,7 @@ public class DistanceView extends TextView {
setText(Units.getDistanceFromKilometers(coords.distanceTo(cacheCoords)));
}
- public void setDistance(Float distance) {
+ public void setDistance(final Float distance) {
setText("~" + Units.getDistanceFromKilometers(distance));
}
} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
index e07bbc3..6f7f587 100644
--- a/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
+++ b/main/src/cgeo/geocaching/ui/FileSelectionListAdapter.java
@@ -40,7 +40,7 @@ public class FileSelectionListAdapter extends ArrayAdapter<File> {
View v = rowView;
- ViewHolder holder;
+ final ViewHolder holder;
if (v == null) {
v = inflater.inflate(R.layout.mapfile_item, parent, false);
holder = new ViewHolder(v);
diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java
index 8bd4ac2..27a68c7 100644
--- a/main/src/cgeo/geocaching/ui/ImagesList.java
+++ b/main/src/cgeo/geocaching/ui/ImagesList.java
@@ -13,7 +13,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import rx.Subscription;
-import rx.android.observables.AndroidObservable;
+import rx.android.app.AppObservable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.subscriptions.CompositeSubscription;
@@ -102,11 +102,11 @@ public class ImagesList {
imagesView = ButterKnife.findById(parentView, R.id.spoiler_list);
- final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST_ID, false);
+ final HtmlImage imgGetter = new HtmlImage(geocode, true, offline ? StoredList.STANDARD_LIST_ID : StoredList.TEMPORARY_LIST.id, false);
for (final Image img : images) {
final LinearLayout rowView = (LinearLayout) inflater.inflate(R.layout.cache_image_item, imagesView, false);
- assert(rowView != null);
+ assert rowView != null;
if (StringUtils.isNotBlank(img.getTitle())) {
final TextView titleView = ButterKnife.findById(rowView, R.id.title);
@@ -121,8 +121,8 @@ public class ImagesList {
}
final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, rowView, false);
- assert(imageView != null);
- subscriptions.add(AndroidObservable.bindActivity(activity, imgGetter.fetchDrawable(img.getUrl())).subscribe(new Action1<BitmapDrawable>() {
+ assert imageView != null;
+ subscriptions.add(AppObservable.bindActivity(activity, imgGetter.fetchDrawable(img.getUrl())).subscribe(new Action1<BitmapDrawable>() {
@Override
public void call(final BitmapDrawable image) {
display(imageView, image, img, rowView);
@@ -203,7 +203,7 @@ public class ImagesList {
}
private static File saveToTemporaryJPGFile(final BitmapDrawable image) throws FileNotFoundException {
- final File file = LocalStorage.getStorageFile(null, "temp.jpg", false, true);
+ final File file = LocalStorage.getStorageFile(HtmlImage.SHARED, "temp.jpg", false, true);
BufferedOutputStream stream = null;
try {
stream = new BufferedOutputStream(new FileOutputStream(file));
diff --git a/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java b/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java
index a0c8b52..4727bf9 100644
--- a/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java
+++ b/main/src/cgeo/geocaching/ui/IndexOutOfBoundsAvoidingTextView.java
@@ -12,43 +12,43 @@ import android.widget.TextView;
*/
public class IndexOutOfBoundsAvoidingTextView extends TextView {
- public IndexOutOfBoundsAvoidingTextView(Context context, AttributeSet attrs, int defStyle) {
+ public IndexOutOfBoundsAvoidingTextView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
- public IndexOutOfBoundsAvoidingTextView(Context context, AttributeSet attrs) {
+ public IndexOutOfBoundsAvoidingTextView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
- public IndexOutOfBoundsAvoidingTextView(Context context) {
+ public IndexOutOfBoundsAvoidingTextView(final Context context) {
super(context);
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
try{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- } catch (IndexOutOfBoundsException e) {
+ } catch (final IndexOutOfBoundsException ignored) {
setText(getText().toString());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
- public void setGravity(int gravity){
+ public void setGravity(final int gravity){
try{
super.setGravity(gravity);
- } catch (IndexOutOfBoundsException e) {
+ } catch (final IndexOutOfBoundsException ignored) {
setText(getText().toString());
super.setGravity(gravity);
}
}
@Override
- public void setText(CharSequence text, BufferType type) {
+ public void setText(final CharSequence text, final BufferType type) {
try{
super.setText(text, type);
- } catch (IndexOutOfBoundsException e) {
+ } catch (final IndexOutOfBoundsException ignored) {
setText(text.toString());
}
}
diff --git a/main/src/cgeo/geocaching/ui/LoggingUI.java b/main/src/cgeo/geocaching/ui/LoggingUI.java
index 8454474..e9656e8 100644
--- a/main/src/cgeo/geocaching/ui/LoggingUI.java
+++ b/main/src/cgeo/geocaching/ui/LoggingUI.java
@@ -17,7 +17,12 @@ import android.widget.ArrayAdapter;
import java.util.ArrayList;
import java.util.List;
-public class LoggingUI extends AbstractUIFactory {
+public final class LoggingUI extends AbstractUIFactory {
+
+ private LoggingUI() {
+ // utility class
+ }
+
public static class LogTypeEntry {
private final LogType logType;
private final SpecialLogType specialLogType;
@@ -79,7 +84,7 @@ public class LoggingUI extends AbstractUIFactory {
final List<LogType> logTypes = cache.getPossibleLogTypes();
final ArrayList<LogTypeEntry> list = new ArrayList<>();
- for (LogType logType : logTypes) {
+ for (final LogType logType : logTypes) {
list.add(new LogTypeEntry(logType, null, logType == currentLogType));
}
if (cache.isLogOffline()) {
@@ -94,7 +99,7 @@ public class LoggingUI extends AbstractUIFactory {
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int item) {
+ public void onClick(final DialogInterface dialog, final int item) {
final LogTypeEntry logTypeEntry = adapter.getItem(item);
if (logTypeEntry.logType == null) {
switch (logTypeEntry.specialLogType) {
@@ -116,7 +121,7 @@ public class LoggingUI extends AbstractUIFactory {
}
- public static void onPrepareOptionsMenu(Menu menu, Geocache cache) {
+ public static void onPrepareOptionsMenu(final Menu menu, final Geocache cache) {
if (cache == null) {
return;
}
@@ -127,7 +132,7 @@ public class LoggingUI extends AbstractUIFactory {
itemOffline.setVisible(cache.supportsLogging() && Settings.getLogOffline());
}
- public static void addMenuItems(Activity activity, Menu menu, Geocache cache) {
+ public static void addMenuItems(final Activity activity, final Menu menu, final Geocache cache) {
activity.getMenuInflater().inflate(R.menu.logging_ui, menu);
onPrepareOptionsMenu(menu, cache);
}
diff --git a/main/src/cgeo/geocaching/ui/NavigationActionProvider.java b/main/src/cgeo/geocaching/ui/NavigationActionProvider.java
index 5840e27..ed4455d 100644
--- a/main/src/cgeo/geocaching/ui/NavigationActionProvider.java
+++ b/main/src/cgeo/geocaching/ui/NavigationActionProvider.java
@@ -9,6 +9,10 @@ import android.support.v4.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.View;
+/**
+ * Action provider showing the compass icon, and reacting to normal click (primary navigation) and long click (secondary
+ * navigation).
+ */
public class NavigationActionProvider extends ActionProvider {
private final Context context;
diff --git a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java
index acd43cb..9aa6bec 100644
--- a/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java
+++ b/main/src/cgeo/geocaching/ui/OwnerActionsClickListener.java
@@ -15,13 +15,13 @@ public class OwnerActionsClickListener extends AbstractUserClickListener {
private final Geocache cache;
- public OwnerActionsClickListener(Geocache cache) {
+ public OwnerActionsClickListener(final Geocache cache) {
super(ConnectorFactory.getConnector(cache).getUserActions());
this.cache = cache;
}
@Override
- protected String getUserName(View view) {
+ protected String getUserName(final View view) {
// Use real owner name vice the one owner chose to display
if (StringUtils.isNotBlank(cache.getOwnerUserId())) {
return cache.getOwnerUserId();
diff --git a/main/src/cgeo/geocaching/ui/UrlPopup.java b/main/src/cgeo/geocaching/ui/UrlPopup.java
index 5a8dba4..18d57d5 100644
--- a/main/src/cgeo/geocaching/ui/UrlPopup.java
+++ b/main/src/cgeo/geocaching/ui/UrlPopup.java
@@ -17,20 +17,20 @@ public class UrlPopup {
}
public void show(final String title, final String message, final String url, final String urlButtonTitle) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(message)
.setIcon(android.R.drawable.ic_dialog_info)
.setTitle(title)
.setPositiveButton(R.string.err_none, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int id) {
+ public void onClick(final DialogInterface dialog, final int id) {
dialog.cancel();
}
})
.setNegativeButton(urlButtonTitle, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int id) {
- Intent i = new Intent(Intent.ACTION_VIEW);
+ public void onClick(final DialogInterface dialog, final int id) {
+ final Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
context.startActivity(i);
}
diff --git a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java
index 19946bc..68c5493 100644
--- a/main/src/cgeo/geocaching/ui/UserActionsClickListener.java
+++ b/main/src/cgeo/geocaching/ui/UserActionsClickListener.java
@@ -12,16 +12,16 @@ import android.widget.TextView;
*/
public class UserActionsClickListener extends AbstractUserClickListener {
- public UserActionsClickListener(Geocache cache) {
+ public UserActionsClickListener(final Geocache cache) {
super(ConnectorFactory.getConnector(cache).getUserActions());
}
- public UserActionsClickListener(Trackable trackable) {
+ public UserActionsClickListener(final Trackable trackable) {
super(ConnectorFactory.getConnector(trackable).getUserActions());
}
@Override
- protected String getUserName(View view) {
+ protected String getUserName(final View view) {
return ((TextView) view).getText().toString();
}
}
diff --git a/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java b/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java
index d51e697..aa75db7 100644
--- a/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java
+++ b/main/src/cgeo/geocaching/ui/WeakReferenceHandler.java
@@ -11,7 +11,6 @@ import java.lang.ref.WeakReference;
*
* Create static private subclasses of this handler class in your activity.
*
- * @param <ActivityType>
*/
public abstract class WeakReferenceHandler<ActivityType extends Activity> extends Handler {
diff --git a/main/src/cgeo/geocaching/ui/WrappingGridView.java b/main/src/cgeo/geocaching/ui/WrappingGridView.java
new file mode 100644
index 0000000..2c85887
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/WrappingGridView.java
@@ -0,0 +1,38 @@
+package cgeo.geocaching.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.GridView;
+
+/**
+ * GridView that will adjust its height to really use wrap_content. The standard GridView only shows one line of items.
+ *
+ * @see <a href="https://gist.github.com/runemart/9781609">https://gist.github.com/runemart/9781609</a>
+ *
+ */
+public class WrappingGridView extends GridView {
+
+ public WrappingGridView(final Context context) {
+ super(context);
+ }
+
+ public WrappingGridView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public WrappingGridView(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+ int heightSpec = heightMeasureSpec;
+ if (getLayoutParams().height == android.view.ViewGroup.LayoutParams.WRAP_CONTENT) {
+ // The two leftmost bits in the height measure spec have
+ // a special meaning, hence we can't use them to describe height.
+ heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ }
+ super.onMeasure(widthMeasureSpec, heightSpec);
+ }
+
+} \ No newline at end of file
diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
index 9aee71a..578a15f 100644
--- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java
@@ -6,11 +6,13 @@ import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.Keyboard;
-import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.geopoint.GeopointFormatter;
-import cgeo.geocaching.sensors.IGeoData;
+import cgeo.geocaching.location.Geopoint;
+import cgeo.geocaching.location.Geopoint.ParseException;
+import cgeo.geocaching.location.GeopointFormatter;
+import cgeo.geocaching.sensors.GeoData;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.Settings.CoordInputFormatEnum;
+import cgeo.geocaching.utils.ClipboardUtils;
import cgeo.geocaching.utils.EditUtils;
import org.apache.commons.lang3.StringUtils;
@@ -21,6 +23,7 @@ import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.Editable;
import android.text.TextWatcher;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -53,16 +56,14 @@ public class CoordinatesInputDialog extends DialogFragment {
private static final String CACHECOORDS_ARG = "CACHECOORDS";
- public static CoordinatesInputDialog getInstance(final Geocache cache, final Geopoint gp, final IGeoData geo) {
+ public static CoordinatesInputDialog getInstance(final Geocache cache, final Geopoint gp, final GeoData geo) {
final Bundle args = new Bundle();
if (gp != null) {
args.putParcelable(GEOPOINT_ARG, gp);
- } else if (geo != null && geo.getCoords() != null) {
- args.putParcelable(GEOPOINT_ARG, geo.getCoords());
} else {
- args.putParcelable(GEOPOINT_ARG, Geopoint.ZERO);
+ args.putParcelable(GEOPOINT_ARG, geo != null ? geo.getCoords() : Geopoint.ZERO);
}
if (geo !=null) {
@@ -173,12 +174,27 @@ public class CoordinatesInputDialog extends DialogFragment {
buttonCache.setVisibility(View.GONE);
}
+ if (hasClipboardCoordinates()) {
+ final Button buttonClipboard = ButterKnife.findById(v, R.id.clipboard);
+ buttonClipboard.setOnClickListener(new ClipboardListener());
+ buttonClipboard.setVisibility(View.VISIBLE);
+ }
+
final Button buttonDone = ButterKnife.findById(v, R.id.done);
buttonDone.setOnClickListener(new InputDoneListener());
return v;
}
+ @SuppressWarnings("unused")
+ private static boolean hasClipboardCoordinates() {
+ try {
+ new Geopoint(StringUtils.defaultString(ClipboardUtils.getText()));
+ } catch (final ParseException ignored) {
+ return false;
+ }
+ return true;
+ }
private void updateGUI() {
@@ -215,8 +231,10 @@ public class CoordinatesInputDialog extends DialogFragment {
eLatDeg.setText(addZeros(gp.getLatDeg(), 2));
eLatMin.setText(addZeros(gp.getLatDegFrac(), 5));
+ eLatMin.setGravity(Gravity.NO_GRAVITY);
eLonDeg.setText(addZeros(gp.getLonDeg(), 3));
eLonMin.setText(addZeros(gp.getLonDegFrac(), 5));
+ eLonMin.setGravity(Gravity.NO_GRAVITY);
break;
case Min: // DDD° MM.MMM
getView().findViewById(R.id.coordTable).setVisibility(View.VISIBLE);
@@ -238,9 +256,11 @@ public class CoordinatesInputDialog extends DialogFragment {
eLatDeg.setText(addZeros(gp.getLatDeg(), 2));
eLatMin.setText(addZeros(gp.getLatMin(), 2));
+ eLatMin.setGravity(Gravity.RIGHT);
eLatSec.setText(addZeros(gp.getLatMinFrac(), 3));
eLonDeg.setText(addZeros(gp.getLonDeg(), 3));
eLonMin.setText(addZeros(gp.getLonMin(), 2));
+ eLonMin.setGravity(Gravity.RIGHT);
eLonSec.setText(addZeros(gp.getLonMinFrac(), 3));
break;
case Sec: // DDD° MM SS.SSS
@@ -263,10 +283,12 @@ public class CoordinatesInputDialog extends DialogFragment {
eLatDeg.setText(addZeros(gp.getLatDeg(), 2));
eLatMin.setText(addZeros(gp.getLatMin(), 2));
+ eLatMin.setGravity(Gravity.RIGHT);
eLatSec.setText(addZeros(gp.getLatSec(), 2));
eLatSub.setText(addZeros(gp.getLatSecFrac(), 3));
eLonDeg.setText(addZeros(gp.getLonDeg(), 3));
eLonMin.setText(addZeros(gp.getLonMin(), 2));
+ eLonMin.setGravity(Gravity.RIGHT);
eLonSec.setText(addZeros(gp.getLonSec(), 2));
eLonSub.setText(addZeros(gp.getLonSecFrac(), 3));
break;
@@ -391,16 +413,18 @@ public class CoordinatesInputDialog extends DialogFragment {
final String lonDir = bLon.getText().toString();
final String latDeg = eLatDeg.getText().toString();
final String lonDeg = eLonDeg.getText().toString();
- final String latDegFrac = eLatMin.getText().toString();
- final String lonDegFrac = eLonMin.getText().toString();
+ // right-pad decimal fraction
+ final String latDegFrac = padZerosRight(eLatMin.getText().toString(), 5);
+ final String lonDegFrac = padZerosRight(eLonMin.getText().toString(), 5);
final String latMin = eLatMin.getText().toString();
final String lonMin = eLonMin.getText().toString();
final String latMinFrac = eLatSec.getText().toString();
final String lonMinFrac = eLonSec.getText().toString();
final String latSec = eLatSec.getText().toString();
final String lonSec = eLonSec.getText().toString();
- final String latSecFrac = eLatSub.getText().toString();
- final String lonSecFrac = eLonSub.getText().toString();
+ // right-pad seconds fraction
+ final String latSecFrac = padZerosRight(eLatSub.getText().toString(), 3);
+ final String lonSecFrac = padZerosRight(eLonSub.getText().toString(), 3);
switch (currentFormat) {
case Deg:
@@ -421,7 +445,7 @@ public class CoordinatesInputDialog extends DialogFragment {
gp = current;
return true;
}
- } catch (final Geopoint.ParseException e) {
+ } catch (final Geopoint.ParseException ignored) {
// Signaled and returned below
}
if (signalError) {
@@ -431,6 +455,10 @@ public class CoordinatesInputDialog extends DialogFragment {
return false;
}
+ private static String padZerosRight(final String value, final int len) {
+ return StringUtils.rightPad(value, len, '0');
+ }
+
public int getMaxLengthFromCurrentField(final EditText editText) {
if (editText == eLonDeg || editText == eLatSub || editText == eLonSub) {
return 3;
@@ -503,6 +531,17 @@ public class CoordinatesInputDialog extends DialogFragment {
}
}
+ private class ClipboardListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(final View v) {
+ try {
+ gp = new Geopoint(StringUtils.defaultString(ClipboardUtils.getText()));
+ updateGUI();
+ } catch (final ParseException ignored) {
+ }
+ }
+ }
private class InputDoneListener implements View.OnClickListener {
diff --git a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
index 1046f81..15c9556 100644
--- a/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
+++ b/main/src/cgeo/geocaching/ui/dialog/DateDialog.java
@@ -22,11 +22,11 @@ public class DateDialog extends DialogFragment {
private Calendar date;
public static DateDialog getInstance(final Calendar date) {
- final DateDialog dd = new DateDialog();
+ final DateDialog dateDialog = new DateDialog();
final Bundle args = new Bundle();
args.putSerializable("date", date);
- dd.setArguments(args);
- return dd;
+ dateDialog.setArguments(args);
+ return dateDialog;
}
@Override
diff --git a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
index 21e1a82..3729677 100644
--- a/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
+++ b/main/src/cgeo/geocaching/ui/dialog/Dialogs.java
@@ -25,8 +25,15 @@ import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
+import android.widget.ArrayAdapter;
import android.widget.EditText;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import java.util.List;
/**
* Wrapper for {@link AlertDialog}. If you want to show a simple text, use one of the
@@ -401,7 +408,6 @@ public final class Dialogs {
/**
* 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());
@@ -410,4 +416,44 @@ public final class Dialogs {
private static void enableDialogButtonIfNotEmpty(final AlertDialog dialog, final String input) {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(StringUtils.isNotBlank(input));
}
+
+ public static interface ItemWithIcon {
+ /**
+ * @return the drawable
+ */
+ int getIcon();
+ }
+
+ public static <T extends ItemWithIcon> void select(final Activity activity, final String title, final List<T> items, final Action1<T> listener) {
+ final ListAdapter adapter = new ArrayAdapter<T>(
+ activity,
+ android.R.layout.select_dialog_item,
+ android.R.id.text1,
+ items) {
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+ // standard list entry
+ final View v = super.getView(position, convertView, parent);
+
+ // add image
+ final TextView tv = (TextView) v.findViewById(android.R.id.text1);
+ tv.setCompoundDrawablesWithIntrinsicBounds(items.get(position).getIcon(), 0, 0, 0);
+
+ // Add margin between image and text
+ final int dp5 = (int) (5 * activity.getResources().getDisplayMetrics().density + 0.5f);
+ tv.setCompoundDrawablePadding(dp5);
+
+ return v;
+ }
+ };
+
+ new AlertDialog.Builder(activity)
+ .setTitle(title)
+ .setAdapter(adapter, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int item) {
+ listener.call(items.get(item));
+ }
+ }).show();
+ }
}
diff --git a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
index 9858c28..d4720bf 100644
--- a/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
+++ b/main/src/cgeo/geocaching/ui/dialog/LiveMapInfoDialogBuilder.java
@@ -15,7 +15,7 @@ import android.view.View;
public class LiveMapInfoDialogBuilder {
- public static AlertDialog create(Activity activity) {
+ public static AlertDialog create(final Activity activity) {
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final Context themedContext;
@@ -32,7 +32,7 @@ public class LiveMapInfoDialogBuilder {
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialog, int which) {
+ public void onClick(final DialogInterface dialog, final int which) {
dialog.dismiss();
CgeoApplication.getInstance().setLiveMapHintShownInThisSession();
}
diff --git a/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
index 7e49c97..076c412 100644
--- a/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/logs/CacheLogsViewCreator.java
@@ -2,6 +2,7 @@ package cgeo.geocaching.ui.logs;
import cgeo.geocaching.CacheDetailActivity;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
@@ -24,28 +25,33 @@ import java.util.Map.Entry;
public class CacheLogsViewCreator extends LogsViewCreator {
private final boolean allLogs;
private final Resources res = CgeoApplication.getInstance().getResources();
+ private final CacheDetailActivity cacheDetailActivity;
- public CacheLogsViewCreator(CacheDetailActivity cacheDetailActivity, boolean allLogs) {
+ public CacheLogsViewCreator(final CacheDetailActivity cacheDetailActivity, final boolean allLogs) {
super(cacheDetailActivity);
+ this.cacheDetailActivity = cacheDetailActivity;
this.allLogs = allLogs;
}
- /**
- * May return null!
- *
- * @return
- */
private Geocache getCache() {
- if (this.activity instanceof CacheDetailActivity) {
- CacheDetailActivity details = (CacheDetailActivity) this.activity;
- return details.getCache();
- }
- return null;
+ return cacheDetailActivity.getCache();
}
@Override
protected List<LogEntry> getLogs() {
- return allLogs ? getCache().getLogs() : getCache().getFriendsLogs();
+ final Geocache cache = getCache();
+ final List<LogEntry> logs = allLogs ? cache.getLogs() : cache.getFriendsLogs();
+ return addOwnOfflineLog(cache, logs);
+ }
+
+ private List<LogEntry> addOwnOfflineLog(final Geocache cache, final List<LogEntry> logsIn) {
+ final LogEntry log = DataStore.loadLogOffline(cache.getGeocode());
+ final ArrayList<LogEntry> logs = new ArrayList<>(logsIn);
+ if (log != null) {
+ log.author = res.getString(R.string.log_your_saved_log);
+ logs.add(0, log);
+ }
+ return logs;
}
@Override
@@ -56,7 +62,7 @@ public class CacheLogsViewCreator extends LogsViewCreator {
final List<Entry<LogType, Integer>> sortedLogCounts = new ArrayList<>(logCounts.size());
for (final Entry<LogType, Integer> entry : logCounts.entrySet()) {
// it may happen that the label is unknown -> then avoid any output for this type
- if (entry.getKey() != LogType.PUBLISH_LISTING && entry.getKey().getL10n() != null && entry.getValue() != 0) {
+ if (entry.getKey() != LogType.PUBLISH_LISTING && entry.getValue() != 0) {
sortedLogCounts.add(entry);
}
}
@@ -66,7 +72,7 @@ public class CacheLogsViewCreator extends LogsViewCreator {
Collections.sort(sortedLogCounts, new Comparator<Entry<LogType, Integer>>() {
@Override
- public int compare(Entry<LogType, Integer> logCountItem1, Entry<LogType, Integer> logCountItem2) {
+ public int compare(final Entry<LogType, Integer> logCountItem1, final Entry<LogType, Integer> logCountItem2) {
return logCountItem1.getKey().compareTo(logCountItem2.getKey());
}
});
@@ -84,7 +90,7 @@ public class CacheLogsViewCreator extends LogsViewCreator {
}
@Override
- protected void fillCountOrLocation(LogViewHolder holder, final LogEntry log) {
+ protected void fillCountOrLocation(final LogViewHolder holder, final LogEntry log) {
// finds count
if (log.found == -1) {
holder.countOrLocation.setVisibility(View.GONE);
@@ -95,6 +101,21 @@ public class CacheLogsViewCreator extends LogsViewCreator {
}
@Override
+ protected void fillViewHolder(final View convertView, final LogViewHolder holder, final LogEntry log) {
+ super.fillViewHolder(convertView, holder, log);
+ if (isOfflineLog(log)) {
+ holder.author.setOnClickListener(new EditOfflineLogListener(getCache(), cacheDetailActivity));
+ holder.text.setOnClickListener(new EditOfflineLogListener(getCache(), cacheDetailActivity));
+ holder.marker.setVisibility(View.VISIBLE);
+ holder.marker.setImageResource(R.drawable.mark_orange);
+ }
+ }
+
+ private boolean isOfflineLog(final LogEntry log) {
+ return log.author.equals(activity.getString(R.string.log_your_saved_log));
+ }
+
+ @Override
protected boolean isValid() {
return getCache() != null;
}
diff --git a/main/src/cgeo/geocaching/ui/logs/EditOfflineLogListener.java b/main/src/cgeo/geocaching/ui/logs/EditOfflineLogListener.java
new file mode 100644
index 0000000..2e0f154
--- /dev/null
+++ b/main/src/cgeo/geocaching/ui/logs/EditOfflineLogListener.java
@@ -0,0 +1,25 @@
+package cgeo.geocaching.ui.logs;
+
+import cgeo.geocaching.CacheDetailActivity;
+import cgeo.geocaching.Geocache;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+class EditOfflineLogListener implements OnClickListener {
+
+ private final Geocache cache;
+ private final CacheDetailActivity activity;
+
+ public EditOfflineLogListener(final Geocache cache, final CacheDetailActivity activity) {
+ this.cache = cache;
+ this.activity = activity;
+ }
+
+ @Override
+ public void onClick(final View v) {
+ activity.setNeedsRefresh();
+ cache.logVisit(activity);
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java b/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java
index 16f5537..302f86c 100644
--- a/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java
+++ b/main/src/cgeo/geocaching/ui/logs/LogViewHolder.java
@@ -20,7 +20,7 @@ public class LogViewHolder extends AbstractViewHolder {
private int position;
- public LogViewHolder(View rowView) {
+ public LogViewHolder(final View rowView) {
super(rowView);
}
diff --git a/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
index 23caf79..a6fd5aa 100644
--- a/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/logs/LogsViewCreator.java
@@ -4,8 +4,7 @@ import cgeo.geocaching.ImagesActivity;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.AbstractActionBarActivity;
-import cgeo.geocaching.list.StoredList;
-import cgeo.geocaching.network.HtmlImage;
+import cgeo.geocaching.network.SmileyImage;
import cgeo.geocaching.ui.AbstractCachingListViewPageViewCreator;
import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod;
import cgeo.geocaching.ui.DecryptTextClickListener;
@@ -69,7 +68,7 @@ public abstract class LogsViewCreator extends AbstractCachingListViewPageViewCre
return view;
}
- protected void fillViewHolder(final View convertView, final LogViewHolder holder, final LogEntry log) {
+ protected void fillViewHolder(@SuppressWarnings("unused") final View convertView, final LogViewHolder holder, final LogEntry log) {
if (log.date > 0) {
holder.date.setText(Formatter.formatShortDateVerbally(log.date));
holder.date.setVisibility(View.VISIBLE);
@@ -87,7 +86,7 @@ public abstract class LogsViewCreator extends AbstractCachingListViewPageViewCre
if (TextUtils.containsHtml(logText)) {
logText = log.getDisplayText();
final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler();
- holder.text.setText(Html.fromHtml(logText, new HtmlImage(getGeocode(), false, StoredList.STANDARD_LIST_ID, false, holder.text),
+ holder.text.setText(Html.fromHtml(logText, new SmileyImage(getGeocode(), holder.text),
unknownTagsHandler), TextView.BufferType.SPANNABLE);
} else {
holder.text.setText(logText, TextView.BufferType.SPANNABLE);
@@ -117,12 +116,10 @@ public abstract class LogsViewCreator extends AbstractCachingListViewPageViewCre
holder.marker.setVisibility(View.GONE);
}
- if (null == convertView) {
- holder.author.setOnClickListener(createUserActionsListener());
- holder.text.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
- holder.text.setOnClickListener(new DecryptTextClickListener(holder.text));
- activity.registerForContextMenu(holder.text);
- }
+ holder.author.setOnClickListener(createUserActionsListener());
+ holder.text.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance());
+ holder.text.setOnClickListener(new DecryptTextClickListener(holder.text));
+ activity.registerForContextMenu(holder.text);
}
abstract protected UserActionsClickListener createUserActionsListener();
diff --git a/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java b/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java
index 300f510..ef8f5cc 100644
--- a/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java
+++ b/main/src/cgeo/geocaching/ui/logs/TrackableLogsViewCreator.java
@@ -15,14 +15,15 @@ import java.util.List;
public class TrackableLogsViewCreator extends LogsViewCreator {
- private final Trackable trackable;
+ private Trackable trackable;
+ private final TrackableActivity trackableActivity;
/**
- * @param trackableActivity
*/
- public TrackableLogsViewCreator(TrackableActivity trackableActivity, final Trackable trackable) {
+ public TrackableLogsViewCreator(final TrackableActivity trackableActivity) {
super(trackableActivity);
- this.trackable = trackable;
+ this.trackableActivity = trackableActivity;
+ trackable = trackableActivity.getTrackable();
}
@Override
@@ -32,6 +33,7 @@ public class TrackableLogsViewCreator extends LogsViewCreator {
@Override
protected List<LogEntry> getLogs() {
+ trackable = trackableActivity.getTrackable();
return trackable.getLogs();
}
@@ -41,19 +43,20 @@ public class TrackableLogsViewCreator extends LogsViewCreator {
}
@Override
- protected void fillCountOrLocation(LogViewHolder holder, final LogEntry log) {
- if (StringUtils.isBlank(log.cacheName)) {
- holder.countOrLocation.setVisibility(View.GONE);
- } else {
+ protected void fillCountOrLocation(final LogViewHolder holder, final LogEntry log) {
+ if (StringUtils.isNotBlank(log.cacheName)) {
holder.countOrLocation.setText(Html.fromHtml(log.cacheName));
+ holder.countOrLocation.setVisibility(View.VISIBLE);
final String cacheGuid = log.cacheGuid;
final String cacheName = log.cacheName;
holder.countOrLocation.setOnClickListener(new View.OnClickListener() {
@Override
- public void onClick(View arg0) {
+ public void onClick(final View arg0) {
CacheDetailActivity.startActivityGuid(activity, cacheGuid, Html.fromHtml(cacheName).toString());
}
});
+ } else {
+ holder.countOrLocation.setVisibility(View.GONE);
}
}
diff --git a/main/src/cgeo/geocaching/utils/AngleUtils.java b/main/src/cgeo/geocaching/utils/AngleUtils.java
index fdd9a9d..5ab2c75 100644
--- a/main/src/cgeo/geocaching/utils/AngleUtils.java
+++ b/main/src/cgeo/geocaching/utils/AngleUtils.java
@@ -1,7 +1,17 @@
package cgeo.geocaching.utils;
+import cgeo.geocaching.CgeoApplication;
+
+import android.content.Context;
+import android.view.Surface;
+import android.view.WindowManager;
+
public final class AngleUtils {
+ private static class WindowManagerHolder {
+ public static final WindowManager WINDOW_MANAGER = (WindowManager) CgeoApplication.getInstance().getSystemService(Context.WINDOW_SERVICE);
+ }
+
private AngleUtils() {
// Do not instantiate
}
@@ -27,4 +37,37 @@ public final class AngleUtils {
public static float normalize(final float angle) {
return (angle >= 0 ? angle : (360 - ((-angle) % 360))) % 360;
}
+
+ public static int getRotationOffset() {
+ switch (WindowManagerHolder.WINDOW_MANAGER.getDefaultDisplay().getRotation()) {
+ case Surface.ROTATION_90:
+ return 90;
+ case Surface.ROTATION_180:
+ return 180;
+ case Surface.ROTATION_270:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Take the phone rotation (through a given activity) in account and adjust the direction.
+ *
+ * @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 float direction) {
+ return normalize(direction + getRotationOffset());
+ }
+
+ /**
+ * Reverse the phone rotation (through a given activity) in account and adjust the direction.
+ *
+ * @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 reverseDirectionNow(final float direction) {
+ return normalize(direction - getRotationOffset());
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java b/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java
index 3d2b2b1..c2edd24 100644
--- a/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java
+++ b/main/src/cgeo/geocaching/utils/AsyncTaskWithProgress.java
@@ -14,8 +14,6 @@ import android.os.AsyncTask;
* automatically derived from the number of {@code Params} given to the task in {@link #execute(Object...)}.
* </p>
*
- * @param <Params>
- * @param <Result>
*/
public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Params, Integer, Result> {
@@ -28,9 +26,6 @@ public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Pa
/**
* Creates an AsyncTask with progress dialog.
*
- * @param activity
- * @param progressTitle
- * @param progressMessage
*/
public AsyncTaskWithProgress(final Activity activity, final String progressTitle, final String progressMessage) {
this(activity, progressTitle, progressMessage, false);
@@ -39,8 +34,6 @@ public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Pa
/**
* Creates an AsyncTask with progress dialog.
*
- * @param activity
- * @param progressTitle
*/
public AsyncTaskWithProgress(final Activity activity, final String progressTitle) {
this(activity, progressTitle, null);
@@ -49,9 +42,6 @@ public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Pa
/**
* Creates an AsyncTask with progress dialog.
*
- * @param activity
- * @param progressTitle
- * @param progressMessage
*/
public AsyncTaskWithProgress(final Activity activity, final String progressTitle, final String progressMessage, final boolean indeterminate) {
this.activity = activity;
@@ -63,8 +53,6 @@ public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Pa
/**
* Creates an AsyncTask with progress dialog.
*
- * @param activity
- * @param progressTitle
*/
public AsyncTaskWithProgress(final Activity activity, final String progressTitle, final boolean indeterminate) {
this(activity, progressTitle, null, indeterminate);
@@ -102,6 +90,8 @@ public abstract class AsyncTaskWithProgress<Params, Result> extends AsyncTask<Pa
* This method should typically be overridden by sub classes instead of {@link #onPostExecute(Object)}.
*
* @param result
+ * The result of the operation computed by {@link #doInBackground(Object...)}.
+ *
*/
protected void onPostExecuteInternal(final Result result) {
// empty by default
diff --git a/main/src/cgeo/geocaching/utils/BundleUtils.java b/main/src/cgeo/geocaching/utils/BundleUtils.java
index 9c4255b..e61e45e 100644
--- a/main/src/cgeo/geocaching/utils/BundleUtils.java
+++ b/main/src/cgeo/geocaching/utils/BundleUtils.java
@@ -7,8 +7,8 @@ import android.os.Bundle;
public class BundleUtils {
@NonNull
- public static String getString(Bundle bundle, @NonNull String key, @NonNull String defaultValue) {
- String res = bundle.getString(key);
+ public static String getString(final Bundle bundle, @NonNull final String key, @NonNull final String defaultValue) {
+ final String res = bundle.getString(key);
if (res != null) {
return res;
}
diff --git a/main/src/cgeo/geocaching/utils/DateUtils.java b/main/src/cgeo/geocaching/utils/CalendarUtils.java
index 9aa4222..ed3b18c 100644
--- a/main/src/cgeo/geocaching/utils/DateUtils.java
+++ b/main/src/cgeo/geocaching/utils/CalendarUtils.java
@@ -5,13 +5,13 @@ import cgeo.geocaching.Geocache;
import java.util.Calendar;
import java.util.Date;
-public final class DateUtils {
+public final class CalendarUtils {
- private DateUtils() {
+ private CalendarUtils() {
// utility class
}
- public static int daysSince(long date) {
+ public static int daysSince(final long date) {
final Calendar logDate = Calendar.getInstance();
logDate.setTimeInMillis(date);
logDate.set(Calendar.SECOND, 0);
@@ -24,12 +24,27 @@ public final class DateUtils {
return (int) Math.round((today.getTimeInMillis() - logDate.getTimeInMillis()) / 86400000d);
}
+ public static int daysSince(final Calendar date) {
+ return daysSince(date.getTimeInMillis());
+ }
+
public static boolean isPastEvent(final Geocache cache) {
if (!cache.isEventCache()) {
return false;
}
final Date hiddenDate = cache.getHiddenDate();
- return hiddenDate != null && DateUtils.daysSince(hiddenDate.getTime()) > 0;
+ return hiddenDate != null && CalendarUtils.daysSince(hiddenDate.getTime()) > 0;
+ }
+
+ /**
+ * Return whether the given date is *more* than 1 day away. We allow 1 day to be "present time" to compensate for
+ * potential timezone issues.
+ *
+ * @param date
+ * the date
+ */
+ public static boolean isFuture(final Calendar date) {
+ return daysSince(date) < -1;
}
}
diff --git a/main/src/cgeo/geocaching/utils/CancellableHandler.java b/main/src/cgeo/geocaching/utils/CancellableHandler.java
index 3ed233a..7b7aa6f 100644
--- a/main/src/cgeo/geocaching/utils/CancellableHandler.java
+++ b/main/src/cgeo/geocaching/utils/CancellableHandler.java
@@ -17,7 +17,7 @@ public abstract class CancellableHandler extends Handler {
public static final int DONE = -1000;
protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186;
private volatile boolean cancelled = false;
- private static CompositeSubscription subscriptions = new CompositeSubscription();
+ private final CompositeSubscription subscriptions = new CompositeSubscription();
private static class CancelHolder {
final Object payload;
diff --git a/main/src/cgeo/geocaching/utils/CheckerUtils.java b/main/src/cgeo/geocaching/utils/CheckerUtils.java
new file mode 100644
index 0000000..39ef078
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/CheckerUtils.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching.utils;
+
+import cgeo.geocaching.Geocache;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import android.util.Patterns;
+
+import java.util.regex.Matcher;
+
+public final class CheckerUtils {
+ private static final String[] CHECKERS = new String[] { "geocheck.org", "geochecker.com", "certitudes.org" };
+
+ private CheckerUtils() {
+ // utility class
+ }
+
+ @Nullable
+ public static String getCheckerUrl(@NonNull final Geocache cache) {
+ final String description = cache.getDescription();
+ final Matcher matcher = Patterns.WEB_URL.matcher(description);
+ while (matcher.find()) {
+ final String url = matcher.group();
+ for (final String checker : CHECKERS) {
+ if (StringUtils.containsIgnoreCase(url, checker)) {
+ return StringEscapeUtils.unescapeHtml4(url);
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/main/src/cgeo/geocaching/utils/ClipboardUtils.java b/main/src/cgeo/geocaching/utils/ClipboardUtils.java
index 77250f3..fb30886 100644
--- a/main/src/cgeo/geocaching/utils/ClipboardUtils.java
+++ b/main/src/cgeo/geocaching/utils/ClipboardUtils.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
+import org.eclipse.jdt.annotation.Nullable;
+
import android.content.Context;
/**
@@ -9,7 +11,6 @@ import android.content.Context;
* This class uses the deprecated function ClipboardManager.setText(CharSequence).
* API 11 introduced setPrimaryClip(ClipData)
*/
-@SuppressWarnings("deprecation")
public final class ClipboardUtils {
private ClipboardUtils() {
@@ -22,10 +23,24 @@ public final class ClipboardUtils {
* @param text
* The text to place in the clipboard.
*/
+ @SuppressWarnings("deprecation")
public static void copyToClipboard(final CharSequence text) {
// fully qualified name used here to avoid buggy deprecation warning (of javac) on the import statement
final android.text.ClipboardManager clipboard = (android.text.ClipboardManager) CgeoApplication.getInstance().getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(text);
}
+ /**
+ * get clipboard content
+ *
+ */
+ @SuppressWarnings("deprecation")
+ @Nullable
+ public static String getText() {
+ // fully qualified name used here to avoid buggy deprecation warning (of javac) on the import statement
+ final android.text.ClipboardManager clipboard = (android.text.ClipboardManager) CgeoApplication.getInstance().getSystemService(Context.CLIPBOARD_SERVICE);
+ final CharSequence text = clipboard.getText();
+ return text != null ? text.toString() : null;
+ }
+
}
diff --git a/main/src/cgeo/geocaching/utils/CryptUtils.java b/main/src/cgeo/geocaching/utils/CryptUtils.java
index 815c2f4..4aec509 100644
--- a/main/src/cgeo/geocaching/utils/CryptUtils.java
+++ b/main/src/cgeo/geocaching/utils/CryptUtils.java
@@ -1,6 +1,5 @@
package cgeo.geocaching.utils;
-
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
@@ -23,28 +22,29 @@ public final class CryptUtils {
// utility class
}
- private static char[] base64map1 = new char[64];
- private static byte[] base64map2 = new byte[128];
+ private static final byte[] EMPTY = {};
+ private static final char[] BASE64MAP1 = new char[64];
+ private static final byte[] BASE64MAP2 = new byte[128];
static {
int i = 0;
for (char c = 'A'; c <= 'Z'; c++) {
- base64map1[i++] = c;
+ BASE64MAP1[i++] = c;
}
for (char c = 'a'; c <= 'z'; c++) {
- base64map1[i++] = c;
+ BASE64MAP1[i++] = c;
}
for (char c = '0'; c <= '9'; c++) {
- base64map1[i++] = c;
+ BASE64MAP1[i++] = c;
}
- base64map1[i++] = '+';
- base64map1[i++] = '/';
+ BASE64MAP1[i++] = '+';
+ BASE64MAP1[i++] = '/';
- for (i = 0; i < base64map2.length; i++) {
- base64map2[i] = -1;
+ for (i = 0; i < BASE64MAP2.length; i++) {
+ BASE64MAP2[i] = -1;
}
for (i = 0; i < 64; i++) {
- base64map2[base64map1[i]] = (byte) i;
+ BASE64MAP2[BASE64MAP1[i]] = (byte) i;
}
}
@@ -58,7 +58,7 @@ public final class CryptUtils {
} else if (result == ']') {
plaintext = false;
} else if (!plaintext) {
- int capitalized = result & 32;
+ final int capitalized = result & 32;
result &= ~capitalized;
result = ((result >= 'A') && (result <= 'Z') ? ((result - 'A' + 13) % 26 + 'A') : result)
| capitalized;
@@ -68,50 +68,44 @@ public final class CryptUtils {
}
@NonNull
- public static String rot13(String text) {
+ public static String rot13(final String text) {
if (text == null) {
return StringUtils.EMPTY;
}
final StringBuilder result = new StringBuilder();
- Rot13Encryption rot13 = new Rot13Encryption();
+ final Rot13Encryption rot13 = new Rot13Encryption();
final int length = text.length();
for (int index = 0; index < length; index++) {
- char c = text.charAt(index);
+ final char c = text.charAt(index);
result.append(rot13.getNextEncryptedCharacter(c));
}
return result.toString();
}
- public static String md5(String text) {
+ public static String md5(final String text) {
try {
final MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(text.getBytes(CharEncoding.UTF_8), 0, text.length());
return new BigInteger(1, digest.digest()).toString(16);
- } catch (NoSuchAlgorithmException e) {
- Log.e("CryptUtils.md5", e);
- } catch (UnsupportedEncodingException e) {
+ } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
Log.e("CryptUtils.md5", e);
}
return StringUtils.EMPTY;
}
- public static byte[] hashHmac(String text, String salt) {
- byte[] macBytes = {};
+ public static byte[] hashHmac(final String text, final String salt) {
try {
final SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(CharEncoding.UTF_8), "HmacSHA1");
final Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKeySpec);
- macBytes = mac.doFinal(text.getBytes(CharEncoding.UTF_8));
- } catch (GeneralSecurityException e) {
- Log.e("CryptUtils.hashHmac", e);
- } catch (UnsupportedEncodingException e) {
+ return mac.doFinal(text.getBytes(CharEncoding.UTF_8));
+ } catch (GeneralSecurityException | UnsupportedEncodingException e) {
Log.e("CryptUtils.hashHmac", e);
+ return EMPTY;
}
-
- return macBytes;
}
public static CharSequence rot13(final Spannable span) {
@@ -119,37 +113,37 @@ public final class CryptUtils {
// a SpannableStringBuilder instead of the pure text and we must replace each character inline.
// Otherwise we loose all the images, colors and so on...
final SpannableStringBuilder buffer = new SpannableStringBuilder(span);
- Rot13Encryption rot13 = new Rot13Encryption();
+ final Rot13Encryption rot13 = new Rot13Encryption();
final int length = span.length();
for (int index = 0; index < length; index++) {
- char c = span.charAt(index);
+ final char c = span.charAt(index);
buffer.replace(index, index + 1, String.valueOf(rot13.getNextEncryptedCharacter(c)));
}
return buffer;
}
- public static String base64Encode(byte[] in) {
- int iLen = in.length;
- int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
- int oLen = ((iLen + 2) / 3) * 4; // output length including padding
- char[] out = new char[oLen];
+ public static String base64Encode(final byte[] in) {
+ final int iLen = in.length;
+ final int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
+ final int oLen = ((iLen + 2) / 3) * 4; // output length including padding
+ final char[] out = new char[oLen];
int ip = 0;
int op = 0;
while (ip < iLen) {
- int i0 = in[ip++] & 0xff;
- int i1 = ip < iLen ? in[ip++] & 0xff : 0;
- int i2 = ip < iLen ? in[ip++] & 0xff : 0;
- int o0 = i0 >>> 2;
- int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
- int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
- int o3 = i2 & 0x3F;
- out[op++] = base64map1[o0];
- out[op++] = base64map1[o1];
- out[op] = op < oDataLen ? base64map1[o2] : '=';
+ final int i0 = in[ip++] & 0xff;
+ final int i1 = ip < iLen ? in[ip++] & 0xff : 0;
+ final int i2 = ip < iLen ? in[ip++] & 0xff : 0;
+ final int o0 = i0 >>> 2;
+ final int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
+ final int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
+ final int o3 = i2 & 0x3F;
+ out[op++] = BASE64MAP1[o0];
+ out[op++] = BASE64MAP1[o1];
+ out[op] = op < oDataLen ? BASE64MAP1[o2] : '=';
op++;
- out[op] = op < oDataLen ? base64map1[o3] : '=';
+ out[op] = op < oDataLen ? BASE64MAP1[o3] : '=';
op++;
}
diff --git a/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java b/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
index d8aff74..a65a9fb 100644
--- a/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
+++ b/main/src/cgeo/geocaching/utils/DatabaseBackupUtils.java
@@ -6,9 +6,18 @@ import cgeo.geocaching.R;
import cgeo.geocaching.ui.dialog.Dialogs;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+import rx.functions.Action0;
+import rx.functions.Action1;
+import rx.functions.Func0;
+import rx.schedulers.Schedulers;
import android.app.Activity;
import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
import android.content.res.Resources;
import java.io.File;
@@ -21,70 +30,107 @@ public class DatabaseBackupUtils {
}
/**
- * restore the database in a new thread, showing a progress window
+ * After confirming to overwrite the existing caches on the devices, restore the database in a new thread, showing a
+ * progress window
*
* @param activity
* calling activity
*/
public static void restoreDatabase(final Activity activity) {
+ if (!hasBackup()) {
+ return;
+ }
+ final int caches = DataStore.getAllCachesCount();
+ if (caches == 0) {
+ restoreDatabaseInternal(activity);
+ }
+ else {
+ Dialogs.confirm(activity, R.string.init_backup_restore, activity.getString(R.string.restore_confirm_overwrite, activity.getResources().getQuantityString(R.plurals.cache_counts, caches, caches)), new OnClickListener() {
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ restoreDatabaseInternal(activity);
+ }
+ });
+
+ }
+ }
+
+ private static void restoreDatabaseInternal(final Activity activity) {
final Resources res = activity.getResources();
final ProgressDialog dialog = ProgressDialog.show(activity, res.getString(R.string.init_backup_restore), res.getString(R.string.init_restore_running), true, false);
final AtomicBoolean restoreSuccessful = new AtomicBoolean(false);
- new Thread() {
+ RxUtils.andThenOnUi(Schedulers.io(), new Action0() {
@Override
- public void run() {
+ public void call() {
restoreSuccessful.set(DataStore.restoreDatabaseInternal());
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- dialog.dismiss();
- boolean restored = restoreSuccessful.get();
- String message = restored ? res.getString(R.string.init_restore_success) : res.getString(R.string.init_restore_failed);
- Dialogs.message(activity, R.string.init_backup_restore, message);
- if (activity instanceof MainActivity) {
- ((MainActivity) activity).updateCacheCounter();
- }
- }
- });
}
- }.start();
+ }, new Action0() {
+ @Override
+ public void call() {
+ dialog.dismiss();
+ final boolean restored = restoreSuccessful.get();
+ final String message = restored ? res.getString(R.string.init_restore_success) : res.getString(R.string.init_restore_failed);
+ Dialogs.message(activity, R.string.init_backup_restore, message);
+ if (activity instanceof MainActivity) {
+ ((MainActivity) activity).updateCacheCounter();
+ }
+ }
+ });
}
- public static boolean createBackup(final Activity activity, final Runnable runAfterwards) {
+ /**
+ * Create a backup after confirming to overwrite the existing backup.
+ *
+ */
+ public static void createBackup(final Activity activity, final Runnable runAfterwards) {
// avoid overwriting an existing backup with an empty database
// (can happen directly after reinstalling the app)
if (DataStore.getAllCachesCount() == 0) {
Dialogs.message(activity, R.string.init_backup, R.string.init_backup_unnecessary);
- return false;
+ return;
}
+ if (hasBackup()) {
+ Dialogs.confirm(activity, R.string.init_backup, activity.getString(R.string.backup_confirm_overwrite, getBackupDateTime()), new OnClickListener() {
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ createBackupInternal(activity, runAfterwards);
+ }
+ });
+ }
+ else {
+ createBackupInternal(activity, runAfterwards);
+ }
+ }
+
+ private static void createBackupInternal(final Activity activity, final Runnable runAfterwards) {
final ProgressDialog dialog = ProgressDialog.show(activity,
activity.getString(R.string.init_backup),
activity.getString(R.string.init_backup_running), true, false);
- new Thread() {
+ RxUtils.andThenOnUi(Schedulers.io(), new Func0<String>() {
+ @Override
+ public String call() {
+ return DataStore.backupDatabaseInternal();
+ }
+ }, new Action1<String>() {
@Override
- public void run() {
- final String backupFileName = DataStore.backupDatabaseInternal();
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- dialog.dismiss();
- Dialogs.message(activity,
- R.string.init_backup_backup,
- backupFileName != null
- ? activity.getString(R.string.init_backup_success)
- + "\n" + backupFileName
- : activity.getString(R.string.init_backup_failed));
- if (runAfterwards != null) {
- runAfterwards.run();
- }
- }
- });
+ public void call(final String backupFileName) {
+ dialog.dismiss();
+ Dialogs.message(activity,
+ R.string.init_backup_backup,
+ backupFileName != null
+ ? activity.getString(R.string.init_backup_success)
+ + "\n" + backupFileName
+ : activity.getString(R.string.init_backup_failed));
+ if (runAfterwards != null) {
+ runAfterwards.run();
+ }
}
- }.start();
- return true;
+ });
}
+ @Nullable
public static File getRestoreFile() {
final File fileSourceFile = DataStore.getBackupFileInternal();
return fileSourceFile.exists() && fileSourceFile.length() > 0 ? fileSourceFile : null;
@@ -94,6 +140,7 @@ public class DatabaseBackupUtils {
return getRestoreFile() != null;
}
+ @NonNull
public static String getBackupDateTime() {
final File restoreFile = getRestoreFile();
if (restoreFile == null) {
diff --git a/main/src/cgeo/geocaching/utils/DebugUtils.java b/main/src/cgeo/geocaching/utils/DebugUtils.java
index 07aac64..1f95e7c 100644
--- a/main/src/cgeo/geocaching/utils/DebugUtils.java
+++ b/main/src/cgeo/geocaching/utils/DebugUtils.java
@@ -22,15 +22,14 @@ public class DebugUtils {
public static void createMemoryDump(final @NonNull Context context) {
try {
- final Date now = new Date();
final SimpleDateFormat fileNameDateFormat = new SimpleDateFormat("yyyy-MM-dd_hh-mm", Locale.US);
- File file = FileUtils.getUniqueNamedFile(Environment.getExternalStorageDirectory().getPath()
- + File.separatorChar + "cgeo_dump_" + fileNameDateFormat.format(now) + ".hprof");
+ final File file = FileUtils.getUniqueNamedFile(new File(Environment.getExternalStorageDirectory(),
+ "cgeo_dump_" + fileNameDateFormat.format(new Date()) + ".hprof"));
android.os.Debug.dumpHprofData(file.getPath());
Toast.makeText(context, context.getString(R.string.init_memory_dumped, file.getAbsolutePath()),
Toast.LENGTH_LONG).show();
ShareUtils.share(context, file, R.string.init_memory_dump);
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("createMemoryDump", e);
}
}
diff --git a/main/src/cgeo/geocaching/utils/EditUtils.java b/main/src/cgeo/geocaching/utils/EditUtils.java
index 0bfe2ea..455ce4d 100644
--- a/main/src/cgeo/geocaching/utils/EditUtils.java
+++ b/main/src/cgeo/geocaching/utils/EditUtils.java
@@ -17,7 +17,7 @@ public final class EditUtils {
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_GO) {
runnable.run();
return true;
@@ -30,7 +30,7 @@ public final class EditUtils {
editText.setOnKeyListener(new View.OnKeyListener() {
@Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
+ public boolean onKey(final View v, final int keyCode, final KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
runnable.run();
@@ -42,7 +42,7 @@ public final class EditUtils {
}
- public static void disableSuggestions(EditText edit) {
+ public static void disableSuggestions(final EditText edit) {
edit.setInputType(edit.getInputType()
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
| InputType.TYPE_TEXT_VARIATION_FILTER);
diff --git a/main/src/cgeo/geocaching/utils/FileUtils.java b/main/src/cgeo/geocaching/utils/FileUtils.java
index 979820c..778b9c7 100644
--- a/main/src/cgeo/geocaching/utils/FileUtils.java
+++ b/main/src/cgeo/geocaching/utils/FileUtils.java
@@ -4,6 +4,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
import android.os.Handler;
import android.os.Message;
@@ -23,14 +24,18 @@ import java.util.List;
*/
public final class FileUtils {
+ private static final int MAX_DIRECTORY_SCAN_DEPTH = 30;
private static final String FILE_PROTOCOL = "file://";
private FileUtils() {
// utility class
}
- public static void listDir(List<File> result, File directory, FileSelector chooser, Handler feedBackHandler) {
+ public static void listDir(final List<File> result, final File directory, final FileSelector chooser, final Handler feedBackHandler) {
+ listDirInternally(result, directory, chooser, feedBackHandler, 0);
+ }
+ private static void listDirInternally(final List<File> result, final File directory, final FileSelector chooser, final Handler feedBackHandler, final int depths) {
if (directory == null || !directory.isDirectory() || !directory.canRead()
|| result == null
|| chooser == null) {
@@ -40,7 +45,7 @@ public final class FileUtils {
final File[] files = directory.listFiles();
if (ArrayUtils.isNotEmpty(files)) {
- for (File file : files) {
+ for (final File file : files) {
if (chooser.shouldEnd()) {
return;
}
@@ -63,12 +68,32 @@ public final class FileUtils {
feedBackHandler.sendMessage(Message.obtain(feedBackHandler, 0, name));
}
- listDir(result, file, chooser, feedBackHandler); // go deeper
+ if (depths < MAX_DIRECTORY_SCAN_DEPTH) {
+ listDirInternally(result, file, chooser, feedBackHandler, depths + 1); // go deeper
+ }
}
}
}
}
+ public static boolean deleteDirectory(@NonNull final File dir) {
+ final File[] files = dir.listFiles();
+
+ // Although we are called on an existing directory, it might have been removed concurrently
+ // in the meantime, for example by the user or by another cleanup task.
+ if (files != null) {
+ for (final File file : files) {
+ if (file.isDirectory()) {
+ deleteDirectory(file);
+ } else {
+ delete(file);
+ }
+ }
+ }
+
+ return delete(dir);
+ }
+
public static abstract class FileSelector {
public abstract boolean isSelected(File file);
@@ -86,18 +111,20 @@ public final class FileUtils {
* </ul>
* which does not yet exist.
*/
- public static File getUniqueNamedFile(final String baseNameAndPath) {
- String extension = StringUtils.substringAfterLast(baseNameAndPath, ".");
- String pathName = StringUtils.substringBeforeLast(baseNameAndPath, ".");
- int number = 1;
- while (new File(getNumberedFileName(pathName, extension, number)).exists()) {
- number++;
+ public static File getUniqueNamedFile(final File file) {
+ if (!file.exists()) {
+ return file;
}
- return new File(getNumberedFileName(pathName, extension, number));
- }
-
- private static String getNumberedFileName(String pathName, String extension, int number) {
- return pathName + (number > 1 ? "_" + Integer.toString(number) : "") + "." + extension;
+ final String baseNameAndPath = file.getPath();
+ final String prefix = StringUtils.substringBeforeLast(baseNameAndPath, ".") + "_";
+ final String extension = "." + StringUtils.substringAfterLast(baseNameAndPath, ".");
+ for (int i = 1; i < Integer.MAX_VALUE; i++) {
+ final File numbered = new File(prefix + i + extension);
+ if (!numbered.exists()) {
+ return numbered;
+ }
+ }
+ throw new IllegalStateException("Unable to generate a non-existing file name");
}
/**
@@ -129,7 +156,7 @@ public final class FileUtils {
* @return <code>true</code> if the directory was created, <code>false</code> on failure or if the directory already
* existed.
*/
- public static boolean mkdirs(File file) {
+ public static boolean mkdirs(final File file) {
final boolean success = file.mkdirs() || file.isDirectory(); // mkdirs returns false on existing directories
if (!success) {
Log.e("Could not make directories " + file.getAbsolutePath());
@@ -137,7 +164,7 @@ public final class FileUtils {
return success;
}
- public static boolean writeFileUTF16(File file, String content) {
+ public static boolean writeFileUTF16(final File file, final String content) {
// TODO: replace by some apache.commons IOUtils or FileUtils code
Writer fileWriter = null;
BufferedOutputStream buffer = null;
@@ -177,7 +204,7 @@ public final class FileUtils {
/**
* Local file name when {@link #isFileUrl(String)} is <tt>true</tt>.
- *
+ *
* @return the local file
*/
public static File urlToFile(final String url) {
diff --git a/main/src/cgeo/geocaching/utils/Formatter.java b/main/src/cgeo/geocaching/utils/Formatter.java
index 3068cd4..2127d59 100644
--- a/main/src/cgeo/geocaching/utils/Formatter.java
+++ b/main/src/cgeo/geocaching/utils/Formatter.java
@@ -17,6 +17,7 @@ import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
public abstract class Formatter {
@@ -33,7 +34,7 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatTime(long date) {
+ public static String formatTime(final long date) {
return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_TIME);
}
@@ -45,7 +46,7 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatDate(long date) {
+ public static String formatDate(final long date) {
return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE);
}
@@ -58,7 +59,7 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatFullDate(long date) {
+ public static String formatFullDate(final long date) {
return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_YEAR);
}
@@ -71,11 +72,15 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatShortDate(long date) {
- DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
+ public static String formatShortDate(final long date) {
+ final DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(context);
return dateFormat.format(date);
}
+ private static String formatShortDateIncludingWeekday(final long time) {
+ return DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY) + ", " + formatShortDate(time);
+ }
+
/**
* Generate a numeric date string according to system-wide settings (locale, date format)
* such as "10/20/2010". Today and yesterday will be presented as strings "today" and "yesterday".
@@ -84,8 +89,8 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatShortDateVerbally(long date) {
- int diff = cgeo.geocaching.utils.DateUtils.daysSince(date);
+ public static String formatShortDateVerbally(final long date) {
+ final int diff = CalendarUtils.daysSince(date);
switch (diff) {
case 0:
return CgeoApplication.getInstance().getString(R.string.log_today);
@@ -104,7 +109,7 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatShortDateTime(long date) {
+ public static String formatShortDateTime(final long date) {
return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL);
}
@@ -116,11 +121,11 @@ public abstract class Formatter {
* milliseconds since the epoch
* @return the formatted string
*/
- public static String formatDateTime(long date) {
+ public static String formatDateTime(final long date) {
return DateUtils.formatDateTime(context, date, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
}
- public static String formatCacheInfoLong(Geocache cache, CacheListType cacheListType) {
+ public static String formatCacheInfoLong(final Geocache cache, final CacheListType cacheListType) {
final ArrayList<String> infos = new ArrayList<>();
if (StringUtils.isNotBlank(cache.getGeocode())) {
infos.add(cache.getGeocode());
@@ -137,18 +142,18 @@ public abstract class Formatter {
return StringUtils.join(infos, Formatter.SEPARATOR);
}
- public static String formatCacheInfoShort(Geocache cache) {
+ public static String formatCacheInfoShort(final Geocache cache) {
final ArrayList<String> infos = new ArrayList<>();
addShortInfos(cache, infos);
return StringUtils.join(infos, Formatter.SEPARATOR);
}
- private static void addShortInfos(Geocache cache, final ArrayList<String> infos) {
+ private static void addShortInfos(final Geocache cache, final ArrayList<String> infos) {
if (cache.hasDifficulty()) {
- infos.add("D " + String.format("%.1f", cache.getDifficulty()));
+ infos.add("D " + formatDT(cache.getDifficulty()));
}
if (cache.hasTerrain()) {
- infos.add("T " + String.format("%.1f", cache.getTerrain()));
+ infos.add("T " + formatDT(cache.getTerrain()));
}
// don't show "not chosen" for events and virtuals, that should be the normal case
@@ -157,12 +162,16 @@ public abstract class Formatter {
} else if (cache.isEventCache()) {
final Date hiddenDate = cache.getHiddenDate();
if (hiddenDate != null) {
- infos.add(Formatter.formatShortDate(hiddenDate.getTime()));
+ infos.add(Formatter.formatShortDateIncludingWeekday(hiddenDate.getTime()));
}
}
}
- public static String formatCacheInfoHistory(Geocache cache) {
+ private static String formatDT(final float value) {
+ return String.format(Locale.getDefault(), "%.1f", value);
+ }
+
+ public static String formatCacheInfoHistory(final Geocache cache) {
final ArrayList<String> infos = new ArrayList<>(3);
infos.add(StringUtils.upperCase(cache.getGeocode()));
infos.add(Formatter.formatDate(cache.getVisitedDate()));
@@ -170,9 +179,9 @@ public abstract class Formatter {
return StringUtils.join(infos, Formatter.SEPARATOR);
}
- public static String formatWaypointInfo(Waypoint waypoint) {
+ public static String formatWaypointInfo(final Waypoint waypoint) {
final List<String> infos = new ArrayList<>(3);
- WaypointType waypointType = waypoint.getWaypointType();
+ final WaypointType waypointType = waypoint.getWaypointType();
if (waypointType != WaypointType.OWN && waypointType != null) {
infos.add(waypointType.getL10n());
}
@@ -188,4 +197,42 @@ public abstract class Formatter {
}
return StringUtils.join(infos, Formatter.SEPARATOR);
}
+
+ public static String formatDaysAgo(final long date) {
+ final int days = CalendarUtils.daysSince(date);
+ switch (days) {
+ case 0:
+ return CgeoApplication.getInstance().getString(R.string.log_today);
+ case 1:
+ return CgeoApplication.getInstance().getString(R.string.log_yesterday);
+ default:
+ return CgeoApplication.getInstance().getResources().getQuantityString(R.plurals.days_ago, days, days);
+ }
+ }
+
+ /**
+ * Formatting of the hidden date of a cache
+ *
+ * @return {@code null} or hidden date of the cache (or event date of the cache) in human readable format
+ */
+ public static String formatHiddenDate(final Geocache cache) {
+ final Date hiddenDate = cache.getHiddenDate();
+ if (hiddenDate == null) {
+ return null;
+ }
+ final long time = hiddenDate.getTime();
+ if (time <= 0) {
+ return null;
+ }
+ String dateString = Formatter.formatFullDate(time);
+ if (cache.isEventCache()) {
+ dateString = DateUtils.formatDateTime(CgeoApplication.getInstance().getBaseContext(), time, DateUtils.FORMAT_SHOW_WEEKDAY) + ", " + dateString;
+ }
+ return dateString;
+ }
+
+ public static String formatMapSubtitle(final Geocache cache) {
+ return "D " + formatDT(cache.getDifficulty()) + SEPARATOR + "T " + formatDT(cache.getTerrain()) + SEPARATOR + cache.getGeocode();
+ }
+
}
diff --git a/main/src/cgeo/geocaching/utils/HtmlUtils.java b/main/src/cgeo/geocaching/utils/HtmlUtils.java
index 51c4d6e..ab6e8fe 100644
--- a/main/src/cgeo/geocaching/utils/HtmlUtils.java
+++ b/main/src/cgeo/geocaching/utils/HtmlUtils.java
@@ -21,10 +21,8 @@ public final class HtmlUtils {
* Extract the text from a HTML based string. This is similar to what HTML.fromHtml(...) does, but this method also
* removes the embedded images instead of replacing them by a small rectangular representation character.
*
- * @param html
- * @return
*/
- public static String extractText(CharSequence html) {
+ public static String extractText(final CharSequence html) {
if (StringUtils.isBlank(html)) {
return StringUtils.EMPTY;
}
@@ -32,13 +30,13 @@ public final class HtmlUtils {
// recognize images in textview HTML contents
if (html instanceof Spanned) {
- Spanned text = (Spanned) html;
- Object[] styles = text.getSpans(0, text.length(), Object.class);
- ArrayList<Pair<Integer, Integer>> removals = new ArrayList<>();
- for (Object style : styles) {
+ final Spanned text = (Spanned) html;
+ final Object[] styles = text.getSpans(0, text.length(), Object.class);
+ final ArrayList<Pair<Integer, Integer>> removals = new ArrayList<>();
+ for (final Object style : styles) {
if (style instanceof ImageSpan) {
- int start = text.getSpanStart(style);
- int end = text.getSpanEnd(style);
+ final int start = text.getSpanStart(style);
+ final int end = text.getSpanEnd(style);
removals.add(Pair.of(start, end));
}
}
@@ -47,12 +45,12 @@ public final class HtmlUtils {
Collections.sort(removals, new Comparator<Pair<Integer, Integer>>() {
@Override
- public int compare(Pair<Integer, Integer> lhs, Pair<Integer, Integer> rhs) {
+ public int compare(final Pair<Integer, Integer> lhs, final Pair<Integer, Integer> rhs) {
return rhs.getRight().compareTo(lhs.getRight());
}
});
result = text.toString();
- for (Pair<Integer, Integer> removal : removals) {
+ for (final Pair<Integer, Integer> removal : removals) {
result = result.substring(0, removal.getLeft()) + result.substring(removal.getRight());
}
}
@@ -60,4 +58,15 @@ public final class HtmlUtils {
// now that images are gone, do a normal html to text conversion
return Html.fromHtml(result).toString().trim();
}
+
+ public static String removeExtraParagraph(final String htmlIn) {
+ final String html = StringUtils.trim(htmlIn);
+ if (StringUtils.startsWith(html, "<p>") && StringUtils.endsWith(html, "</p>")) {
+ final String paragraph = StringUtils.substring(html, "<p>".length(), html.length() - "</p>".length()).trim();
+ if (extractText(paragraph).equals(paragraph)) {
+ return paragraph;
+ }
+ }
+ return html;
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java
index 739ecc4..71d5e39 100644
--- a/main/src/cgeo/geocaching/utils/ImageUtils.java
+++ b/main/src/cgeo/geocaching/utils/ImageUtils.java
@@ -1,16 +1,20 @@
package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Image;
import cgeo.geocaching.R;
import cgeo.geocaching.compatibility.Compatibility;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import rx.Observable;
+import rx.Scheduler.Worker;
import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action0;
import rx.functions.Action1;
import android.content.res.Resources;
@@ -25,6 +29,8 @@ import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
+import android.text.Html;
+import android.text.Html.ImageGetter;
import android.util.Base64;
import android.util.Base64InputStream;
import android.widget.TextView;
@@ -36,8 +42,14 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
public final class ImageUtils {
private static final int[] ORIENTATIONS = new int[] {
@@ -49,6 +61,10 @@ public final class ImageUtils {
private static final int[] ROTATION = new int[] { 90, 180, 270 };
private static final int MAX_DISPLAY_IMAGE_XY = 800;
+ // Images whose URL contains one of those patterns will not be available on the Images tab
+ // for opening into an external application.
+ private final static String[] NO_EXTERNAL = new String[] { "geocheck.org" };
+
private ImageUtils() {
// Do not let this class be instantiated, this is a utility class.
}
@@ -61,7 +77,7 @@ public final class ImageUtils {
* @return BitmapDrawable The scaled image
*/
public static BitmapDrawable scaleBitmapToFitDisplay(@NonNull final Bitmap image) {
- Point displaySize = Compatibility.getDisplaySize();
+ final Point displaySize = Compatibility.getDisplaySize();
final int maxWidth = displaySize.x - 25;
final int maxHeight = displaySize.y - 25;
return scaleBitmapTo(image, maxWidth, maxHeight);
@@ -76,7 +92,7 @@ public final class ImageUtils {
*/
@Nullable
public static Bitmap readAndScaleImageToFitDisplay(@NonNull final String filename) {
- Point displaySize = Compatibility.getDisplaySize();
+ final Point displaySize = Compatibility.getDisplaySize();
// Restrict image size to 800 x 800 to prevent OOM on tablets
final int maxWidth = Math.min(displaySize.x - 25, MAX_DISPLAY_IMAGE_XY);
final int maxHeight = Math.min(displaySize.y - 25, MAX_DISPLAY_IMAGE_XY);
@@ -128,12 +144,12 @@ public final class ImageUtils {
*/
public static void storeBitmap(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String pathOfOutputImage) {
try {
- FileOutputStream out = new FileOutputStream(pathOfOutputImage);
- BufferedOutputStream bos = new BufferedOutputStream(out);
+ final FileOutputStream out = new FileOutputStream(pathOfOutputImage);
+ final BufferedOutputStream bos = new BufferedOutputStream(out);
bitmap.compress(format, quality, bos);
bos.flush();
bos.close();
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("ImageHelper.storeBitmap", e);
}
}
@@ -152,7 +168,7 @@ public final class ImageUtils {
if (maxXY <= 0) {
return filePath;
}
- Bitmap image = readDownsampledImage(filePath, maxXY, maxXY);
+ final Bitmap image = readDownsampledImage(filePath, maxXY, maxXY);
if (image == null) {
return null;
}
@@ -184,7 +200,7 @@ public final class ImageUtils {
try {
final ExifInterface exif = new ExifInterface(filePath);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
- } catch (IOException e) {
+ } catch (final IOException e) {
Log.e("ImageUtils.readDownsampledImage", e);
}
final BitmapFactory.Options sizeOnlyOptions = new BitmapFactory.Options();
@@ -233,7 +249,7 @@ public final class ImageUtils {
}
// Create a media file name
- String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
+ final String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
return new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
}
@@ -254,7 +270,7 @@ public final class ImageUtils {
* @return <tt>true</tt> if the URL contains at least one of the patterns, <tt>false</tt> otherwise
*/
public static boolean containsPattern(final String url, final String[] patterns) {
- for (String entry : patterns) {
+ for (final String entry : patterns) {
if (StringUtils.containsIgnoreCase(url, entry)) {
return true;
}
@@ -282,7 +298,7 @@ public final class ImageUtils {
/**
* Decode a base64-encoded string and save the result into a stream.
- *
+ *
* @param inString
* the encoded string
* @param out
@@ -303,42 +319,158 @@ public final class ImageUtils {
}
/**
+ * Add images present in the HTML description to the existing collection.
+ * @param images a collection of images
+ * @param geocode the common title for images in the description
+ * @param htmlText the HTML description to be parsed, can be repeated
+ */
+ public static void addImagesFromHtml(final Collection<Image> images, final String geocode, final String... htmlText) {
+ final Set<String> urls = new LinkedHashSet<>();
+ for (final Image image : images) {
+ urls.add(image.getUrl());
+ }
+ for (final String text: htmlText) {
+ Html.fromHtml(StringUtils.defaultString(text), new ImageGetter() {
+ @Override
+ public Drawable getDrawable(final String source) {
+ if (!urls.contains(source) && canBeOpenedExternally(source)) {
+ images.add(new Image(source, StringUtils.defaultString(geocode)));
+ urls.add(source);
+ }
+ return null;
+ }
+ }, null);
+ }
+ }
+
+ /**
* Container which can hold a drawable (initially an empty one) and get a newer version when it
* becomes available. It also invalidates the view the container belongs to, so that it is
* redrawn properly.
+ * <p/>
+ * When a new version of the drawable is available, it is put into a queue and, if needed (no other elements
+ * waiting in the queue), a refresh is launched on the UI thread. This refresh will empty the queue (including
+ * elements arrived in the meantime) and ensures that the view is uploaded only once all the queued requests have
+ * been handled.
*/
- @SuppressWarnings("deprecation")
- public final static class ContainerDrawable extends BitmapDrawable implements Action1<Drawable> {
+ public static class ContainerDrawable extends BitmapDrawable implements Action1<Drawable> {
+ final private static Object lock = new Object(); // Used to lock the queue to determine if a refresh needs to be scheduled
+ final private static LinkedBlockingQueue<ImmutablePair<ContainerDrawable, Drawable>> REDRAW_QUEUE = new LinkedBlockingQueue<>();
+ final private static Set<TextView> VIEWS = new HashSet<>(); // Modified only on the UI thread
+ final private static Worker UI_WORKER = AndroidSchedulers.mainThread().createWorker();
+ final private static Action0 REDRAW_QUEUED_DRAWABLES = new Action0() {
+ @Override
+ public void call() {
+ redrawQueuedDrawables();
+ }
+ };
+
private Drawable drawable;
- final private TextView view;
+ final protected TextView view;
- public ContainerDrawable(@NonNull final TextView view) {
+ @SuppressWarnings("deprecation")
+ public ContainerDrawable(@NonNull final TextView view, final Observable<? extends Drawable> drawableObservable) {
this.view = view;
drawable = null;
setBounds(0, 0, 0, 0);
- }
-
- public ContainerDrawable(@NonNull final TextView view, final Observable<? extends Drawable> drawableObservable) {
- this(view);
- updateFrom(drawableObservable);
+ drawableObservable.subscribe(this);
}
@Override
- public void draw(final Canvas canvas) {
+ public final void draw(final Canvas canvas) {
if (drawable != null) {
drawable.draw(canvas);
}
}
@Override
- public void call(final Drawable newDrawable) {
+ public final void call(final Drawable newDrawable) {
+ final boolean needsRedraw;
+ synchronized (lock) {
+ // Check for emptyness inside the call to match the behaviour in redrawQueuedDrawables().
+ needsRedraw = REDRAW_QUEUE.isEmpty();
+ REDRAW_QUEUE.add(ImmutablePair.of(this, newDrawable));
+ }
+ if (needsRedraw) {
+ UI_WORKER.schedule(REDRAW_QUEUED_DRAWABLES);
+ }
+ }
+
+ /**
+ * Update the container with the new drawable. Called on the UI thread.
+ *
+ * @param newDrawable the new drawable
+ * @return the view to update
+ */
+ protected TextView updateDrawable(final Drawable newDrawable) {
setBounds(0, 0, newDrawable.getIntrinsicWidth(), newDrawable.getIntrinsicHeight());
drawable = newDrawable;
- view.setText(view.getText());
+ return view;
+ }
+
+ private static void redrawQueuedDrawables() {
+ if (!REDRAW_QUEUE.isEmpty()) {
+ // Add a small margin so that drawables arriving between the beginning of the allocation and the draining
+ // of the queue might be absorbed without reallocation.
+ final ArrayList<ImmutablePair<ContainerDrawable, Drawable>> toRedraw = new ArrayList<>(REDRAW_QUEUE.size() + 16);
+ synchronized (lock) {
+ // Empty the queue inside the lock to match the check done in call().
+ REDRAW_QUEUE.drainTo(toRedraw);
+ }
+ for (final ImmutablePair<ContainerDrawable, Drawable> redrawable : toRedraw) {
+ VIEWS.add(redrawable.left.updateDrawable(redrawable.right));
+ }
+ for (final TextView view : VIEWS) {
+ view.setText(view.getText());
+ }
+ VIEWS.clear();
+ }
+ }
+
+ }
+
+ /**
+ * Image that automatically scales to fit a line of text in the containing {@link TextView}.
+ */
+ public final static class LineHeightContainerDrawable extends ContainerDrawable {
+ public LineHeightContainerDrawable(@NonNull final TextView view, final Observable<? extends Drawable> drawableObservable) {
+ super(view, drawableObservable);
}
- public void updateFrom(final Observable<? extends Drawable> drawableObservable) {
- drawableObservable.observeOn(AndroidSchedulers.mainThread()).subscribe(this);
+ @Override
+ protected TextView updateDrawable(final Drawable newDrawable) {
+ super.updateDrawable(newDrawable);
+ setBounds(ImageUtils.scaleImageToLineHeight(newDrawable, view));
+ return view;
}
}
+
+ public static boolean canBeOpenedExternally(final String source) {
+ return !containsPattern(source, NO_EXTERNAL);
+ }
+
+ public static Rect scaleImageToLineHeight(final Drawable drawable, final TextView view) {
+ final int lineHeight = (int) (view.getLineHeight() * 0.8);
+ final int width = drawable.getIntrinsicWidth() * lineHeight / drawable.getIntrinsicHeight();
+ return new Rect(0, 0, width, lineHeight);
+ }
+
+ public static Bitmap convertToBitmap(final Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+
+ // handle solid colors, which have no width
+ int width = drawable.getIntrinsicWidth();
+ width = width > 0 ? width : 1;
+ int height = drawable.getIntrinsicHeight();
+ height = height > 0 ? height : 1;
+
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+
+ return bitmap;
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/JsonUtils.java b/main/src/cgeo/geocaching/utils/JsonUtils.java
new file mode 100644
index 0000000..492e137
--- /dev/null
+++ b/main/src/cgeo/geocaching/utils/JsonUtils.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+
+public class JsonUtils {
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+ public static final ObjectReader reader = mapper.reader();
+ public static final ObjectWriter writer = mapper.writer();
+
+ public static final JsonNodeFactory factory = new JsonNodeFactory(true);
+
+ private JsonUtils() {
+ // Do not instantiate
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/utils/LazyInitializedList.java b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
index b0e2e46..866acad 100644
--- a/main/src/cgeo/geocaching/utils/LazyInitializedList.java
+++ b/main/src/cgeo/geocaching/utils/LazyInitializedList.java
@@ -49,7 +49,7 @@ public abstract class LazyInitializedList<ElementType> extends AbstractList<Elem
}
@Override
- public void add(int index, final ElementType element) {
+ public void add(final int index, final ElementType element) {
getUnderlyingList().add(index, element);
}
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
index 6122532..aecfaf1 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedMap.java
@@ -30,7 +30,7 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
final int initialCapacity;
final float loadFactor;
- protected LeastRecentlyUsedMap(int maxEntries, int initialCapacity, float loadFactor, OperationModes opMode) {
+ protected LeastRecentlyUsedMap(final int maxEntries, final int initialCapacity, final float loadFactor, final OperationModes opMode) {
super(initialCapacity, loadFactor, (opMode==OperationModes.LRU_CACHE));
this.initialCapacity = initialCapacity;
this.loadFactor = loadFactor;
@@ -38,12 +38,12 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
this.opMode = opMode;
}
- protected LeastRecentlyUsedMap(int maxEntries, OperationModes opMode) {
+ protected LeastRecentlyUsedMap(final int maxEntries, final OperationModes opMode) {
this(maxEntries, 16, 0.75f, opMode);
}
@Override
- public V put(K key, V value) {
+ public V put(final K key, final V value) {
// in case the underlying Map is not running with accessOrder==true, the map won't notice any changes
// of existing keys, so for the normal BOUNDED mode we remove and put the value to get its order updated.
if (opMode == OperationModes.BOUNDED && containsKey(key)) {
@@ -57,7 +57,7 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
}
@Override
- protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
return size() > maxEntries;
}
@@ -66,9 +66,9 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
}
@Override
- public V remove(Object key) {
+ public V remove(final Object key) {
- V removed = super.remove(key);
+ final V removed = super.remove(key);
if (removed != null && removeHandler != null) {
removeHandler.onRemove(removed);
@@ -84,18 +84,18 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
* @param removeHandler
* The new handler to receive notifications or null to remove a handler
*/
- public void setRemoveHandler(RemoveHandler<V> removeHandler) {
+ public void setRemoveHandler(final RemoveHandler<V> removeHandler) {
this.removeHandler = removeHandler;
}
public static class LruCache<K, V> extends LeastRecentlyUsedMap<K, V> {
private static final long serialVersionUID = 9028478916221334454L;
- public LruCache(int maxEntries, int initialCapacity, float loadFactor) {
+ public LruCache(final int maxEntries, final int initialCapacity, final float loadFactor) {
super(maxEntries, initialCapacity, loadFactor, OperationModes.LRU_CACHE);
}
- public LruCache(int maxEntries) {
+ public LruCache(final int maxEntries) {
super(maxEntries, OperationModes.LRU_CACHE);
}
}
@@ -104,11 +104,11 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = -1476389304214398315L;
- public Bounded(int maxEntries, int initialCapacity, float loadFactor) {
+ public Bounded(final int maxEntries, final int initialCapacity, final float loadFactor) {
super(maxEntries, initialCapacity, loadFactor, OperationModes.BOUNDED);
}
- public Bounded(int maxEntries) {
+ public Bounded(final int maxEntries) {
super(maxEntries, OperationModes.BOUNDED);
}
}
@@ -117,7 +117,6 @@ public abstract class LeastRecentlyUsedMap<K, V> extends LinkedHashMap<K, V> {
* Interface for handlers that wish to get notified when items are
* removed from the LRUMap
*
- * @param <V>
*/
public interface RemoveHandler<V> {
diff --git a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
index a69f427..c139136 100644
--- a/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
+++ b/main/src/cgeo/geocaching/utils/LeastRecentlyUsedSet.java
@@ -20,21 +20,18 @@ import java.util.List;
* access has to be guarded externally or the synchronized getAsList method can be used
* to get a clone for iteration.
*/
-public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
- implements Cloneable, java.io.Serializable {
+public class LeastRecentlyUsedSet<E> extends AbstractSet<E> {
- private static final long serialVersionUID = -1942301031191419547L;
-
- private transient LeastRecentlyUsedMap<E, Object> map;
+ private final LeastRecentlyUsedMap<E, Object> map;
private static final Object PRESENT = new Object();
- public LeastRecentlyUsedSet(int maxEntries, int initialCapacity, float loadFactor) {
+ public LeastRecentlyUsedSet(final int maxEntries, final int initialCapacity, final float loadFactor) {
// because we don't use any Map.get() methods from the Set, BOUNDED and LRU_CACHE have the exact same Behaviour
// So we use LRU_CACHE mode because it should perform a bit better (as it doesn't re-add explicitly)
map = new LeastRecentlyUsedMap.LruCache<>(maxEntries, initialCapacity, loadFactor);
}
- public LeastRecentlyUsedSet(int maxEntries) {
+ public LeastRecentlyUsedSet(final int maxEntries) {
map = new LeastRecentlyUsedMap.LruCache<>(maxEntries);
}
@@ -79,7 +76,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
* @see HashSet
*/
@Override
- public synchronized boolean contains(Object o) {
+ public synchronized boolean contains(final Object o) {
return map.containsKey(o);
}
@@ -90,7 +87,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
* @see HashSet
*/
@Override
- public synchronized boolean add(E e) {
+ public synchronized boolean add(final E e) {
if (e == null) {
throw new IllegalArgumentException("LeastRecentlyUsedSet cannot take null element");
}
@@ -104,7 +101,7 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
* @see HashSet
*/
@Override
- public synchronized boolean remove(Object o) {
+ public synchronized boolean remove(final Object o) {
return map.remove(o) == PRESENT;
}
@@ -132,26 +129,6 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
}
/**
- * (synchronized) Clone of the set
- * Copy of the HashSet code if clone()
- *
- * @see HashSet
- */
- @Override
- @SuppressWarnings("unchecked")
- public Object clone() throws CloneNotSupportedException {
- try {
- synchronized (this) {
- final LeastRecentlyUsedSet<E> newSet = (LeastRecentlyUsedSet<E>) super.clone();
- newSet.map = (LeastRecentlyUsedMap<E, Object>) map.clone();
- return newSet;
- }
- } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
- }
-
- /**
* Creates a clone as a list in a synchronized fashion.
*
* @return List based clone of the set
@@ -160,56 +137,4 @@ public class LeastRecentlyUsedSet<E> extends AbstractSet<E>
return new ArrayList<>(this);
}
- /**
- * Serialization version of HashSet with the additional parameters for the custom Map
- *
- * @see HashSet
- */
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- // Write out any hidden serialization magic
- s.defaultWriteObject();
-
- // Write out HashMap capacity and load factor
- s.writeInt(map.initialCapacity);
- s.writeFloat(map.loadFactor);
- s.writeInt(map.getMaxEntries());
-
- // Write out size
- s.writeInt(map.size());
-
- // Write out all elements in the proper order.
- for (final E e : map.keySet()) {
- s.writeObject(e);
- }
- }
-
- /**
- * Serialization version of HashSet with the additional parameters for the custom Map
- *
- * @see HashSet
- */
- @SuppressWarnings("unchecked")
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- // Read in any hidden serialization magic
- s.defaultReadObject();
-
- // Read in HashMap capacity and load factor and create backing HashMap
- final int capacity = s.readInt();
- final float loadFactor = s.readFloat();
- final int maxEntries = s.readInt();
-
- map = new LeastRecentlyUsedMap.LruCache<>(maxEntries, capacity, loadFactor);
-
- // Read in size
- final int size = s.readInt();
-
- // Read in all elements in the proper order.
- for (int i = 0; i < size; i++) {
- E e = (E) s.readObject();
- map.put(e, PRESENT);
- }
- }
-
}
diff --git a/main/src/cgeo/geocaching/utils/Log.java b/main/src/cgeo/geocaching/utils/Log.java
index f338a8e..861faaa 100644
--- a/main/src/cgeo/geocaching/utils/Log.java
+++ b/main/src/cgeo/geocaching/utils/Log.java
@@ -37,62 +37,65 @@ public final class Log {
/**
* Save a copy of the debug flag from the settings for performance reasons.
*
- * @param isDebug
*/
public static void setDebug(final boolean isDebug) {
Log.isDebug = isDebug;
}
+ private static String addThreadInfo(final String msg) {
+ return new StringBuilder("[").append(Thread.currentThread().getName()).append("] ").append(msg).toString();
+ }
+
public static void v(final String msg) {
if (isDebug) {
- android.util.Log.v(TAG, msg);
+ android.util.Log.v(TAG, addThreadInfo(msg));
}
}
public static void v(final String msg, final Throwable t) {
if (isDebug) {
- android.util.Log.v(TAG, msg, t);
+ android.util.Log.v(TAG, addThreadInfo(msg), t);
}
}
public static void d(final String msg) {
if (isDebug) {
- android.util.Log.d(TAG, msg);
+ android.util.Log.d(TAG, addThreadInfo(msg));
}
}
public static void d(final String msg, final Throwable t) {
if (isDebug) {
- android.util.Log.d(TAG, msg, t);
+ android.util.Log.d(TAG, addThreadInfo(msg), t);
}
}
public static void i(final String msg) {
if (isDebug) {
- android.util.Log.i(TAG, msg);
+ android.util.Log.i(TAG, addThreadInfo(msg));
}
}
public static void i(final String msg, final Throwable t) {
if (isDebug) {
- android.util.Log.i(TAG, msg, t);
+ android.util.Log.i(TAG, addThreadInfo(msg), t);
}
}
public static void w(final String msg) {
- android.util.Log.w(TAG, msg);
+ android.util.Log.w(TAG, addThreadInfo(msg));
}
public static void w(final String msg, final Throwable t) {
- android.util.Log.w(TAG, msg, t);
+ android.util.Log.w(TAG, addThreadInfo(msg), t);
}
public static void e(final String msg) {
- android.util.Log.e(TAG, msg);
+ android.util.Log.e(TAG, addThreadInfo(msg));
}
public static void e(final String msg, final Throwable t) {
- android.util.Log.e(TAG, msg, t);
+ android.util.Log.e(TAG, addThreadInfo(msg), t);
}
/**
@@ -116,7 +119,7 @@ public final class Log {
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true), CharEncoding.UTF_8));
- writer.write(msg);
+ writer.write(addThreadInfo(msg));
} catch (final IOException e) {
Log.e("logToFile: cannot write to " + file, e);
} finally {
diff --git a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
index ff4013c..1db3d5b 100644
--- a/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
+++ b/main/src/cgeo/geocaching/utils/LogTemplateProvider.java
@@ -215,7 +215,7 @@ public final class LogTemplateProvider {
}
final Geocache cache = context.getCache();
if (cache != null) {
- return cache.getUrl();
+ return StringUtils.defaultString(cache.getUrl());
}
return StringUtils.EMPTY;
}
diff --git a/main/src/cgeo/geocaching/utils/MapUtils.java b/main/src/cgeo/geocaching/utils/MapUtils.java
index 5120ca5..f41247c 100644
--- a/main/src/cgeo/geocaching/utils/MapUtils.java
+++ b/main/src/cgeo/geocaching/utils/MapUtils.java
@@ -154,7 +154,6 @@ public final class MapUtils {
}
private static int calculateResolution(final Drawable marker) {
- final int resolution = marker.getIntrinsicWidth() > 40 ? (marker.getIntrinsicWidth() > 50 ? (marker.getIntrinsicWidth() > 70 ? (marker.getIntrinsicWidth() > 100 ? 4 : 3) : 2) : 1) : 0;
- return resolution;
+ return marker.getIntrinsicWidth() > 40 ? (marker.getIntrinsicWidth() > 50 ? (marker.getIntrinsicWidth() > 70 ? (marker.getIntrinsicWidth() > 100 ? 4 : 3) : 2) : 1) : 0;
}
}
diff --git a/main/src/cgeo/geocaching/utils/MatcherWrapper.java b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
index c99d3c4..733a18e 100644
--- a/main/src/cgeo/geocaching/utils/MatcherWrapper.java
+++ b/main/src/cgeo/geocaching/utils/MatcherWrapper.java
@@ -2,6 +2,8 @@ package cgeo.geocaching.utils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.eclipse.jdt.annotation.NonNull;
+
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -13,7 +15,7 @@ import java.util.regex.Pattern;
public class MatcherWrapper {
private final Matcher matcher;
- public MatcherWrapper(Pattern pattern, String input) {
+ public MatcherWrapper(@NonNull final Pattern pattern, @NonNull final String input) {
this.matcher = pattern.matcher(input);
}
@@ -24,14 +26,14 @@ public class MatcherWrapper {
return matcher.find();
}
- public boolean find(int start) {
+ public boolean find(final int start) {
return matcher.find(start);
}
/**
* see {@link Matcher#group(int)}
*/
- public String group(int index) {
+ public String group(final int index) {
return newString(matcher.group(index));
}
@@ -43,11 +45,9 @@ public class MatcherWrapper {
* <p>
* Do not change this method, even if Findbugs and other tools will report a violation for that line!
*
- * @param input
- * @return
*/
@SuppressFBWarnings("DM_STRING_CTOR")
- private static String newString(String input) {
+ private static String newString(final String input) {
if (input == null) {
return null;
}
@@ -78,7 +78,7 @@ public class MatcherWrapper {
/**
* see {@link Matcher#replaceAll(String)}
*/
- public String replaceAll(String replacement) {
+ public String replaceAll(final String replacement) {
return newString(matcher.replaceAll(replacement));
}
@@ -92,7 +92,7 @@ public class MatcherWrapper {
/**
* see {@link Matcher#replaceFirst(String)}
*/
- public String replaceFirst(String replacement) {
+ public String replaceFirst(final String replacement) {
return newString(matcher.replaceFirst(replacement));
}
}
diff --git a/main/src/cgeo/geocaching/utils/OOMDumpingUncaughtExceptionHandler.java b/main/src/cgeo/geocaching/utils/OOMDumpingUncaughtExceptionHandler.java
index 1401542..0c6365c 100644
--- a/main/src/cgeo/geocaching/utils/OOMDumpingUncaughtExceptionHandler.java
+++ b/main/src/cgeo/geocaching/utils/OOMDumpingUncaughtExceptionHandler.java
@@ -11,14 +11,12 @@ public class OOMDumpingUncaughtExceptionHandler implements UncaughtExceptionHand
private boolean defaultReplaced = false;
public static boolean activateHandler() {
-
final OOMDumpingUncaughtExceptionHandler handler = new OOMDumpingUncaughtExceptionHandler();
return handler.activate();
}
private boolean activate() {
-
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// replace default handler if that has not been done already
@@ -34,10 +32,8 @@ public class OOMDumpingUncaughtExceptionHandler implements UncaughtExceptionHand
}
public static boolean resetToDefault() {
-
- boolean defaultResetted = false;
-
final UncaughtExceptionHandler unspecificHandler = Thread.getDefaultUncaughtExceptionHandler();
+ boolean defaultResetted = unspecificHandler != null;
if (unspecificHandler instanceof OOMDumpingUncaughtExceptionHandler) {
final OOMDumpingUncaughtExceptionHandler handler = (OOMDumpingUncaughtExceptionHandler) unspecificHandler;
@@ -48,7 +44,6 @@ public class OOMDumpingUncaughtExceptionHandler implements UncaughtExceptionHand
}
private boolean reset() {
-
final boolean resetted = defaultReplaced;
if (defaultReplaced) {
diff --git a/main/src/cgeo/geocaching/utils/ProcessUtils.java b/main/src/cgeo/geocaching/utils/ProcessUtils.java
index d80674b..6a57cbf 100644
--- a/main/src/cgeo/geocaching/utils/ProcessUtils.java
+++ b/main/src/cgeo/geocaching/utils/ProcessUtils.java
@@ -3,7 +3,10 @@ package cgeo.geocaching.utils;
import cgeo.geocaching.CgeoApplication;
import org.apache.commons.collections4.CollectionUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -21,10 +24,8 @@ public final class ProcessUtils {
/**
* Preferred method to detect the availability of an external app
*
- * @param packageName
- * @return
*/
- public static boolean isLaunchable(final String packageName) {
+ public static boolean isLaunchable(@Nullable final String packageName) {
return getLaunchIntent(packageName) != null;
}
@@ -33,17 +34,15 @@ public final class ProcessUtils {
* This function is relatively costly, so if you know that the package in question has
* a launch intent, use isLaunchable() instead.
*
- * @param packageName
- * @return
*/
- public static boolean isInstalled(final String packageName) {
+ public static boolean isInstalled(@NonNull final String packageName) {
return isLaunchable(packageName) || hasPackageInstalled(packageName);
}
/**
* This will find installed applications even without launch intent (e.g. the streetview plugin).
*/
- private static boolean hasPackageInstalled(final String packageName) {
+ private static boolean hasPackageInstalled(@NonNull final String packageName) {
final List<PackageInfo> packs = CgeoApplication.getInstance().getPackageManager().getInstalledPackages(0);
for (final PackageInfo packageInfo : packs) {
if (packageName.equals(packageInfo.packageName)) {
@@ -56,7 +55,8 @@ public final class ProcessUtils {
/**
* This will find applications, which can be launched.
*/
- public static Intent getLaunchIntent(final String packageName) {
+ @Nullable
+ public static Intent getLaunchIntent(@Nullable final String packageName) {
if (packageName == null) {
return null;
}
@@ -65,12 +65,12 @@ public final class ProcessUtils {
// This can throw an exception where the exception type is only defined on API Level > 3
// therefore surround with try-catch
return packageManager.getLaunchIntentForPackage(packageName);
- } catch (final Exception e) {
+ } catch (final Exception ignored) {
return null;
}
}
- public static boolean isIntentAvailable(final String intent) {
+ public static boolean isIntentAvailable(@NonNull final String intent) {
return isIntentAvailable(intent, null);
}
@@ -79,16 +79,16 @@ public final class ProcessUtils {
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
* found, this method returns false.
- *
+ *
* @param action
* The Intent action to check for availability.
* @param uri
* The Intent URI to check for availability.
- *
+ *
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
- public static boolean isIntentAvailable(final String action, final Uri uri) {
+ public static boolean isIntentAvailable(@NonNull final String action, @Nullable final Uri uri) {
final PackageManager packageManager = CgeoApplication.getInstance().getPackageManager();
final Intent intent;
if (uri == null) {
@@ -98,7 +98,23 @@ public final class ProcessUtils {
}
final List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
- return CollectionUtils.isNotEmpty(list);
+ final List<ResolveInfo> servicesList = packageManager.queryIntentServices(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ return CollectionUtils.isNotEmpty(list) || CollectionUtils.isNotEmpty(servicesList);
+ }
+
+ @SuppressWarnings("deprecation")
+ public static void openMarket(final Activity activity, @NonNull final String packageName) {
+ try {
+ final String url = "market://details?id=" + packageName;
+ final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ activity.startActivity(marketIntent);
+
+ } catch (final RuntimeException ignored) {
+ // market not available, fall back to browser
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + packageName)));
+ }
}
}
diff --git a/main/src/cgeo/geocaching/utils/RxUtils.java b/main/src/cgeo/geocaching/utils/RxUtils.java
index 241ba78..08cc3e7 100644
--- a/main/src/cgeo/geocaching/utils/RxUtils.java
+++ b/main/src/cgeo/geocaching/utils/RxUtils.java
@@ -1,22 +1,56 @@
package cgeo.geocaching.utils;
import rx.Observable;
+import rx.Observable.OnSubscribe;
import rx.Scheduler;
+import rx.Scheduler.Worker;
+import rx.Subscriber;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action0;
+import rx.functions.Action1;
+import rx.functions.Func0;
+import rx.functions.Func1;
+import rx.internal.util.RxThreadFactory;
import rx.observables.BlockingObservable;
+import rx.observers.Subscribers;
import rx.schedulers.Schedulers;
+import rx.subjects.PublishSubject;
+import rx.subscriptions.Subscriptions;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
public class RxUtils {
- // Utility class, not to be instanciated
- private RxUtils() {}
+ private RxUtils() {
+ // Utility class, not to be instantiated
+ }
public final static Scheduler computationScheduler = Schedulers.computation();
- public static final Scheduler networkScheduler = Schedulers.from(new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()));
+ public static final Scheduler networkScheduler = Schedulers.from(Executors.newFixedThreadPool(10, new RxThreadFactory("network-")));
+
+ public static final Scheduler refreshScheduler = Schedulers.from(Executors.newFixedThreadPool(3, new RxThreadFactory("refresh-")));
+
+ private static final HandlerThread looperCallbacksThread =
+ new HandlerThread("looper callbacks", Process.THREAD_PRIORITY_DEFAULT);
+
+ static {
+ looperCallbacksThread.start();
+ }
+
+ public static final Looper looperCallbacksLooper = looperCallbacksThread.getLooper();
+ public static final Scheduler looperCallbacksScheduler = AndroidSchedulers.handlerThread(new Handler(looperCallbacksLooper));
+ public static final Worker looperCallbacksWorker = looperCallbacksScheduler.createWorker();
public static <T> void waitForCompletion(final BlockingObservable<T> observable) {
observable.lastOrDefault(null);
@@ -25,4 +59,139 @@ public class RxUtils {
public static void waitForCompletion(final Observable<?>... observables) {
waitForCompletion(Observable.merge(observables).toBlocking());
}
+
+ /**
+ * Subscribe function whose subscription and unsubscription take place on a looper thread.
+ *
+ * @param <T>
+ * the type of the observable
+ */
+ public static abstract class LooperCallbacks<T> implements OnSubscribe<T> {
+
+ final AtomicInteger counter = new AtomicInteger(0);
+ final long stopDelay;
+ final TimeUnit stopDelayUnit;
+ final protected PublishSubject<T> subject = PublishSubject.create();
+
+ public LooperCallbacks(final long stopDelay, final TimeUnit stopDelayUnit) {
+ this.stopDelay = stopDelay;
+ this.stopDelayUnit = stopDelayUnit;
+ }
+
+ public LooperCallbacks() {
+ this(0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ final public void call(final Subscriber<? super T> subscriber) {
+ subscriber.add(subject.subscribe(Subscribers.from(subscriber)));
+ looperCallbacksWorker.schedule(new Action0() {
+ @Override
+ public void call() {
+ if (counter.getAndIncrement() == 0) {
+ onStart();
+ }
+ subscriber.add(Subscriptions.create(new Action0() {
+ @Override
+ public void call() {
+ looperCallbacksWorker.schedule(new Action0() {
+ @Override
+ public void call() {
+ if (counter.decrementAndGet() == 0) {
+ onStop();
+ }
+ }
+ }, stopDelay, stopDelayUnit);
+ }
+ }));
+ }
+ });
+ }
+
+ abstract protected void onStart();
+
+ abstract protected void onStop();
+ }
+
+ public static<T> Observable<T> rememberLast(final Observable<T> observable, final T initialValue) {
+ final AtomicReference<T> lastValue = new AtomicReference<>(initialValue);
+ return observable.doOnNext(new Action1<T>() {
+ @Override
+ public void call(final T value) {
+ lastValue.set(value);
+ }
+ }).startWith(Observable.defer(new Func0<Observable<T>>() {
+ @Override
+ public Observable<T> call() {
+ final T last = lastValue.get();
+ return last != null ? Observable.just(last) : Observable.<T>empty();
+ }
+ })).replay(1).refCount();
+ }
+
+ public static <T> void andThenOnUi(final Scheduler scheduler, final Func0<T> background, final Action1<T> foreground) {
+ scheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ final T value = background.call();
+ AndroidSchedulers.mainThread().createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ foreground.call(value);
+ }
+ });
+ }
+ });
+ }
+
+ public static void andThenOnUi(final Scheduler scheduler, final Action0 background, final Action0 foreground) {
+ scheduler.createWorker().schedule(new Action0() {
+ @Override
+ public void call() {
+ background.call();
+ AndroidSchedulers.mainThread().createWorker().schedule(foreground);
+ }
+ });
+ }
+
+ /**
+ * Cache the last value of observables so that every key is associated to only one of them.
+ *
+ * @param <K> the type of the key
+ * @param <V> the type of the value
+ */
+ public static class ObservableCache<K, V> {
+
+ final private Func1<K, Observable<V>> func;
+ final private Map<K, Observable<V>> cached = new HashMap<>();
+
+ /**
+ * Create a new observables cache.
+ *
+ * @param func the function transforming a key into an observable
+ */
+ public ObservableCache(final Func1<K, Observable<V>> func) {
+ this.func = func;
+ }
+
+ /**
+ * Get the observable corresponding to a key. If the key has not already been
+ * seen, the function passed to the constructor will be called to build the observable
+ * <p/>
+ * If the observable has already emitted values, only the last one will be remembered.
+ *
+ * @param key the key
+ * @return the observable corresponding to the key
+ */
+ public synchronized Observable<V> get(final K key) {
+ if (cached.containsKey(key)) {
+ return cached.get(key);
+ }
+ final Observable<V> value = func.call(key).replay(1).refCount();
+ cached.put(key, value);
+ return value;
+ }
+
+ }
+
}
diff --git a/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java b/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java
index eee71ba..0743692 100644
--- a/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java
+++ b/main/src/cgeo/geocaching/utils/SimpleCancellableHandler.java
@@ -5,6 +5,7 @@ import cgeo.geocaching.activity.AbstractActivity;
import cgeo.geocaching.activity.Progress;
import android.content.res.Resources;
+import android.os.Bundle;
import android.os.Message;
import java.lang.ref.WeakReference;
@@ -21,7 +22,7 @@ public class SimpleCancellableHandler extends CancellableHandler {
@Override
protected void handleRegularMessage(final Message msg) {
- AbstractActivity activity = activityRef.get();
+ final AbstractActivity activity = activityRef.get();
if (activity != null && msg.getData() != null && msg.getData().getString(MESSAGE_TEXT) != null) {
activity.showToast(msg.getData().getString(MESSAGE_TEXT));
}
@@ -30,37 +31,37 @@ public class SimpleCancellableHandler extends CancellableHandler {
@Override
protected void handleCancel(final Object extra) {
- AbstractActivity activity = activityRef.get();
+ final AbstractActivity activity = activityRef.get();
if (activity != null) {
activity.showToast((String) extra);
}
dismissProgress();
}
- protected final void showToast(int resId) {
- AbstractActivity activity = activityRef.get();
+ protected final void showToast(final int resId) {
+ final AbstractActivity activity = activityRef.get();
if (activity != null) {
- Resources res = activity.getResources();
+ final Resources res = activity.getResources();
activity.showToast(res.getText(resId).toString());
}
}
protected final void dismissProgress() {
- Progress progressDialog = progressDialogRef.get();
+ final Progress progressDialog = progressDialogRef.get();
if (progressDialog != null) {
progressDialog.dismiss();
}
}
protected final void setProgressMessage(final String txt) {
- Progress progressDialog = progressDialogRef.get();
+ final Progress progressDialog = progressDialogRef.get();
if (progressDialog != null) {
progressDialog.setMessage(txt);
}
}
protected final void finishActivity() {
- AbstractActivity activity = activityRef.get();
+ final AbstractActivity activity = activityRef.get();
if (activity != null) {
activity.finish();
}
@@ -68,7 +69,7 @@ public class SimpleCancellableHandler extends CancellableHandler {
}
protected void updateStatusMsg(final int resId, final String msg) {
- CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
+ final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
if (activity != null) {
setProgressMessage(activity.getResources().getString(resId)
+ "\n\n"
@@ -76,4 +77,15 @@ public class SimpleCancellableHandler extends CancellableHandler {
}
}
+ public void sendTextMessage(final int what, final int resId) {
+ final CacheDetailActivity activity = ((CacheDetailActivity) activityRef.get());
+ if (activity != null) {
+ final Message msg = obtainMessage(what);
+ final Bundle bundle = new Bundle();
+ bundle.putString(SimpleCancellableHandler.MESSAGE_TEXT, activity.getResources().getString(resId));
+ msg.setData(bundle);
+ msg.sendToTarget();
+ }
+ }
+
}
diff --git a/main/src/cgeo/geocaching/utils/StartableHandlerThread.java b/main/src/cgeo/geocaching/utils/StartableHandlerThread.java
deleted file mode 100644
index 91ab1d0..0000000
--- a/main/src/cgeo/geocaching/utils/StartableHandlerThread.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package cgeo.geocaching.utils;
-
-import org.eclipse.jdt.annotation.NonNull;
-import rx.Subscriber;
-import rx.functions.Action0;
-import rx.subscriptions.Subscriptions;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-
-/**
- * Derivated class of {@link android.os.HandlerThread} with an exposed handler and a start/stop mechanism
- * based on subscriptions.
- */
-
-public class StartableHandlerThread extends HandlerThread {
-
- private final static int START = 1;
- private final static int STOP = 2;
-
- static public interface Callback {
- public void start(final Context context, final Handler handler);
- public void stop();
- }
-
- // The handler and the thread are intimely linked, there will be no leak.
- @SuppressLint("HandlerLeak")
- private class StartableHandler extends Handler {
- public StartableHandler() {
- super(StartableHandlerThread.this.getLooper());
- }
-
- @Override
- public void handleMessage(final Message message) {
- if (callback != null) {
- switch (message.what) {
- case START:
- callback.start((Context) message.obj, this);
- break;
- case STOP:
- callback.stop();
- break;
- }
- }
- }
- }
-
- private Handler handler;
- private Callback callback;
-
- public StartableHandlerThread(@NonNull final String name, final int priority, final Callback callback) {
- super(name, priority);
- this.callback = callback;
- }
-
- public StartableHandlerThread(@NonNull final String name, final int priority) {
- this(name, priority, null);
- }
-
- public synchronized Handler getHandler() {
- if (handler == null) {
- handler = new StartableHandler();
- }
- return handler;
- }
-
- public void start(final Subscriber<?> subscriber, final Context context) {
- getHandler().obtainMessage(START, context).sendToTarget();
- subscriber.add(Subscriptions.create(new Action0() {
- @Override
- public void call() {
- getHandler().sendEmptyMessage(STOP);
- }
- }));
- }
-
-}
diff --git a/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java b/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
index 7848d1a..5963e2e 100644
--- a/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
+++ b/main/src/cgeo/geocaching/utils/SynchronizedDateFormat.java
@@ -13,7 +13,7 @@ public class SynchronizedDateFormat {
format = new SimpleDateFormat(pattern, locale);
}
- public SynchronizedDateFormat(String pattern, TimeZone timeZone, Locale locale) {
+ public SynchronizedDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
format = new SimpleDateFormat(pattern, locale);
format.setTimeZone(timeZone);
}
diff --git a/main/src/cgeo/geocaching/utils/TextUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java
index 77aa167..1f14f8d 100644
--- a/main/src/cgeo/geocaching/utils/TextUtils.java
+++ b/main/src/cgeo/geocaching/utils/TextUtils.java
@@ -8,6 +8,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.eclipse.jdt.annotation.Nullable;
import java.nio.charset.Charset;
+import java.text.Collator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
@@ -27,11 +28,11 @@ public final class TextUtils {
}
/**
- * Searches for the pattern p in the data. If the pattern is not found defaultValue is returned
+ * Searches for the pattern pattern in the data. If the pattern is not found defaultValue is returned
*
* @param data
* Data to search in
- * @param p
+ * @param pattern
* Pattern to search for
* @param trim
* Set to true if the group found should be trim'ed
@@ -44,37 +45,38 @@ public final class TextUtils {
* @return defaultValue or the n-th group if the pattern matches (trimmed if wanted)
*/
@SuppressFBWarnings("DM_STRING_CTOR")
- public static String getMatch(@Nullable final String data, final Pattern p, final boolean trim, final int group, final String defaultValue, final boolean last) {
+ public static String getMatch(@Nullable final String data, final Pattern pattern, final boolean trim, final int group, final String defaultValue, final boolean last) {
if (data != null) {
-
- String result = null;
- final Matcher matcher = p.matcher(data);
-
+ final Matcher matcher = pattern.matcher(data);
if (matcher.find()) {
- result = matcher.group(group);
- }
- if (null != result) {
- final Matcher remover = PATTERN_REMOVE_NONPRINTABLE.matcher(result);
- result = remover.replaceAll(" ");
+ String result = matcher.group(group);
+ while (last && matcher.find()) {
+ result = matcher.group(group);
+ }
- return trim ? new String(result).trim() : new String(result);
- // Java copies the whole page String, when matching with regular expressions
- // later this would block the garbage collector, as we only need tiny parts of the page
- // see http://developer.android.com/reference/java/lang/String.html#backing_array
- // Thus the creating of a new String via String constructor is necessary here!!
+ if (result != null) {
+ final Matcher remover = PATTERN_REMOVE_NONPRINTABLE.matcher(result);
+ result = remover.replaceAll(" ");
- // And BTW: You cannot even see that effect in the debugger, but must use a separate memory profiler!
+ // Some versions of Java copy the whole page String, when matching with regular expressions
+ // later this would block the garbage collector, as we only need tiny parts of the page
+ // see http://developer.android.com/reference/java/lang/String.html#backing_array
+ // Thus the creating of a new String via String constructor is voluntary here!!
+ // And BTW: You cannot even see that effect in the debugger, but must use a separate memory profiler!
+ return trim ? new String(result).trim() : new String(result);
+ }
}
}
+
return defaultValue;
}
/**
- * Searches for the pattern p in the data. If the pattern is not found defaultValue is returned
+ * Searches for the pattern pattern in the data. If the pattern is not found defaultValue is returned
*
* @param data
* Data to search in
- * @param p
+ * @param pattern
* Pattern to search for
* @param trim
* Set to true if the group found should be trim'ed
@@ -82,38 +84,33 @@ public final class TextUtils {
* Value to return if the pattern is not found
* @return defaultValue or the first group if the pattern matches (trimmed if wanted)
*/
- public static String getMatch(final String data, final Pattern p, final boolean trim, final String defaultValue) {
- return TextUtils.getMatch(data, p, trim, 1, defaultValue, false);
+ public static String getMatch(final String data, final Pattern pattern, final boolean trim, final String defaultValue) {
+ return TextUtils.getMatch(data, pattern, trim, 1, defaultValue, false);
}
/**
- * Searches for the pattern p in the data. If the pattern is not found defaultValue is returned
+ * Searches for the pattern pattern in the data. If the pattern is not found defaultValue is returned
*
* @param data
* Data to search in
- * @param p
+ * @param pattern
* Pattern to search for
* @param defaultValue
* Value to return if the pattern is not found
* @return defaultValue or the first group if the pattern matches (trimmed)
*/
- public static String getMatch(@Nullable final String data, final Pattern p, final String defaultValue) {
- return TextUtils.getMatch(data, p, true, 1, defaultValue, false);
+ public static String getMatch(@Nullable final String data, final Pattern pattern, final String defaultValue) {
+ return TextUtils.getMatch(data, pattern, true, 1, defaultValue, false);
}
/**
- * Searches for the pattern p in the data.
+ * Searches for the pattern pattern in the data.
*
- * @param data
- * @param p
- * @return true if data contains the pattern p
+ * @return true if data contains the pattern pattern
*/
- public static boolean matches(final String data, final Pattern p) {
- if (data == null) {
- return false;
- }
+ public static boolean matches(final String data, final Pattern pattern) {
// matcher is faster than String.contains() and more flexible - it takes patterns instead of fixed texts
- return p.matcher(data).find();
+ return data != null && pattern.matcher(data).find();
}
@@ -165,8 +162,6 @@ public final class TextUtils {
* Remove all control characters (which are not valid in XML or HTML), as those should not appear in cache texts
* anyway
*
- * @param input
- * @return
*/
public static String removeControlCharacters(final String input) {
final Matcher remover = PATTERN_REMOVE_NONPRINTABLE.matcher(input);
@@ -182,7 +177,19 @@ public final class TextUtils {
*/
public static long checksum(final String input) {
final CRC32 checksum = new CRC32();
- checksum.update(input.getBytes());
+ checksum.update(input.getBytes(CHARSET_UTF8));
return checksum.getValue();
}
+
+ /**
+ * Build a Collator instance appropriate for comparing strings using the default locale while ignoring the casing.
+ *
+ * @return a collator
+ */
+ public static Collator getCollator() {
+ final Collator collator = Collator.getInstance();
+ collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
+ collator.setStrength(Collator.TERTIARY);
+ return collator;
+ }
}
diff --git a/main/src/cgeo/geocaching/utils/UnknownTagsHandler.java b/main/src/cgeo/geocaching/utils/UnknownTagsHandler.java
index 3cb4f16..d518ac8 100644
--- a/main/src/cgeo/geocaching/utils/UnknownTagsHandler.java
+++ b/main/src/cgeo/geocaching/utils/UnknownTagsHandler.java
@@ -22,8 +22,8 @@ public class UnknownTagsHandler implements TagHandler {
private ListType listType = ListType.Unordered;
@Override
- public void handleTag(boolean opening, String tag, Editable output,
- XMLReader xmlReader) {
+ public void handleTag(final boolean opening, final String tag, final Editable output,
+ final XMLReader xmlReader) {
if (tag.equalsIgnoreCase("strike") || tag.equals("s")) {
handleStrike(opening, output);
} else if (tag.equalsIgnoreCase("table")) {
@@ -41,7 +41,7 @@ public class UnknownTagsHandler implements TagHandler {
}
}
- private void handleStrike(boolean opening, Editable output) {
+ private void handleStrike(final boolean opening, final Editable output) {
final int length = output.length();
if (opening) {
strikePos = length;
@@ -61,7 +61,7 @@ public class UnknownTagsHandler implements TagHandler {
problematicDetected = true;
}
- private void handleTd(boolean opening, Editable output) {
+ private void handleTd(final boolean opening, final Editable output) {
// insert bar for each table column, see https://en.wikipedia.org/wiki/Box-drawing_characters
if (opening) {
if (countCells++ > 0) {
@@ -70,7 +70,7 @@ public class UnknownTagsHandler implements TagHandler {
}
}
- private void handleTr(boolean opening, Editable output) {
+ private void handleTr(final boolean opening, final Editable output) {
// insert new line for each table row
if (opening) {
output.append('\n');
@@ -80,7 +80,7 @@ public class UnknownTagsHandler implements TagHandler {
// Ordered lists are handled in a simple manner. They are rendered as Arabic numbers starting at 1
// with no handling for alpha or Roman numbers or arbitrary numbering.
- private void handleOl(boolean opening) {
+ private void handleOl(final boolean opening) {
if (opening) {
listIndex = 1;
listType = ListType.Ordered;
@@ -89,7 +89,7 @@ public class UnknownTagsHandler implements TagHandler {
}
}
- private void handleLi(boolean opening, Editable output) {
+ private void handleLi(final boolean opening, final Editable output) {
if (opening) {
if (listType == ListType.Ordered) {
output.append("\n ").append(String.valueOf(listIndex++)).append(". ");
diff --git a/main/src/cgeo/geocaching/utils/XmlUtils.java b/main/src/cgeo/geocaching/utils/XmlUtils.java
index c36fb53..004fd1b 100644
--- a/main/src/cgeo/geocaching/utils/XmlUtils.java
+++ b/main/src/cgeo/geocaching/utils/XmlUtils.java
@@ -17,7 +17,6 @@ public final class XmlUtils {
* @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)}
* @param tag an XML tag
* @param text some text to insert, or <tt>null</tt> to omit completely this tag
- * @throws IOException
*/
public static void simpleText(final XmlSerializer serializer, final String prefix, final String tag, final String text) throws IOException {
if (text != null) {
@@ -34,7 +33,6 @@ public final class XmlUtils {
* @param prefix an XML prefix, see {@link XmlSerializer#startTag(String, String)} shared by all tags
* @param tagAndText an XML tag, the corresponding text, another XML tag, the corresponding text. <tt>null</tt> texts
* will be omitted along with their respective tag.
- * @throws IOException
*/
public static void multipleTexts(final XmlSerializer serializer, final String prefix, final String... tagAndText) throws IOException {
for (int i = 0; i < tagAndText.length; i += 2) {
diff --git a/main/templates/keys.xml b/main/templates/keys.xml
index d40c0e3..b624b86 100644
--- a/main/templates/keys.xml
+++ b/main/templates/keys.xml
@@ -23,7 +23,7 @@
<string name="oc_ro_okapi_consumer_key" translatable="false">@ocro.okapi.consumer.key@</string>
<string name="oc_ro_okapi_consumer_secret" translatable="false">@ocro.okapi.consumer.secret@</string>
- <!-- Opencaching.og.uk -->
+ <!-- Opencaching.org.uk -->
<string name="oc_uk_okapi_consumer_key" translatable="false">@ocuk.okapi.consumer.key@</string>
<string name="oc_uk_okapi_consumer_secret" translatable="false">@ocuk.okapi.consumer.secret@</string>
</resources>
diff --git a/main/thirdparty/android/support/v4/app/FragmentListActivity.java b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
index a7f8880..9641249 100644
--- a/main/thirdparty/android/support/v4/app/FragmentListActivity.java
+++ b/main/thirdparty/android/support/v4/app/FragmentListActivity.java
@@ -254,12 +254,10 @@ public class FragmentListActivity extends FragmentActivity {
/**
* Provide the cursor for the list view.
*/
- public void setListAdapter(final ListAdapter adapter) {
- synchronized (this) {
- ensureList();
- mAdapter = adapter;
- mList.setAdapter(adapter);
- }
+ public synchronized void setListAdapter(final ListAdapter adapter) {
+ ensureList();
+ mAdapter = adapter;
+ mList.setAdapter(adapter);
}
/**
diff --git a/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java b/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java
index 027ff53..01a1872 100644
--- a/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java
+++ b/main/thirdparty/cgeo/org/kxml2/io/KXmlSerializer.java
@@ -32,6 +32,7 @@ import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Locale;
+@SuppressWarnings("ALL")
public class KXmlSerializer implements XmlSerializer {
// static final String UNDEFINED = ":";
diff --git a/main/thirdparty/com/google/zxing/integration/android/IntentIntegrator.java b/main/thirdparty/com/google/zxing/integration/android/IntentIntegrator.java
index 902de4f..610bee3 100644
--- a/main/thirdparty/com/google/zxing/integration/android/IntentIntegrator.java
+++ b/main/thirdparty/com/google/zxing/integration/android/IntentIntegrator.java
@@ -311,7 +311,7 @@ public class IntentIntegrator {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
try {
activity.startActivity(intent);
- } catch (ActivityNotFoundException anfe) {
+ } catch (ActivityNotFoundException ignored) {
// Hmm, market is not installed
Log.w(TAG, "Google Play is not installed; cannot install " + packageName);
}
diff --git a/main/src/cgeo/geocaching/apps/LocusDataStorageProvider.java b/main/thirdparty/menion/android/locus/LocusDataStorageProvider.java
index 03954f5..b575cb5 100644
--- a/main/src/cgeo/geocaching/apps/LocusDataStorageProvider.java
+++ b/main/thirdparty/menion/android/locus/LocusDataStorageProvider.java
@@ -1,4 +1,4 @@
-package cgeo.geocaching.apps;
+package menion.android.locus;
import menion.android.locus.addon.publiclib.geoData.PointsData;
import menion.android.locus.addon.publiclib.utils.DataCursor;