aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormucek4 <tomaz@gorenc.org>2011-07-11 08:12:48 +0200
committermucek4 <tomaz@gorenc.org>2011-07-11 08:12:48 +0200
commit3a311f2a45a79a19ebc4e2b66f5e92a2f390c04d (patch)
tree6109c451668d4517785e8225c06230b7f02d1414
downloadcgeo-3a311f2a45a79a19ebc4e2b66f5e92a2f390c04d.zip
cgeo-3a311f2a45a79a19ebc4e2b66f5e92a2f390c04d.tar.gz
cgeo-3a311f2a45a79a19ebc4e2b66f5e92a2f390c04d.tar.bz2
First commit
-rw-r--r--AndroidManifest.xml284
-rw-r--r--LICENSE13
-rw-r--r--README14
-rw-r--r--libs/libGoogleAnalytics.jarbin0 -> 29178 bytes
-rw-r--r--libs/mapsforge-map-0.2.3.jarbin0 -> 396702 bytes
-rw-r--r--manifest.mf3
-rw-r--r--res/drawable-hdpi/actionbar_background_tile.pngbin0 -> 34868 bytes
-rw-r--r--res/drawable-hdpi/actionbar_cgeo.pngbin0 -> 3557 bytes
-rw-r--r--res/drawable-hdpi/actionbar_compass.pngbin0 -> 1217 bytes
-rw-r--r--res/drawable-hdpi/actionbar_home.pngbin0 -> 447 bytes
-rw-r--r--res/drawable-hdpi/actionbar_manual.pngbin0 -> 652 bytes
-rw-r--r--res/drawable-hdpi/actionbar_map.pngbin0 -> 1215 bytes
-rw-r--r--res/drawable-hdpi/actionbar_search.pngbin0 -> 641 bytes
-rw-r--r--res/drawable-hdpi/actionbar_share.pngbin0 -> 681 bytes
-rw-r--r--res/drawable-hdpi/cgeo.pngbin0 -> 4551 bytes
-rw-r--r--res/drawable-hdpi/compass_arrow.pngbin0 -> 14541 bytes
-rw-r--r--res/drawable-hdpi/compass_overlay.pngbin0 -> 7973 bytes
-rw-r--r--res/drawable-hdpi/compass_rose.pngbin0 -> 10144 bytes
-rw-r--r--res/drawable-hdpi/compass_underlay.pngbin0 -> 37276 bytes
-rw-r--r--res/drawable-hdpi/hw_menu.pngbin0 -> 947 bytes
-rw-r--r--res/drawable-hdpi/image_not_loaded.pngbin0 -> 85310 bytes
-rw-r--r--res/drawable-hdpi/main_about.pngbin0 -> 4559 bytes
-rw-r--r--res/drawable-hdpi/main_any.pngbin0 -> 9864 bytes
-rw-r--r--res/drawable-hdpi/main_filter.pngbin0 -> 4843 bytes
-rw-r--r--res/drawable-hdpi/main_live.pngbin0 -> 9403 bytes
-rw-r--r--res/drawable-hdpi/main_nearby.pngbin0 -> 9214 bytes
-rw-r--r--res/drawable-hdpi/main_search.pngbin0 -> 9426 bytes
-rw-r--r--res/drawable-hdpi/main_settings.pngbin0 -> 10393 bytes
-rw-r--r--res/drawable-hdpi/main_stored.pngbin0 -> 9291 bytes
-rw-r--r--res/drawable-hdpi/marker.pngbin0 -> 2477 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_ape.pngbin0 -> 3561 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_ape_disabled.pngbin0 -> 3516 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_ape_found.pngbin0 -> 4244 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_ape_own.pngbin0 -> 3984 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_cito.pngbin0 -> 3701 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_cito_disabled.pngbin0 -> 3596 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_cito_found.pngbin0 -> 4312 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_cito_own.pngbin0 -> 4157 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_earth.pngbin0 -> 3965 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_earth_disabled.pngbin0 -> 3864 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_earth_found.pngbin0 -> 4557 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_earth_own.pngbin0 -> 4360 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_event.pngbin0 -> 3670 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_event_disabled.pngbin0 -> 3575 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_event_found.pngbin0 -> 4323 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_event_own.pngbin0 -> 3993 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_gchq.pngbin0 -> 3734 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_gchq_disabled.pngbin0 -> 3615 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_gchq_found.pngbin0 -> 4374 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_gchq_own.pngbin0 -> 4008 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_letterbox.pngbin0 -> 3625 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_letterbox_disabled.pngbin0 -> 3554 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_letterbox_found.pngbin0 -> 4364 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_letterbox_own.pngbin0 -> 4004 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_locationless.pngbin0 -> 3907 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_locationless_disabled.pngbin0 -> 3849 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_locationless_found.pngbin0 -> 4520 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_locationless_own.pngbin0 -> 4305 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mega.pngbin0 -> 3855 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mega_disabled.pngbin0 -> 3773 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mega_found.pngbin0 -> 4521 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mega_own.pngbin0 -> 4114 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_multi.pngbin0 -> 4321 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_multi_disabled.pngbin0 -> 4244 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_multi_found.pngbin0 -> 4862 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_multi_own.pngbin0 -> 4527 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mystery.pngbin0 -> 3950 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mystery_disabled.pngbin0 -> 3877 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mystery_found.pngbin0 -> 4509 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_mystery_own.pngbin0 -> 4172 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_traditional.pngbin0 -> 3734 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_traditional_disabled.pngbin0 -> 3615 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_traditional_found.pngbin0 -> 4374 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_traditional_own.pngbin0 -> 4008 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_virtual.pngbin0 -> 3331 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_virtual_disabled.pngbin0 -> 3287 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_virtual_found.pngbin0 -> 4031 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_virtual_own.pngbin0 -> 3924 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_webcam.pngbin0 -> 3668 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_webcam_disabled.pngbin0 -> 3634 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_webcam_found.pngbin0 -> 4305 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_webcam_own.pngbin0 -> 4026 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_wherigo.pngbin0 -> 3759 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_wherigo_disabled.pngbin0 -> 3699 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_wherigo_found.pngbin0 -> 4401 bytes
-rw-r--r--res/drawable-hdpi/marker_cache_wherigo_own.pngbin0 -> 4170 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_flag.pngbin0 -> 3291 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_pkg.pngbin0 -> 3468 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_puzzle.pngbin0 -> 3622 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_stage.pngbin0 -> 3444 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_trailhead.pngbin0 -> 3361 bytes
-rw-r--r--res/drawable-hdpi/marker_waypoint_waypoint.pngbin0 -> 3685 bytes
-rw-r--r--res/drawable-hdpi/my_location.pngbin0 -> 1138 bytes
-rw-r--r--res/drawable-hdpi/my_location_arrow.pngbin0 -> 542 bytes
-rw-r--r--res/drawable-hdpi/my_location_chevron.pngbin0 -> 2139 bytes
-rw-r--r--res/drawable-hdpi/my_location_off.pngbin0 -> 2164 bytes
-rw-r--r--res/drawable-hdpi/my_location_on.pngbin0 -> 2321 bytes
-rw-r--r--res/drawable-hdpi/star_half.pngbin0 -> 681 bytes
-rw-r--r--res/drawable-hdpi/star_off.pngbin0 -> 482 bytes
-rw-r--r--res/drawable-hdpi/star_on.pngbin0 -> 761 bytes
-rw-r--r--res/drawable-hdpi/trackable_all.pngbin0 -> 1318 bytes
-rw-r--r--res/drawable-hdpi/trackable_coin.pngbin0 -> 864 bytes
-rw-r--r--res/drawable-hdpi/trackable_coins.pngbin0 -> 1032 bytes
-rw-r--r--res/drawable-hdpi/trackable_tb.pngbin0 -> 1103 bytes
-rw-r--r--res/drawable-hdpi/trackable_tbs.pngbin0 -> 1426 bytes
-rw-r--r--res/drawable-hdpi/type_ape.pngbin0 -> 1111 bytes
-rw-r--r--res/drawable-hdpi/type_cito.pngbin0 -> 1324 bytes
-rw-r--r--res/drawable-hdpi/type_earth.pngbin0 -> 1582 bytes
-rw-r--r--res/drawable-hdpi/type_event.pngbin0 -> 1099 bytes
-rw-r--r--res/drawable-hdpi/type_letterbox.pngbin0 -> 1100 bytes
-rw-r--r--res/drawable-hdpi/type_locationless.pngbin0 -> 1593 bytes
-rw-r--r--res/drawable-hdpi/type_mega.pngbin0 -> 1258 bytes
-rw-r--r--res/drawable-hdpi/type_multi.pngbin0 -> 1924 bytes
-rw-r--r--res/drawable-hdpi/type_mystery.pngbin0 -> 1515 bytes
-rw-r--r--res/drawable-hdpi/type_traditional.pngbin0 -> 1248 bytes
-rw-r--r--res/drawable-hdpi/type_virtual.pngbin0 -> 906 bytes
-rw-r--r--res/drawable-hdpi/type_webcam.pngbin0 -> 1292 bytes
-rw-r--r--res/drawable-hdpi/type_wherigo.pngbin0 -> 1359 bytes
-rw-r--r--res/drawable-hdpi/waypoint_flag.pngbin0 -> 736 bytes
-rw-r--r--res/drawable-hdpi/waypoint_pkg.pngbin0 -> 784 bytes
-rw-r--r--res/drawable-hdpi/waypoint_puzzle.pngbin0 -> 907 bytes
-rw-r--r--res/drawable-hdpi/waypoint_stage.pngbin0 -> 854 bytes
-rw-r--r--res/drawable-hdpi/waypoint_trailhead.pngbin0 -> 840 bytes
-rw-r--r--res/drawable-hdpi/waypoint_waypoint.pngbin0 -> 840 bytes
-rw-r--r--res/drawable-ldpi/actionbar_background_tile.pngbin0 -> 7662 bytes
-rw-r--r--res/drawable-ldpi/actionbar_cgeo.pngbin0 -> 1028 bytes
-rw-r--r--res/drawable-ldpi/actionbar_compass.pngbin0 -> 539 bytes
-rw-r--r--res/drawable-ldpi/actionbar_home.pngbin0 -> 521 bytes
-rw-r--r--res/drawable-ldpi/actionbar_manual.pngbin0 -> 501 bytes
-rw-r--r--res/drawable-ldpi/actionbar_map.pngbin0 -> 612 bytes
-rw-r--r--res/drawable-ldpi/actionbar_search.pngbin0 -> 455 bytes
-rw-r--r--res/drawable-ldpi/actionbar_share.pngbin0 -> 495 bytes
-rw-r--r--res/drawable-ldpi/cgeo.pngbin0 -> 3018 bytes
-rw-r--r--res/drawable-ldpi/hw_menu.pngbin0 -> 737 bytes
-rw-r--r--res/drawable-ldpi/main_about.pngbin0 -> 2950 bytes
-rw-r--r--res/drawable-ldpi/main_any.pngbin0 -> 2946 bytes
-rw-r--r--res/drawable-ldpi/main_filter.pngbin0 -> 1564 bytes
-rw-r--r--res/drawable-ldpi/main_live.pngbin0 -> 2837 bytes
-rw-r--r--res/drawable-ldpi/main_nearby.pngbin0 -> 2506 bytes
-rw-r--r--res/drawable-ldpi/main_search.pngbin0 -> 2586 bytes
-rw-r--r--res/drawable-ldpi/main_settings.pngbin0 -> 5982 bytes
-rw-r--r--res/drawable-ldpi/main_stored.pngbin0 -> 2550 bytes
-rw-r--r--res/drawable-ldpi/my_location_chevron.pngbin0 -> 1430 bytes
-rw-r--r--res/drawable-ldpi/my_location_off.pngbin0 -> 1167 bytes
-rw-r--r--res/drawable-ldpi/my_location_on.pngbin0 -> 1199 bytes
-rw-r--r--res/drawable-ldpi/star_half.pngbin0 -> 359 bytes
-rw-r--r--res/drawable-ldpi/star_off.pngbin0 -> 282 bytes
-rw-r--r--res/drawable-ldpi/star_on.pngbin0 -> 409 bytes
-rw-r--r--res/drawable-mdpi/actionbar_background_tile.pngbin0 -> 18719 bytes
-rw-r--r--res/drawable-mdpi/actionbar_cgeo.pngbin0 -> 1865 bytes
-rw-r--r--res/drawable-mdpi/actionbar_compass.pngbin0 -> 870 bytes
-rw-r--r--res/drawable-mdpi/actionbar_home.pngbin0 -> 706 bytes
-rw-r--r--res/drawable-mdpi/actionbar_manual.pngbin0 -> 769 bytes
-rw-r--r--res/drawable-mdpi/actionbar_map.pngbin0 -> 886 bytes
-rw-r--r--res/drawable-mdpi/actionbar_search.pngbin0 -> 668 bytes
-rw-r--r--res/drawable-mdpi/actionbar_share.pngbin0 -> 757 bytes
-rw-r--r--res/drawable-mdpi/cgeo.pngbin0 -> 4942 bytes
-rw-r--r--res/drawable-mdpi/hw_menu.pngbin0 -> 1148 bytes
-rw-r--r--res/drawable-mdpi/main_about.pngbin0 -> 3985 bytes
-rw-r--r--res/drawable-mdpi/main_any.pngbin0 -> 5115 bytes
-rw-r--r--res/drawable-mdpi/main_filter.pngbin0 -> 2634 bytes
-rw-r--r--res/drawable-mdpi/main_live.pngbin0 -> 4799 bytes
-rw-r--r--res/drawable-mdpi/main_nearby.pngbin0 -> 4536 bytes
-rw-r--r--res/drawable-mdpi/main_search.pngbin0 -> 4707 bytes
-rw-r--r--res/drawable-mdpi/main_settings.pngbin0 -> 7358 bytes
-rw-r--r--res/drawable-mdpi/main_stored.pngbin0 -> 4614 bytes
-rw-r--r--res/drawable-mdpi/my_location_chevron.pngbin0 -> 2264 bytes
-rw-r--r--res/drawable-mdpi/my_location_off.pngbin0 -> 1702 bytes
-rw-r--r--res/drawable-mdpi/my_location_on.pngbin0 -> 1782 bytes
-rw-r--r--res/drawable-mdpi/star_half.pngbin0 -> 503 bytes
-rw-r--r--res/drawable-mdpi/star_off.pngbin0 -> 341 bytes
-rw-r--r--res/drawable-mdpi/star_on.pngbin0 -> 549 bytes
-rw-r--r--res/drawable/action_button_dark.xml7
-rw-r--r--res/drawable/action_button_dark_default.xml9
-rw-r--r--res/drawable/action_button_dark_dialog.xml9
-rw-r--r--res/drawable/action_button_dark_off.xml9
-rw-r--r--res/drawable/action_button_dark_pressed.xml9
-rw-r--r--res/drawable/action_button_light.xml7
-rw-r--r--res/drawable/action_button_light_default.xml9
-rw-r--r--res/drawable/action_button_light_dialog.xml9
-rw-r--r--res/drawable/action_button_light_off.xml9
-rw-r--r--res/drawable/action_button_light_pressed.xml9
-rw-r--r--res/drawable/actionbar_background.xml4
-rw-r--r--res/drawable/actionbar_background_tile.pngbin0 -> 18719 bytes
-rw-r--r--res/drawable/actionbar_cgeo.pngbin0 -> 1865 bytes
-rw-r--r--res/drawable/actionbar_compass.pngbin0 -> 870 bytes
-rw-r--r--res/drawable/actionbar_home.pngbin0 -> 706 bytes
-rw-r--r--res/drawable/actionbar_manual.pngbin0 -> 769 bytes
-rw-r--r--res/drawable/actionbar_map.pngbin0 -> 886 bytes
-rw-r--r--res/drawable/actionbar_search.pngbin0 -> 668 bytes
-rw-r--r--res/drawable/actionbar_separator.xml8
-rw-r--r--res/drawable/actionbar_share.pngbin0 -> 757 bytes
-rw-r--r--res/drawable/bcg_dark.xml6
-rw-r--r--res/drawable/bcg_dialog_dark.xml6
-rw-r--r--res/drawable/bcg_dialog_light.xml6
-rw-r--r--res/drawable/bcg_light.xml6
-rw-r--r--res/drawable/cache_dark.xml6
-rw-r--r--res/drawable/cache_dark_pressed.xml6
-rw-r--r--res/drawable/cache_light.xml6
-rw-r--r--res/drawable/cache_light_pressed.xml6
-rw-r--r--res/drawable/carnero_logo.pngbin0 -> 33527 bytes
-rw-r--r--res/drawable/cgeo.pngbin0 -> 4942 bytes
-rw-r--r--res/drawable/client_cgeo.pngbin0 -> 2413 bytes
-rw-r--r--res/drawable/client_handygeocaching.pngbin0 -> 2072 bytes
-rw-r--r--res/drawable/client_precaching.pngbin0 -> 2030 bytes
-rw-r--r--res/drawable/compass_arrow.pngbin0 -> 8608 bytes
-rw-r--r--res/drawable/compass_arrow_mini_black.pngbin0 -> 313 bytes
-rw-r--r--res/drawable/compass_arrow_mini_white.pngbin0 -> 318 bytes
-rw-r--r--res/drawable/compass_overlay.pngbin0 -> 4526 bytes
-rw-r--r--res/drawable/compass_rose.pngbin0 -> 4972 bytes
-rw-r--r--res/drawable/compass_underlay.pngbin0 -> 22480 bytes
-rw-r--r--res/drawable/count_bcg.xml14
-rw-r--r--res/drawable/dialog_button_dark.xml6
-rw-r--r--res/drawable/dialog_button_light.xml6
-rw-r--r--res/drawable/favourite_background_dark.xml11
-rw-r--r--res/drawable/favourite_background_green_dark.xml11
-rw-r--r--res/drawable/favourite_background_green_light.xml11
-rw-r--r--res/drawable/favourite_background_light.xml11
-rw-r--r--res/drawable/favourite_background_orange_dark.xml11
-rw-r--r--res/drawable/favourite_background_orange_light.xml11
-rw-r--r--res/drawable/favourite_background_red_dark.xml11
-rw-r--r--res/drawable/favourite_background_red_light.xml11
-rw-r--r--res/drawable/helper_bcg.xml14
-rw-r--r--res/drawable/helper_bluetoothgps.pngbin0 -> 31768 bytes
-rw-r--r--res/drawable/helper_gpsstatus.pngbin0 -> 59328 bytes
-rw-r--r--res/drawable/helper_locus.pngbin0 -> 43680 bytes
-rw-r--r--res/drawable/helper_manual.pngbin0 -> 50536 bytes
-rw-r--r--res/drawable/hw_menu.pngbin0 -> 1148 bytes
-rw-r--r--res/drawable/icon_bcg.xml11
-rw-r--r--res/drawable/icon_big.pngbin0 -> 4551 bytes
-rw-r--r--res/drawable/image_no_placement.pngbin0 -> 147 bytes
-rw-r--r--res/drawable/image_not_loaded.pngbin0 -> 85310 bytes
-rw-r--r--res/drawable/input_bcg_dark.xml9
-rw-r--r--res/drawable/input_bcg_light.xml9
-rw-r--r--res/drawable/inventory_background_dark.xml11
-rw-r--r--res/drawable/inventory_background_light.xml11
-rw-r--r--res/drawable/list_footer_background.xml4
-rw-r--r--res/drawable/main_about.pngbin0 -> 3985 bytes
-rw-r--r--res/drawable/main_any.pngbin0 -> 5115 bytes
-rw-r--r--res/drawable/main_filter.pngbin0 -> 2634 bytes
-rw-r--r--res/drawable/main_live.pngbin0 -> 4799 bytes
-rw-r--r--res/drawable/main_nearby.pngbin0 -> 4536 bytes
-rw-r--r--res/drawable/main_search.pngbin0 -> 4707 bytes
-rw-r--r--res/drawable/main_settings.pngbin0 -> 7358 bytes
-rw-r--r--res/drawable/main_stored.pngbin0 -> 4614 bytes
-rw-r--r--res/drawable/map_close_dark.xml9
-rw-r--r--res/drawable/map_close_light.xml9
-rw-r--r--res/drawable/map_status_dark.xml9
-rw-r--r--res/drawable/map_status_light.xml9
-rw-r--r--res/drawable/mark_green.xml6
-rw-r--r--res/drawable/mark_orange.xml6
-rw-r--r--res/drawable/mark_red.xml6
-rw-r--r--res/drawable/mark_red_more.xml6
-rw-r--r--res/drawable/marker.pngbin0 -> 1949 bytes
-rw-r--r--res/drawable/marker_cache_ape.pngbin0 -> 2919 bytes
-rw-r--r--res/drawable/marker_cache_ape_disabled.pngbin0 -> 3168 bytes
-rw-r--r--res/drawable/marker_cache_ape_found.pngbin0 -> 3430 bytes
-rw-r--r--res/drawable/marker_cache_ape_own.pngbin0 -> 3180 bytes
-rw-r--r--res/drawable/marker_cache_cito.pngbin0 -> 2932 bytes
-rw-r--r--res/drawable/marker_cache_cito_disabled.pngbin0 -> 3174 bytes
-rw-r--r--res/drawable/marker_cache_cito_found.pngbin0 -> 3375 bytes
-rw-r--r--res/drawable/marker_cache_cito_own.pngbin0 -> 3200 bytes
-rw-r--r--res/drawable/marker_cache_earth.pngbin0 -> 3015 bytes
-rw-r--r--res/drawable/marker_cache_earth_disabled.pngbin0 -> 3255 bytes
-rw-r--r--res/drawable/marker_cache_earth_found.pngbin0 -> 3429 bytes
-rw-r--r--res/drawable/marker_cache_earth_own.pngbin0 -> 3235 bytes
-rw-r--r--res/drawable/marker_cache_event.pngbin0 -> 2784 bytes
-rw-r--r--res/drawable/marker_cache_event_disabled.pngbin0 -> 3060 bytes
-rw-r--r--res/drawable/marker_cache_event_found.pngbin0 -> 3288 bytes
-rw-r--r--res/drawable/marker_cache_event_own.pngbin0 -> 3032 bytes
-rw-r--r--res/drawable/marker_cache_gchq.pngbin0 -> 2965 bytes
-rw-r--r--res/drawable/marker_cache_gchq_disabled.pngbin0 -> 3180 bytes
-rw-r--r--res/drawable/marker_cache_gchq_found.pngbin0 -> 3377 bytes
-rw-r--r--res/drawable/marker_cache_gchq_own.pngbin0 -> 3172 bytes
-rw-r--r--res/drawable/marker_cache_letterbox.pngbin0 -> 2610 bytes
-rw-r--r--res/drawable/marker_cache_letterbox_disabled.pngbin0 -> 2937 bytes
-rw-r--r--res/drawable/marker_cache_letterbox_found.pngbin0 -> 3139 bytes
-rw-r--r--res/drawable/marker_cache_letterbox_own.pngbin0 -> 2938 bytes
-rw-r--r--res/drawable/marker_cache_locationless.pngbin0 -> 2978 bytes
-rw-r--r--res/drawable/marker_cache_locationless_disabled.pngbin0 -> 3242 bytes
-rw-r--r--res/drawable/marker_cache_locationless_found.pngbin0 -> 3387 bytes
-rw-r--r--res/drawable/marker_cache_locationless_own.pngbin0 -> 3251 bytes
-rw-r--r--res/drawable/marker_cache_mega.pngbin0 -> 2852 bytes
-rw-r--r--res/drawable/marker_cache_mega_disabled.pngbin0 -> 3093 bytes
-rw-r--r--res/drawable/marker_cache_mega_found.pngbin0 -> 3332 bytes
-rw-r--r--res/drawable/marker_cache_mega_own.pngbin0 -> 3084 bytes
-rw-r--r--res/drawable/marker_cache_multi.pngbin0 -> 3224 bytes
-rw-r--r--res/drawable/marker_cache_multi_disabled.pngbin0 -> 3432 bytes
-rw-r--r--res/drawable/marker_cache_multi_found.pngbin0 -> 3581 bytes
-rw-r--r--res/drawable/marker_cache_multi_own.pngbin0 -> 3353 bytes
-rw-r--r--res/drawable/marker_cache_mystery.pngbin0 -> 3013 bytes
-rw-r--r--res/drawable/marker_cache_mystery_disabled.pngbin0 -> 3234 bytes
-rw-r--r--res/drawable/marker_cache_mystery_found.pngbin0 -> 3425 bytes
-rw-r--r--res/drawable/marker_cache_mystery_own.pngbin0 -> 3193 bytes
-rw-r--r--res/drawable/marker_cache_traditional.pngbin0 -> 2965 bytes
-rw-r--r--res/drawable/marker_cache_traditional_disabled.pngbin0 -> 3180 bytes
-rw-r--r--res/drawable/marker_cache_traditional_found.pngbin0 -> 3377 bytes
-rw-r--r--res/drawable/marker_cache_traditional_own.pngbin0 -> 3172 bytes
-rw-r--r--res/drawable/marker_cache_virtual.pngbin0 -> 2593 bytes
-rw-r--r--res/drawable/marker_cache_virtual_disabled.pngbin0 -> 2959 bytes
-rw-r--r--res/drawable/marker_cache_virtual_found.pngbin0 -> 3077 bytes
-rw-r--r--res/drawable/marker_cache_virtual_own.pngbin0 -> 2970 bytes
-rw-r--r--res/drawable/marker_cache_webcam.pngbin0 -> 2768 bytes
-rw-r--r--res/drawable/marker_cache_webcam_disabled.pngbin0 -> 3058 bytes
-rw-r--r--res/drawable/marker_cache_webcam_found.pngbin0 -> 3210 bytes
-rw-r--r--res/drawable/marker_cache_webcam_own.pngbin0 -> 3036 bytes
-rw-r--r--res/drawable/marker_cache_wherigo.pngbin0 -> 2906 bytes
-rw-r--r--res/drawable/marker_cache_wherigo_disabled.pngbin0 -> 3143 bytes
-rw-r--r--res/drawable/marker_cache_wherigo_found.pngbin0 -> 3356 bytes
-rw-r--r--res/drawable/marker_cache_wherigo_own.pngbin0 -> 3177 bytes
-rw-r--r--res/drawable/marker_waypoint_flag.pngbin0 -> 2543 bytes
-rw-r--r--res/drawable/marker_waypoint_pkg.pngbin0 -> 2869 bytes
-rw-r--r--res/drawable/marker_waypoint_puzzle.pngbin0 -> 2871 bytes
-rw-r--r--res/drawable/marker_waypoint_stage.pngbin0 -> 2676 bytes
-rw-r--r--res/drawable/marker_waypoint_trailhead.pngbin0 -> 2658 bytes
-rw-r--r--res/drawable/marker_waypoint_waypoint.pngbin0 -> 2798 bytes
-rw-r--r--res/drawable/my_location.pngbin0 -> 1138 bytes
-rw-r--r--res/drawable/my_location_arrow.pngbin0 -> 542 bytes
-rw-r--r--res/drawable/my_location_chevron.pngbin0 -> 2264 bytes
-rw-r--r--res/drawable/my_location_off.pngbin0 -> 1702 bytes
-rw-r--r--res/drawable/my_location_on.pngbin0 -> 1782 bytes
-rw-r--r--res/drawable/separator_dark.xml6
-rw-r--r--res/drawable/separator_light.xml6
-rw-r--r--res/drawable/star_half.pngbin0 -> 503 bytes
-rw-r--r--res/drawable/star_off.pngbin0 -> 341 bytes
-rw-r--r--res/drawable/star_on.pngbin0 -> 549 bytes
-rw-r--r--res/drawable/trackable_all.pngbin0 -> 748 bytes
-rw-r--r--res/drawable/type_ape.pngbin0 -> 697 bytes
-rw-r--r--res/drawable/type_cito.pngbin0 -> 781 bytes
-rw-r--r--res/drawable/type_earth.pngbin0 -> 872 bytes
-rw-r--r--res/drawable/type_event.pngbin0 -> 654 bytes
-rw-r--r--res/drawable/type_hq.pngbin0 -> 621 bytes
-rw-r--r--res/drawable/type_letterbox.pngbin0 -> 692 bytes
-rw-r--r--res/drawable/type_locationless.pngbin0 -> 881 bytes
-rw-r--r--res/drawable/type_mega.pngbin0 -> 736 bytes
-rw-r--r--res/drawable/type_multi.pngbin0 -> 1073 bytes
-rw-r--r--res/drawable/type_mystery.pngbin0 -> 899 bytes
-rw-r--r--res/drawable/type_traditional.pngbin0 -> 756 bytes
-rw-r--r--res/drawable/type_virtual.pngbin0 -> 580 bytes
-rw-r--r--res/drawable/type_webcam.pngbin0 -> 769 bytes
-rw-r--r--res/drawable/type_wherigo.pngbin0 -> 807 bytes
-rw-r--r--res/drawable/user_location.pngbin0 -> 553 bytes
-rw-r--r--res/drawable/user_location_active.pngbin0 -> 574 bytes
-rw-r--r--res/drawable/waypoint_flag.pngbin0 -> 462 bytes
-rw-r--r--res/drawable/waypoint_pkg.pngbin0 -> 487 bytes
-rw-r--r--res/drawable/waypoint_puzzle.pngbin0 -> 560 bytes
-rw-r--r--res/drawable/waypoint_stage.pngbin0 -> 554 bytes
-rw-r--r--res/drawable/waypoint_trailhead.pngbin0 -> 560 bytes
-rw-r--r--res/drawable/waypoint_waypoint.pngbin0 -> 550 bytes
-rw-r--r--res/layout/about.xml218
-rw-r--r--res/layout/address_button.xml11
-rw-r--r--res/layout/addresses.xml24
-rw-r--r--res/layout/auth.xml86
-rw-r--r--res/layout/cache.xml165
-rw-r--r--res/layout/cache_item.xml34
-rw-r--r--res/layout/cache_layout.xml45
-rw-r--r--res/layout/caches.xml45
-rw-r--r--res/layout/caches_footer.xml16
-rw-r--r--res/layout/date.xml9
-rw-r--r--res/layout/detail.xml231
-rw-r--r--res/layout/googlemap.xml52
-rw-r--r--res/layout/gpx.xml22
-rw-r--r--res/layout/gpx_item.xml33
-rw-r--r--res/layout/helpers.xml185
-rw-r--r--res/layout/image_item.xml7
-rw-r--r--res/layout/init.xml600
-rw-r--r--res/layout/list_create_dialog.xml8
-rw-r--r--res/layout/log_item.xml104
-rw-r--r--res/layout/main.xml174
-rw-r--r--res/layout/map_static.xml24
-rw-r--r--res/layout/map_static_item.xml9
-rw-r--r--res/layout/mfmap.xml51
-rw-r--r--res/layout/navigate.xml90
-rw-r--r--res/layout/point.xml53
-rw-r--r--res/layout/popup.xml74
-rw-r--r--res/layout/recaptcha_dialog.xml28
-rw-r--r--res/layout/search.xml131
-rw-r--r--res/layout/spoiler_item.xml20
-rw-r--r--res/layout/spoilers.xml24
-rw-r--r--res/layout/star.xml9
-rw-r--r--res/layout/touch.xml89
-rw-r--r--res/layout/trackable_button.xml8
-rw-r--r--res/layout/trackable_detail.xml107
-rw-r--r--res/layout/trackable_icon.xml8
-rw-r--r--res/layout/trackable_image.xml9
-rw-r--r--res/layout/trackable_logitem.xml77
-rw-r--r--res/layout/trackables.xml27
-rw-r--r--res/layout/visit.xml142
-rw-r--r--res/layout/visit_trackable.xml53
-rw-r--r--res/layout/waypoint.xml95
-rw-r--r--res/layout/waypoint_item.xml57
-rw-r--r--res/layout/waypoint_new.xml56
-rw-r--r--res/values-cs/strings.xml497
-rw-r--r--res/values-da/strings.xml331
-rw-r--r--res/values-de/strings.xml747
-rw-r--r--res/values-es/strings.xml606
-rw-r--r--res/values-fr/strings.xml266
-rw-r--r--res/values-hu/strings.xml331
-rw-r--r--res/values-ja/strings.xml742
-rw-r--r--res/values-nb/strings.xml475
-rw-r--r--res/values-nl/strings.xml502
-rw-r--r--res/values-pl/strings.xml598
-rw-r--r--res/values-pt/strings.xml470
-rw-r--r--res/values-sk/strings.xml502
-rw-r--r--res/values-sv/strings.xml612
-rw-r--r--res/values/attrs.xml33
-rw-r--r--res/values/colors.xml27
-rw-r--r--res/values/dimens.xml6
-rw-r--r--res/values/ids.xml5
-rw-r--r--res/values/strings.xml957
-rw-r--r--res/values/styles.xml283
-rw-r--r--res/values/themes.xml109
-rw-r--r--res/xml/searchable.xml8
-rw-r--r--src/cgeo/geocaching/cg8.java17
-rw-r--r--src/cgeo/geocaching/cg8wrap.java27
-rw-r--r--src/cgeo/geocaching/cgAddressImg.java60
-rw-r--r--src/cgeo/geocaching/cgBase.java5828
-rw-r--r--src/cgeo/geocaching/cgCache.java218
-rw-r--r--src/cgeo/geocaching/cgCacheDifficultyComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheDistanceComparator.java51
-rw-r--r--src/cgeo/geocaching/cgCacheGeocodeComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheInventoryComparator.java36
-rw-r--r--src/cgeo/geocaching/cgCacheListAdapter.java909
-rw-r--r--src/cgeo/geocaching/cgCacheNameComparator.java20
-rw-r--r--src/cgeo/geocaching/cgCachePopularityComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheRatingComparator.java36
-rw-r--r--src/cgeo/geocaching/cgCacheSizeComparator.java47
-rw-r--r--src/cgeo/geocaching/cgCacheTerrainComparator.java26
-rw-r--r--src/cgeo/geocaching/cgCacheView.java29
-rw-r--r--src/cgeo/geocaching/cgCacheVisitComparator.java27
-rw-r--r--src/cgeo/geocaching/cgCacheVoteComparator.java38
-rw-r--r--src/cgeo/geocaching/cgCacheWrap.java12
-rw-r--r--src/cgeo/geocaching/cgCompass.java322
-rw-r--r--src/cgeo/geocaching/cgCompassMini.java176
-rw-r--r--src/cgeo/geocaching/cgCoord.java46
-rw-r--r--src/cgeo/geocaching/cgData.java3046
-rw-r--r--src/cgeo/geocaching/cgDirection.java102
-rw-r--r--src/cgeo/geocaching/cgDirectionImg.java96
-rw-r--r--src/cgeo/geocaching/cgDistanceView.java45
-rw-r--r--src/cgeo/geocaching/cgGPXListAdapter.java75
-rw-r--r--src/cgeo/geocaching/cgGPXParser.java547
-rw-r--r--src/cgeo/geocaching/cgGPXView.java9
-rw-r--r--src/cgeo/geocaching/cgGeo.java445
-rw-r--r--src/cgeo/geocaching/cgHtmlImg.java286
-rw-r--r--src/cgeo/geocaching/cgList.java20
-rw-r--r--src/cgeo/geocaching/cgLog.java12
-rw-r--r--src/cgeo/geocaching/cgLogForm.java10
-rw-r--r--src/cgeo/geocaching/cgMapImg.java114
-rw-r--r--src/cgeo/geocaching/cgOAuth.java53
-rw-r--r--src/cgeo/geocaching/cgRating.java7
-rw-r--r--src/cgeo/geocaching/cgResponse.java40
-rw-r--r--src/cgeo/geocaching/cgSearch.java39
-rw-r--r--src/cgeo/geocaching/cgSearchHandler.java104
-rw-r--r--src/cgeo/geocaching/cgSearchThread.java46
-rw-r--r--src/cgeo/geocaching/cgSettings.java513
-rw-r--r--src/cgeo/geocaching/cgSpoiler.java7
-rw-r--r--src/cgeo/geocaching/cgTrackable.java35
-rw-r--r--src/cgeo/geocaching/cgTrackableLog.java9
-rw-r--r--src/cgeo/geocaching/cgUpdateDir.java7
-rw-r--r--src/cgeo/geocaching/cgUpdateLoc.java7
-rw-r--r--src/cgeo/geocaching/cgUser.java12
-rw-r--r--src/cgeo/geocaching/cgWarning.java52
-rw-r--r--src/cgeo/geocaching/cgWaypoint.java16
-rw-r--r--src/cgeo/geocaching/cgeo.java669
-rw-r--r--src/cgeo/geocaching/cgeoabout.java110
-rw-r--r--src/cgeo/geocaching/cgeoaddresses.java201
-rw-r--r--src/cgeo/geocaching/cgeoadvsearch.java552
-rw-r--r--src/cgeo/geocaching/cgeoapplication.java828
-rw-r--r--src/cgeo/geocaching/cgeoauth.java413
-rw-r--r--src/cgeo/geocaching/cgeocaches.java2193
-rw-r--r--src/cgeo/geocaching/cgeodate.java62
-rw-r--r--src/cgeo/geocaching/cgeodetail.java1902
-rw-r--r--src/cgeo/geocaching/cgeogpxes.java292
-rw-r--r--src/cgeo/geocaching/cgeohelpers.java107
-rw-r--r--src/cgeo/geocaching/cgeoinit.java965
-rw-r--r--src/cgeo/geocaching/cgeonavigate.java503
-rw-r--r--src/cgeo/geocaching/cgeopoint.java535
-rw-r--r--src/cgeo/geocaching/cgeopopup.java834
-rw-r--r--src/cgeo/geocaching/cgeosmaps.java172
-rw-r--r--src/cgeo/geocaching/cgeospoilers.java231
-rw-r--r--src/cgeo/geocaching/cgeotouch.java487
-rw-r--r--src/cgeo/geocaching/cgeotrackable.java671
-rw-r--r--src/cgeo/geocaching/cgeotrackables.java186
-rw-r--r--src/cgeo/geocaching/cgeovisit.java912
-rw-r--r--src/cgeo/geocaching/cgeowaypoint.java465
-rw-r--r--src/cgeo/geocaching/cgeowaypointadd.java434
-rw-r--r--src/cgeo/geocaching/filter/cgFilter.java20
-rw-r--r--src/cgeo/geocaching/filter/cgFilterBySize.java17
-rw-r--r--src/cgeo/geocaching/filter/cgFilterByTrackables.java12
-rw-r--r--src/cgeo/geocaching/filter/cgFilterByType.java17
-rw-r--r--src/cgeo/geocaching/googlemaps/googleCacheOverlay.java101
-rw-r--r--src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java28
-rw-r--r--src/cgeo/geocaching/googlemaps/googleGeoPoint.java13
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapActivity.java101
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapController.java37
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapFactory.java54
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapProjection.java28
-rw-r--r--src/cgeo/geocaching/googlemaps/googleMapView.java118
-rw-r--r--src/cgeo/geocaching/googlemaps/googleOverlay.java26
-rw-r--r--src/cgeo/geocaching/googlemaps/googleUsersOverlay.java94
-rw-r--r--src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java43
-rw-r--r--src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java57
-rw-r--r--src/cgeo/geocaching/mapcommon/MapBase.java64
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java198
-rw-r--r--src/cgeo/geocaching/mapcommon/cgMapOverlay.java322
-rw-r--r--src/cgeo/geocaching/mapcommon/cgOverlayScale.java140
-rw-r--r--src/cgeo/geocaching/mapcommon/cgUsersOverlay.java185
-rw-r--r--src/cgeo/geocaching/mapcommon/cgeomap.java1686
-rw-r--r--src/cgeo/geocaching/mapinterfaces/ActivityImpl.java33
-rw-r--r--src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java17
-rw-r--r--src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java15
-rw-r--r--src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java33
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java19
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapFactory.java30
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java17
-rw-r--r--src/cgeo/geocaching/mapinterfaces/MapViewImpl.java64
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayBase.java19
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayImpl.java11
-rw-r--r--src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java18
-rw-r--r--src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java14
-rw-r--r--src/cgeo/geocaching/mapsforge/mfCacheOverlay.java99
-rw-r--r--src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java35
-rw-r--r--src/cgeo/geocaching/mapsforge/mfGeoPoint.java12
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapActivity.java96
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapController.java43
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapFactory.java54
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapProjection.java28
-rw-r--r--src/cgeo/geocaching/mapsforge/mfMapView.java159
-rw-r--r--src/cgeo/geocaching/mapsforge/mfOverlay.java26
-rw-r--r--src/cgeo/geocaching/mapsforge/mfUsersOverlay.java98
-rw-r--r--src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java43
-rw-r--r--src/gnu/android/app/appmanualclient/AppManualReaderClient.java377
532 files changed, 44334 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644
index 0000000..928a0b8
--- /dev/null
+++ b/AndroidManifest.xml
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="2"
+ android:versionName="2.26 RC1a"
+ package="cgeo.geocaching"
+ name="c:geo"
+ android:installLocation="auto" >
+ <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.READ_CALENDAR"/>
+ <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
+ <supports-screens
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true"
+ android:anyDensity="true" />
+ <application
+ android:name=".cgeoapplication"
+ android:theme="@style/cgeo"
+ android:label="@string/app_name"
+ android:icon="@drawable/cgeo" >
+ <uses-library android:name="com.google.android.maps" />
+ <meta-data
+ android:name="android.app.default_searchable"
+ android:value=".cgeoadvsearch" />
+ <activity
+ android:name=".cgeo"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeoadvsearch"
+ android:label="@string/app_name"
+ android:launchMode="singleTop"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="android.intent.action.SEARCH"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOADVSEARCH"/>
+ </intent-filter>
+ <meta-data
+ android:name="android.app.searchable"
+ android:resource="@xml/searchable" />
+ </activity>
+ <activity
+ android:name=".cgeopopup"
+ android:label="@string/app_name"
+ android:theme="@style/cgeo_transparent"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOPOPUP"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeoabout"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOABOUT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeohelpers"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOHELPERS"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeoauth"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOAUTH"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeowaypointadd"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOWAYPOINTADD"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeowaypoint"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOWAYPOINT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeopoint"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOPOINT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeoaddresses"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOADDRESSES"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeoinit"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOINIT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeocaches"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOCACHES"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="cgeo.geocaching.googlemaps.googleMapActivity"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOMAP"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="cgeo.geocaching.mapsforge.mfMapActivity"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOMAP"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeosmaps"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOSMAPS"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeologs"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOLOGS"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeovisit"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOVISIT"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeotouch"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOTOUCH"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeospoilers"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOSPOILERS"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeotrackables"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOTRACKABLES"/>
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeodetail"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEODETAIL"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="wikitudeapi.arcallback" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="coord.info" android:pathPrefix="/GC" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="geocaching.com" android:pathPrefix="/seek/cache_details.aspx" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.geocaching.com" android:pathPrefix="/seek/cache_details.aspx" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeotrackable"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOTRACKABLE"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="coord.info" android:pathPrefix="/TB" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="geocaching.com" android:pathPrefix="/track/details.aspx" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" android:host="www.geocaching.com" android:pathPrefix="/track/details.aspx" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeonavigate"
+ android:label="@string/app_name_compass"
+ android:screenOrientation="nosensor" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEONAVIGATE" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".cgeogpxes"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation" >
+ <intent-filter>
+ <action android:name="cgeo.geocaching.CGEOGPXES"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c43dd4b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2011
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License. \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..28b9703
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+c:geo is simple yet powerful unofficial geocaching client for Android devices.
+In contrast with other similar applications, c:geo doesn't require web browser
+nor exports. You can just go geocaching with your phone and without any
+home preparation or worries. Of course, you can go without paying - it's free.
+
+In July 2011 original author Radovan Paska aka carnero put the code as opensource
+licence.
+
+- original author: Radovan Paska aka carnero
+- questions: support@cgeo.org
+- website: http://www.cgeo.org/
+- support: support@cgeo.org
+- twitter: http://twitter.com/android_gc
+- facebook: http://www.facebook.com/android.geocaching \ No newline at end of file
diff --git a/libs/libGoogleAnalytics.jar b/libs/libGoogleAnalytics.jar
new file mode 100644
index 0000000..d3f7193
--- /dev/null
+++ b/libs/libGoogleAnalytics.jar
Binary files differ
diff --git a/libs/mapsforge-map-0.2.3.jar b/libs/mapsforge-map-0.2.3.jar
new file mode 100644
index 0000000..b744efc
--- /dev/null
+++ b/libs/mapsforge-map-0.2.3.jar
Binary files differ
diff --git a/manifest.mf b/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/res/drawable-hdpi/actionbar_background_tile.png b/res/drawable-hdpi/actionbar_background_tile.png
new file mode 100644
index 0000000..d30c591
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_background_tile.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_cgeo.png b/res/drawable-hdpi/actionbar_cgeo.png
new file mode 100644
index 0000000..5e27b58
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_cgeo.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_compass.png b/res/drawable-hdpi/actionbar_compass.png
new file mode 100644
index 0000000..7cd939e
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_compass.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_home.png b/res/drawable-hdpi/actionbar_home.png
new file mode 100644
index 0000000..a5a1a8c
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_home.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_manual.png b/res/drawable-hdpi/actionbar_manual.png
new file mode 100644
index 0000000..0b0c93c
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_manual.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_map.png b/res/drawable-hdpi/actionbar_map.png
new file mode 100644
index 0000000..0daa215
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_map.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_search.png b/res/drawable-hdpi/actionbar_search.png
new file mode 100644
index 0000000..59de344
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_search.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_share.png b/res/drawable-hdpi/actionbar_share.png
new file mode 100644
index 0000000..e748c85
--- /dev/null
+++ b/res/drawable-hdpi/actionbar_share.png
Binary files differ
diff --git a/res/drawable-hdpi/cgeo.png b/res/drawable-hdpi/cgeo.png
new file mode 100644
index 0000000..a7d0d1b
--- /dev/null
+++ b/res/drawable-hdpi/cgeo.png
Binary files differ
diff --git a/res/drawable-hdpi/compass_arrow.png b/res/drawable-hdpi/compass_arrow.png
new file mode 100644
index 0000000..d005e6e
--- /dev/null
+++ b/res/drawable-hdpi/compass_arrow.png
Binary files differ
diff --git a/res/drawable-hdpi/compass_overlay.png b/res/drawable-hdpi/compass_overlay.png
new file mode 100644
index 0000000..d471459
--- /dev/null
+++ b/res/drawable-hdpi/compass_overlay.png
Binary files differ
diff --git a/res/drawable-hdpi/compass_rose.png b/res/drawable-hdpi/compass_rose.png
new file mode 100644
index 0000000..1014883
--- /dev/null
+++ b/res/drawable-hdpi/compass_rose.png
Binary files differ
diff --git a/res/drawable-hdpi/compass_underlay.png b/res/drawable-hdpi/compass_underlay.png
new file mode 100644
index 0000000..abd6a6d
--- /dev/null
+++ b/res/drawable-hdpi/compass_underlay.png
Binary files differ
diff --git a/res/drawable-hdpi/hw_menu.png b/res/drawable-hdpi/hw_menu.png
new file mode 100644
index 0000000..182788a
--- /dev/null
+++ b/res/drawable-hdpi/hw_menu.png
Binary files differ
diff --git a/res/drawable-hdpi/image_not_loaded.png b/res/drawable-hdpi/image_not_loaded.png
new file mode 100644
index 0000000..f37377c
--- /dev/null
+++ b/res/drawable-hdpi/image_not_loaded.png
Binary files differ
diff --git a/res/drawable-hdpi/main_about.png b/res/drawable-hdpi/main_about.png
new file mode 100644
index 0000000..a3c75cb
--- /dev/null
+++ b/res/drawable-hdpi/main_about.png
Binary files differ
diff --git a/res/drawable-hdpi/main_any.png b/res/drawable-hdpi/main_any.png
new file mode 100644
index 0000000..1ddce91
--- /dev/null
+++ b/res/drawable-hdpi/main_any.png
Binary files differ
diff --git a/res/drawable-hdpi/main_filter.png b/res/drawable-hdpi/main_filter.png
new file mode 100644
index 0000000..c5b2548
--- /dev/null
+++ b/res/drawable-hdpi/main_filter.png
Binary files differ
diff --git a/res/drawable-hdpi/main_live.png b/res/drawable-hdpi/main_live.png
new file mode 100644
index 0000000..ddaac04
--- /dev/null
+++ b/res/drawable-hdpi/main_live.png
Binary files differ
diff --git a/res/drawable-hdpi/main_nearby.png b/res/drawable-hdpi/main_nearby.png
new file mode 100644
index 0000000..e75a338
--- /dev/null
+++ b/res/drawable-hdpi/main_nearby.png
Binary files differ
diff --git a/res/drawable-hdpi/main_search.png b/res/drawable-hdpi/main_search.png
new file mode 100644
index 0000000..bc9994a
--- /dev/null
+++ b/res/drawable-hdpi/main_search.png
Binary files differ
diff --git a/res/drawable-hdpi/main_settings.png b/res/drawable-hdpi/main_settings.png
new file mode 100644
index 0000000..02b564d
--- /dev/null
+++ b/res/drawable-hdpi/main_settings.png
Binary files differ
diff --git a/res/drawable-hdpi/main_stored.png b/res/drawable-hdpi/main_stored.png
new file mode 100644
index 0000000..57d3683
--- /dev/null
+++ b/res/drawable-hdpi/main_stored.png
Binary files differ
diff --git a/res/drawable-hdpi/marker.png b/res/drawable-hdpi/marker.png
new file mode 100644
index 0000000..3be6c58
--- /dev/null
+++ b/res/drawable-hdpi/marker.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_ape.png b/res/drawable-hdpi/marker_cache_ape.png
new file mode 100644
index 0000000..ea23ab5
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_ape.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_ape_disabled.png b/res/drawable-hdpi/marker_cache_ape_disabled.png
new file mode 100644
index 0000000..bec7d35
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_ape_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_ape_found.png b/res/drawable-hdpi/marker_cache_ape_found.png
new file mode 100644
index 0000000..88a3c60
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_ape_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_ape_own.png b/res/drawable-hdpi/marker_cache_ape_own.png
new file mode 100644
index 0000000..789dfce
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_ape_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_cito.png b/res/drawable-hdpi/marker_cache_cito.png
new file mode 100644
index 0000000..7316474
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_cito.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_cito_disabled.png b/res/drawable-hdpi/marker_cache_cito_disabled.png
new file mode 100644
index 0000000..46ec516
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_cito_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_cito_found.png b/res/drawable-hdpi/marker_cache_cito_found.png
new file mode 100644
index 0000000..52cab85
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_cito_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_cito_own.png b/res/drawable-hdpi/marker_cache_cito_own.png
new file mode 100644
index 0000000..a5ccea7
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_cito_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_earth.png b/res/drawable-hdpi/marker_cache_earth.png
new file mode 100644
index 0000000..67fe6a8
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_earth.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_earth_disabled.png b/res/drawable-hdpi/marker_cache_earth_disabled.png
new file mode 100644
index 0000000..314abd9
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_earth_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_earth_found.png b/res/drawable-hdpi/marker_cache_earth_found.png
new file mode 100644
index 0000000..ed35305
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_earth_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_earth_own.png b/res/drawable-hdpi/marker_cache_earth_own.png
new file mode 100644
index 0000000..ff40ae7
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_earth_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_event.png b/res/drawable-hdpi/marker_cache_event.png
new file mode 100644
index 0000000..ca4a992
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_event.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_event_disabled.png b/res/drawable-hdpi/marker_cache_event_disabled.png
new file mode 100644
index 0000000..07009a2
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_event_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_event_found.png b/res/drawable-hdpi/marker_cache_event_found.png
new file mode 100644
index 0000000..8a353f7
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_event_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_event_own.png b/res/drawable-hdpi/marker_cache_event_own.png
new file mode 100644
index 0000000..5eac369
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_event_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_gchq.png b/res/drawable-hdpi/marker_cache_gchq.png
new file mode 100644
index 0000000..8a325af
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_gchq.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_gchq_disabled.png b/res/drawable-hdpi/marker_cache_gchq_disabled.png
new file mode 100644
index 0000000..2758ef1
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_gchq_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_gchq_found.png b/res/drawable-hdpi/marker_cache_gchq_found.png
new file mode 100644
index 0000000..5fb2f14
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_gchq_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_gchq_own.png b/res/drawable-hdpi/marker_cache_gchq_own.png
new file mode 100644
index 0000000..bedc59e
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_gchq_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_letterbox.png b/res/drawable-hdpi/marker_cache_letterbox.png
new file mode 100644
index 0000000..ec15411
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_letterbox.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_letterbox_disabled.png b/res/drawable-hdpi/marker_cache_letterbox_disabled.png
new file mode 100644
index 0000000..8637e64
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_letterbox_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_letterbox_found.png b/res/drawable-hdpi/marker_cache_letterbox_found.png
new file mode 100644
index 0000000..ef34447
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_letterbox_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_letterbox_own.png b/res/drawable-hdpi/marker_cache_letterbox_own.png
new file mode 100644
index 0000000..8523796
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_letterbox_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_locationless.png b/res/drawable-hdpi/marker_cache_locationless.png
new file mode 100644
index 0000000..c8daf38
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_locationless.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_locationless_disabled.png b/res/drawable-hdpi/marker_cache_locationless_disabled.png
new file mode 100644
index 0000000..9f37db5
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_locationless_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_locationless_found.png b/res/drawable-hdpi/marker_cache_locationless_found.png
new file mode 100644
index 0000000..948b266
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_locationless_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_locationless_own.png b/res/drawable-hdpi/marker_cache_locationless_own.png
new file mode 100644
index 0000000..82b24ed
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_locationless_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mega.png b/res/drawable-hdpi/marker_cache_mega.png
new file mode 100644
index 0000000..d30387d
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mega.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mega_disabled.png b/res/drawable-hdpi/marker_cache_mega_disabled.png
new file mode 100644
index 0000000..6f0930e
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mega_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mega_found.png b/res/drawable-hdpi/marker_cache_mega_found.png
new file mode 100644
index 0000000..607a74b
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mega_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mega_own.png b/res/drawable-hdpi/marker_cache_mega_own.png
new file mode 100644
index 0000000..e90a31e
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mega_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_multi.png b/res/drawable-hdpi/marker_cache_multi.png
new file mode 100644
index 0000000..78fa60c
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_multi.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_multi_disabled.png b/res/drawable-hdpi/marker_cache_multi_disabled.png
new file mode 100644
index 0000000..e84b8b6
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_multi_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_multi_found.png b/res/drawable-hdpi/marker_cache_multi_found.png
new file mode 100644
index 0000000..a3b42ae
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_multi_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_multi_own.png b/res/drawable-hdpi/marker_cache_multi_own.png
new file mode 100644
index 0000000..de70369
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_multi_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mystery.png b/res/drawable-hdpi/marker_cache_mystery.png
new file mode 100644
index 0000000..0ac038b
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mystery.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mystery_disabled.png b/res/drawable-hdpi/marker_cache_mystery_disabled.png
new file mode 100644
index 0000000..08553cf
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mystery_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mystery_found.png b/res/drawable-hdpi/marker_cache_mystery_found.png
new file mode 100644
index 0000000..ffd852e
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mystery_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_mystery_own.png b/res/drawable-hdpi/marker_cache_mystery_own.png
new file mode 100644
index 0000000..7e51d30
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_mystery_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_traditional.png b/res/drawable-hdpi/marker_cache_traditional.png
new file mode 100644
index 0000000..8a325af
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_traditional.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_traditional_disabled.png b/res/drawable-hdpi/marker_cache_traditional_disabled.png
new file mode 100644
index 0000000..2758ef1
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_traditional_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_traditional_found.png b/res/drawable-hdpi/marker_cache_traditional_found.png
new file mode 100644
index 0000000..5fb2f14
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_traditional_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_traditional_own.png b/res/drawable-hdpi/marker_cache_traditional_own.png
new file mode 100644
index 0000000..bedc59e
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_traditional_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_virtual.png b/res/drawable-hdpi/marker_cache_virtual.png
new file mode 100644
index 0000000..e743ad4
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_virtual.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_virtual_disabled.png b/res/drawable-hdpi/marker_cache_virtual_disabled.png
new file mode 100644
index 0000000..9b4146c
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_virtual_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_virtual_found.png b/res/drawable-hdpi/marker_cache_virtual_found.png
new file mode 100644
index 0000000..9bb2eaa
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_virtual_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_virtual_own.png b/res/drawable-hdpi/marker_cache_virtual_own.png
new file mode 100644
index 0000000..3e813b5
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_virtual_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_webcam.png b/res/drawable-hdpi/marker_cache_webcam.png
new file mode 100644
index 0000000..b1612ea
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_webcam.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_webcam_disabled.png b/res/drawable-hdpi/marker_cache_webcam_disabled.png
new file mode 100644
index 0000000..90099d2
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_webcam_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_webcam_found.png b/res/drawable-hdpi/marker_cache_webcam_found.png
new file mode 100644
index 0000000..8892e18
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_webcam_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_webcam_own.png b/res/drawable-hdpi/marker_cache_webcam_own.png
new file mode 100644
index 0000000..4d28310
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_webcam_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_wherigo.png b/res/drawable-hdpi/marker_cache_wherigo.png
new file mode 100644
index 0000000..5520e35
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_wherigo.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_wherigo_disabled.png b/res/drawable-hdpi/marker_cache_wherigo_disabled.png
new file mode 100644
index 0000000..9cd4d0a
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_wherigo_disabled.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_wherigo_found.png b/res/drawable-hdpi/marker_cache_wherigo_found.png
new file mode 100644
index 0000000..dc8af16
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_wherigo_found.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_cache_wherigo_own.png b/res/drawable-hdpi/marker_cache_wherigo_own.png
new file mode 100644
index 0000000..718d733
--- /dev/null
+++ b/res/drawable-hdpi/marker_cache_wherigo_own.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_flag.png b/res/drawable-hdpi/marker_waypoint_flag.png
new file mode 100644
index 0000000..a15e26f
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_flag.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_pkg.png b/res/drawable-hdpi/marker_waypoint_pkg.png
new file mode 100644
index 0000000..251c5e5
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_pkg.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_puzzle.png b/res/drawable-hdpi/marker_waypoint_puzzle.png
new file mode 100644
index 0000000..1f51df5
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_puzzle.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_stage.png b/res/drawable-hdpi/marker_waypoint_stage.png
new file mode 100644
index 0000000..ffbf39b
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_stage.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_trailhead.png b/res/drawable-hdpi/marker_waypoint_trailhead.png
new file mode 100644
index 0000000..fe2e46a
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_trailhead.png
Binary files differ
diff --git a/res/drawable-hdpi/marker_waypoint_waypoint.png b/res/drawable-hdpi/marker_waypoint_waypoint.png
new file mode 100644
index 0000000..872359f
--- /dev/null
+++ b/res/drawable-hdpi/marker_waypoint_waypoint.png
Binary files differ
diff --git a/res/drawable-hdpi/my_location.png b/res/drawable-hdpi/my_location.png
new file mode 100644
index 0000000..cdb58c7
--- /dev/null
+++ b/res/drawable-hdpi/my_location.png
Binary files differ
diff --git a/res/drawable-hdpi/my_location_arrow.png b/res/drawable-hdpi/my_location_arrow.png
new file mode 100644
index 0000000..c8401d2
--- /dev/null
+++ b/res/drawable-hdpi/my_location_arrow.png
Binary files differ
diff --git a/res/drawable-hdpi/my_location_chevron.png b/res/drawable-hdpi/my_location_chevron.png
new file mode 100644
index 0000000..d0e7a8e
--- /dev/null
+++ b/res/drawable-hdpi/my_location_chevron.png
Binary files differ
diff --git a/res/drawable-hdpi/my_location_off.png b/res/drawable-hdpi/my_location_off.png
new file mode 100644
index 0000000..ced343c
--- /dev/null
+++ b/res/drawable-hdpi/my_location_off.png
Binary files differ
diff --git a/res/drawable-hdpi/my_location_on.png b/res/drawable-hdpi/my_location_on.png
new file mode 100644
index 0000000..5fde837
--- /dev/null
+++ b/res/drawable-hdpi/my_location_on.png
Binary files differ
diff --git a/res/drawable-hdpi/star_half.png b/res/drawable-hdpi/star_half.png
new file mode 100644
index 0000000..ae04557
--- /dev/null
+++ b/res/drawable-hdpi/star_half.png
Binary files differ
diff --git a/res/drawable-hdpi/star_off.png b/res/drawable-hdpi/star_off.png
new file mode 100644
index 0000000..28fd2eb
--- /dev/null
+++ b/res/drawable-hdpi/star_off.png
Binary files differ
diff --git a/res/drawable-hdpi/star_on.png b/res/drawable-hdpi/star_on.png
new file mode 100644
index 0000000..0675455
--- /dev/null
+++ b/res/drawable-hdpi/star_on.png
Binary files differ
diff --git a/res/drawable-hdpi/trackable_all.png b/res/drawable-hdpi/trackable_all.png
new file mode 100644
index 0000000..317f2d9
--- /dev/null
+++ b/res/drawable-hdpi/trackable_all.png
Binary files differ
diff --git a/res/drawable-hdpi/trackable_coin.png b/res/drawable-hdpi/trackable_coin.png
new file mode 100644
index 0000000..3f5138e
--- /dev/null
+++ b/res/drawable-hdpi/trackable_coin.png
Binary files differ
diff --git a/res/drawable-hdpi/trackable_coins.png b/res/drawable-hdpi/trackable_coins.png
new file mode 100644
index 0000000..7713407
--- /dev/null
+++ b/res/drawable-hdpi/trackable_coins.png
Binary files differ
diff --git a/res/drawable-hdpi/trackable_tb.png b/res/drawable-hdpi/trackable_tb.png
new file mode 100644
index 0000000..29f348c
--- /dev/null
+++ b/res/drawable-hdpi/trackable_tb.png
Binary files differ
diff --git a/res/drawable-hdpi/trackable_tbs.png b/res/drawable-hdpi/trackable_tbs.png
new file mode 100644
index 0000000..595f7a1
--- /dev/null
+++ b/res/drawable-hdpi/trackable_tbs.png
Binary files differ
diff --git a/res/drawable-hdpi/type_ape.png b/res/drawable-hdpi/type_ape.png
new file mode 100644
index 0000000..a312e7d
--- /dev/null
+++ b/res/drawable-hdpi/type_ape.png
Binary files differ
diff --git a/res/drawable-hdpi/type_cito.png b/res/drawable-hdpi/type_cito.png
new file mode 100644
index 0000000..13b0a6d
--- /dev/null
+++ b/res/drawable-hdpi/type_cito.png
Binary files differ
diff --git a/res/drawable-hdpi/type_earth.png b/res/drawable-hdpi/type_earth.png
new file mode 100644
index 0000000..88f060f
--- /dev/null
+++ b/res/drawable-hdpi/type_earth.png
Binary files differ
diff --git a/res/drawable-hdpi/type_event.png b/res/drawable-hdpi/type_event.png
new file mode 100644
index 0000000..64cbefd
--- /dev/null
+++ b/res/drawable-hdpi/type_event.png
Binary files differ
diff --git a/res/drawable-hdpi/type_letterbox.png b/res/drawable-hdpi/type_letterbox.png
new file mode 100644
index 0000000..c47fcd1
--- /dev/null
+++ b/res/drawable-hdpi/type_letterbox.png
Binary files differ
diff --git a/res/drawable-hdpi/type_locationless.png b/res/drawable-hdpi/type_locationless.png
new file mode 100644
index 0000000..9eea7bf
--- /dev/null
+++ b/res/drawable-hdpi/type_locationless.png
Binary files differ
diff --git a/res/drawable-hdpi/type_mega.png b/res/drawable-hdpi/type_mega.png
new file mode 100644
index 0000000..0a4df62
--- /dev/null
+++ b/res/drawable-hdpi/type_mega.png
Binary files differ
diff --git a/res/drawable-hdpi/type_multi.png b/res/drawable-hdpi/type_multi.png
new file mode 100644
index 0000000..e8bb3f7
--- /dev/null
+++ b/res/drawable-hdpi/type_multi.png
Binary files differ
diff --git a/res/drawable-hdpi/type_mystery.png b/res/drawable-hdpi/type_mystery.png
new file mode 100644
index 0000000..e0c63bd
--- /dev/null
+++ b/res/drawable-hdpi/type_mystery.png
Binary files differ
diff --git a/res/drawable-hdpi/type_traditional.png b/res/drawable-hdpi/type_traditional.png
new file mode 100644
index 0000000..fa5e39a
--- /dev/null
+++ b/res/drawable-hdpi/type_traditional.png
Binary files differ
diff --git a/res/drawable-hdpi/type_virtual.png b/res/drawable-hdpi/type_virtual.png
new file mode 100644
index 0000000..98fd974
--- /dev/null
+++ b/res/drawable-hdpi/type_virtual.png
Binary files differ
diff --git a/res/drawable-hdpi/type_webcam.png b/res/drawable-hdpi/type_webcam.png
new file mode 100644
index 0000000..498e383
--- /dev/null
+++ b/res/drawable-hdpi/type_webcam.png
Binary files differ
diff --git a/res/drawable-hdpi/type_wherigo.png b/res/drawable-hdpi/type_wherigo.png
new file mode 100644
index 0000000..4dccd4a
--- /dev/null
+++ b/res/drawable-hdpi/type_wherigo.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_flag.png b/res/drawable-hdpi/waypoint_flag.png
new file mode 100644
index 0000000..d537dfc
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_flag.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_pkg.png b/res/drawable-hdpi/waypoint_pkg.png
new file mode 100644
index 0000000..782c4bf
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_pkg.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_puzzle.png b/res/drawable-hdpi/waypoint_puzzle.png
new file mode 100644
index 0000000..a63e8c9
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_puzzle.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_stage.png b/res/drawable-hdpi/waypoint_stage.png
new file mode 100644
index 0000000..e9b38f3
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_stage.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_trailhead.png b/res/drawable-hdpi/waypoint_trailhead.png
new file mode 100644
index 0000000..8eb2a40
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_trailhead.png
Binary files differ
diff --git a/res/drawable-hdpi/waypoint_waypoint.png b/res/drawable-hdpi/waypoint_waypoint.png
new file mode 100644
index 0000000..504ac44
--- /dev/null
+++ b/res/drawable-hdpi/waypoint_waypoint.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_background_tile.png b/res/drawable-ldpi/actionbar_background_tile.png
new file mode 100644
index 0000000..d7f4732
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_background_tile.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_cgeo.png b/res/drawable-ldpi/actionbar_cgeo.png
new file mode 100644
index 0000000..ab98d37
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_cgeo.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_compass.png b/res/drawable-ldpi/actionbar_compass.png
new file mode 100644
index 0000000..665e695
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_compass.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_home.png b/res/drawable-ldpi/actionbar_home.png
new file mode 100644
index 0000000..2334d7d
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_home.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_manual.png b/res/drawable-ldpi/actionbar_manual.png
new file mode 100644
index 0000000..14af11d
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_manual.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_map.png b/res/drawable-ldpi/actionbar_map.png
new file mode 100644
index 0000000..afc108c
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_map.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_search.png b/res/drawable-ldpi/actionbar_search.png
new file mode 100644
index 0000000..f3ce1d9
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_search.png
Binary files differ
diff --git a/res/drawable-ldpi/actionbar_share.png b/res/drawable-ldpi/actionbar_share.png
new file mode 100644
index 0000000..53f28fe
--- /dev/null
+++ b/res/drawable-ldpi/actionbar_share.png
Binary files differ
diff --git a/res/drawable-ldpi/cgeo.png b/res/drawable-ldpi/cgeo.png
new file mode 100644
index 0000000..3dbbd0a
--- /dev/null
+++ b/res/drawable-ldpi/cgeo.png
Binary files differ
diff --git a/res/drawable-ldpi/hw_menu.png b/res/drawable-ldpi/hw_menu.png
new file mode 100644
index 0000000..d1b54f4
--- /dev/null
+++ b/res/drawable-ldpi/hw_menu.png
Binary files differ
diff --git a/res/drawable-ldpi/main_about.png b/res/drawable-ldpi/main_about.png
new file mode 100644
index 0000000..482e511
--- /dev/null
+++ b/res/drawable-ldpi/main_about.png
Binary files differ
diff --git a/res/drawable-ldpi/main_any.png b/res/drawable-ldpi/main_any.png
new file mode 100644
index 0000000..b307f95
--- /dev/null
+++ b/res/drawable-ldpi/main_any.png
Binary files differ
diff --git a/res/drawable-ldpi/main_filter.png b/res/drawable-ldpi/main_filter.png
new file mode 100644
index 0000000..b632ec1
--- /dev/null
+++ b/res/drawable-ldpi/main_filter.png
Binary files differ
diff --git a/res/drawable-ldpi/main_live.png b/res/drawable-ldpi/main_live.png
new file mode 100644
index 0000000..568b777
--- /dev/null
+++ b/res/drawable-ldpi/main_live.png
Binary files differ
diff --git a/res/drawable-ldpi/main_nearby.png b/res/drawable-ldpi/main_nearby.png
new file mode 100644
index 0000000..d6e1756
--- /dev/null
+++ b/res/drawable-ldpi/main_nearby.png
Binary files differ
diff --git a/res/drawable-ldpi/main_search.png b/res/drawable-ldpi/main_search.png
new file mode 100644
index 0000000..5ab1f1b
--- /dev/null
+++ b/res/drawable-ldpi/main_search.png
Binary files differ
diff --git a/res/drawable-ldpi/main_settings.png b/res/drawable-ldpi/main_settings.png
new file mode 100644
index 0000000..a6c46b3
--- /dev/null
+++ b/res/drawable-ldpi/main_settings.png
Binary files differ
diff --git a/res/drawable-ldpi/main_stored.png b/res/drawable-ldpi/main_stored.png
new file mode 100644
index 0000000..17dad09
--- /dev/null
+++ b/res/drawable-ldpi/main_stored.png
Binary files differ
diff --git a/res/drawable-ldpi/my_location_chevron.png b/res/drawable-ldpi/my_location_chevron.png
new file mode 100644
index 0000000..108df78
--- /dev/null
+++ b/res/drawable-ldpi/my_location_chevron.png
Binary files differ
diff --git a/res/drawable-ldpi/my_location_off.png b/res/drawable-ldpi/my_location_off.png
new file mode 100644
index 0000000..5889b1d
--- /dev/null
+++ b/res/drawable-ldpi/my_location_off.png
Binary files differ
diff --git a/res/drawable-ldpi/my_location_on.png b/res/drawable-ldpi/my_location_on.png
new file mode 100644
index 0000000..81538a4
--- /dev/null
+++ b/res/drawable-ldpi/my_location_on.png
Binary files differ
diff --git a/res/drawable-ldpi/star_half.png b/res/drawable-ldpi/star_half.png
new file mode 100644
index 0000000..a278913
--- /dev/null
+++ b/res/drawable-ldpi/star_half.png
Binary files differ
diff --git a/res/drawable-ldpi/star_off.png b/res/drawable-ldpi/star_off.png
new file mode 100644
index 0000000..647d641
--- /dev/null
+++ b/res/drawable-ldpi/star_off.png
Binary files differ
diff --git a/res/drawable-ldpi/star_on.png b/res/drawable-ldpi/star_on.png
new file mode 100644
index 0000000..df5b053
--- /dev/null
+++ b/res/drawable-ldpi/star_on.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_background_tile.png b/res/drawable-mdpi/actionbar_background_tile.png
new file mode 100644
index 0000000..ba0b08b
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_background_tile.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_cgeo.png b/res/drawable-mdpi/actionbar_cgeo.png
new file mode 100644
index 0000000..a89abf8
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_cgeo.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_compass.png b/res/drawable-mdpi/actionbar_compass.png
new file mode 100644
index 0000000..2f5c22b
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_compass.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_home.png b/res/drawable-mdpi/actionbar_home.png
new file mode 100644
index 0000000..e109f0a
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_home.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_manual.png b/res/drawable-mdpi/actionbar_manual.png
new file mode 100644
index 0000000..a71acb3
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_manual.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_map.png b/res/drawable-mdpi/actionbar_map.png
new file mode 100644
index 0000000..80287d7
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_map.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_search.png b/res/drawable-mdpi/actionbar_search.png
new file mode 100644
index 0000000..cce7789
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_search.png
Binary files differ
diff --git a/res/drawable-mdpi/actionbar_share.png b/res/drawable-mdpi/actionbar_share.png
new file mode 100644
index 0000000..f323732
--- /dev/null
+++ b/res/drawable-mdpi/actionbar_share.png
Binary files differ
diff --git a/res/drawable-mdpi/cgeo.png b/res/drawable-mdpi/cgeo.png
new file mode 100644
index 0000000..126feb3
--- /dev/null
+++ b/res/drawable-mdpi/cgeo.png
Binary files differ
diff --git a/res/drawable-mdpi/hw_menu.png b/res/drawable-mdpi/hw_menu.png
new file mode 100644
index 0000000..ba7dee9
--- /dev/null
+++ b/res/drawable-mdpi/hw_menu.png
Binary files differ
diff --git a/res/drawable-mdpi/main_about.png b/res/drawable-mdpi/main_about.png
new file mode 100644
index 0000000..61abcac
--- /dev/null
+++ b/res/drawable-mdpi/main_about.png
Binary files differ
diff --git a/res/drawable-mdpi/main_any.png b/res/drawable-mdpi/main_any.png
new file mode 100644
index 0000000..cea3288
--- /dev/null
+++ b/res/drawable-mdpi/main_any.png
Binary files differ
diff --git a/res/drawable-mdpi/main_filter.png b/res/drawable-mdpi/main_filter.png
new file mode 100644
index 0000000..996d15b
--- /dev/null
+++ b/res/drawable-mdpi/main_filter.png
Binary files differ
diff --git a/res/drawable-mdpi/main_live.png b/res/drawable-mdpi/main_live.png
new file mode 100644
index 0000000..f2cc262
--- /dev/null
+++ b/res/drawable-mdpi/main_live.png
Binary files differ
diff --git a/res/drawable-mdpi/main_nearby.png b/res/drawable-mdpi/main_nearby.png
new file mode 100644
index 0000000..9166267
--- /dev/null
+++ b/res/drawable-mdpi/main_nearby.png
Binary files differ
diff --git a/res/drawable-mdpi/main_search.png b/res/drawable-mdpi/main_search.png
new file mode 100644
index 0000000..c3c1fdc
--- /dev/null
+++ b/res/drawable-mdpi/main_search.png
Binary files differ
diff --git a/res/drawable-mdpi/main_settings.png b/res/drawable-mdpi/main_settings.png
new file mode 100644
index 0000000..a0a624e
--- /dev/null
+++ b/res/drawable-mdpi/main_settings.png
Binary files differ
diff --git a/res/drawable-mdpi/main_stored.png b/res/drawable-mdpi/main_stored.png
new file mode 100644
index 0000000..b595723
--- /dev/null
+++ b/res/drawable-mdpi/main_stored.png
Binary files differ
diff --git a/res/drawable-mdpi/my_location_chevron.png b/res/drawable-mdpi/my_location_chevron.png
new file mode 100644
index 0000000..67b863f
--- /dev/null
+++ b/res/drawable-mdpi/my_location_chevron.png
Binary files differ
diff --git a/res/drawable-mdpi/my_location_off.png b/res/drawable-mdpi/my_location_off.png
new file mode 100644
index 0000000..0266600
--- /dev/null
+++ b/res/drawable-mdpi/my_location_off.png
Binary files differ
diff --git a/res/drawable-mdpi/my_location_on.png b/res/drawable-mdpi/my_location_on.png
new file mode 100644
index 0000000..04bec8f
--- /dev/null
+++ b/res/drawable-mdpi/my_location_on.png
Binary files differ
diff --git a/res/drawable-mdpi/star_half.png b/res/drawable-mdpi/star_half.png
new file mode 100644
index 0000000..17eeaf7
--- /dev/null
+++ b/res/drawable-mdpi/star_half.png
Binary files differ
diff --git a/res/drawable-mdpi/star_off.png b/res/drawable-mdpi/star_off.png
new file mode 100644
index 0000000..a7e0c83
--- /dev/null
+++ b/res/drawable-mdpi/star_off.png
Binary files differ
diff --git a/res/drawable-mdpi/star_on.png b/res/drawable-mdpi/star_on.png
new file mode 100644
index 0000000..801928a
--- /dev/null
+++ b/res/drawable-mdpi/star_on.png
Binary files differ
diff --git a/res/drawable/action_button_dark.xml b/res/drawable/action_button_dark.xml
new file mode 100644
index 0000000..82ecdcd
--- /dev/null
+++ b/res/drawable/action_button_dark.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="true" android:drawable="@drawable/action_button_dark_default" />
+ <item android:state_pressed="true" android:drawable="@drawable/action_button_dark_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/action_button_dark_pressed" />
+ <item android:drawable="@drawable/action_button_dark_off" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/action_button_dark_default.xml b/res/drawable/action_button_dark_default.xml
new file mode 100644
index 0000000..8059482
--- /dev/null
+++ b/res/drawable/action_button_dark_default.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66FFFFFF"
+ android:width="1px" />
+ <solid
+ android:color="#11FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_dark_dialog.xml b/res/drawable/action_button_dark_dialog.xml
new file mode 100644
index 0000000..17db3fb
--- /dev/null
+++ b/res/drawable/action_button_dark_dialog.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66FFFFFF"
+ android:width="1px" />
+ <solid
+ android:color="#FF080808" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_dark_off.xml b/res/drawable/action_button_dark_off.xml
new file mode 100644
index 0000000..6b0f3ff
--- /dev/null
+++ b/res/drawable/action_button_dark_off.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#44FFFFFF"
+ android:width="1px" />
+ <solid
+ android:color="#33000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_dark_pressed.xml b/res/drawable/action_button_dark_pressed.xml
new file mode 100644
index 0000000..79a1c65
--- /dev/null
+++ b/res/drawable/action_button_dark_pressed.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#FFFFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#44FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_light.xml b/res/drawable/action_button_light.xml
new file mode 100644
index 0000000..ac59bf7
--- /dev/null
+++ b/res/drawable/action_button_light.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="true" android:drawable="@drawable/action_button_light_default" />
+ <item android:state_pressed="true" android:drawable="@drawable/action_button_light_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/action_button_light_pressed" />
+ <item android:drawable="@drawable/action_button_light_off" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/action_button_light_default.xml b/res/drawable/action_button_light_default.xml
new file mode 100644
index 0000000..a7ac6fb
--- /dev/null
+++ b/res/drawable/action_button_light_default.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66000000"
+ android:width="1px" />
+ <solid
+ android:color="#11000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_light_dialog.xml b/res/drawable/action_button_light_dialog.xml
new file mode 100644
index 0000000..e17a55a
--- /dev/null
+++ b/res/drawable/action_button_light_dialog.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66000000"
+ android:width="1px" />
+ <solid
+ android:color="#FFEEEEEE" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_light_off.xml b/res/drawable/action_button_light_off.xml
new file mode 100644
index 0000000..ad94267
--- /dev/null
+++ b/res/drawable/action_button_light_off.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#44000000"
+ android:width="1px" />
+ <solid
+ android:color="#33FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/action_button_light_pressed.xml b/res/drawable/action_button_light_pressed.xml
new file mode 100644
index 0000000..fd8a9fb
--- /dev/null
+++ b/res/drawable/action_button_light_pressed.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#FF000000"
+ android:width="2px" />
+ <solid
+ android:color="#44000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/actionbar_background.xml b/res/drawable/actionbar_background.xml
new file mode 100644
index 0000000..0994d2c
--- /dev/null
+++ b/res/drawable/actionbar_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/actionbar_background_tile"
+ android:tileMode="repeat" /> \ No newline at end of file
diff --git a/res/drawable/actionbar_background_tile.png b/res/drawable/actionbar_background_tile.png
new file mode 100644
index 0000000..ba0b08b
--- /dev/null
+++ b/res/drawable/actionbar_background_tile.png
Binary files differ
diff --git a/res/drawable/actionbar_cgeo.png b/res/drawable/actionbar_cgeo.png
new file mode 100644
index 0000000..a89abf8
--- /dev/null
+++ b/res/drawable/actionbar_cgeo.png
Binary files differ
diff --git a/res/drawable/actionbar_compass.png b/res/drawable/actionbar_compass.png
new file mode 100644
index 0000000..2f5c22b
--- /dev/null
+++ b/res/drawable/actionbar_compass.png
Binary files differ
diff --git a/res/drawable/actionbar_home.png b/res/drawable/actionbar_home.png
new file mode 100644
index 0000000..e109f0a
--- /dev/null
+++ b/res/drawable/actionbar_home.png
Binary files differ
diff --git a/res/drawable/actionbar_manual.png b/res/drawable/actionbar_manual.png
new file mode 100644
index 0000000..a71acb3
--- /dev/null
+++ b/res/drawable/actionbar_manual.png
Binary files differ
diff --git a/res/drawable/actionbar_map.png b/res/drawable/actionbar_map.png
new file mode 100644
index 0000000..80287d7
--- /dev/null
+++ b/res/drawable/actionbar_map.png
Binary files differ
diff --git a/res/drawable/actionbar_search.png b/res/drawable/actionbar_search.png
new file mode 100644
index 0000000..cce7789
--- /dev/null
+++ b/res/drawable/actionbar_search.png
Binary files differ
diff --git a/res/drawable/actionbar_separator.xml b/res/drawable/actionbar_separator.xml
new file mode 100644
index 0000000..72c42f9
--- /dev/null
+++ b/res/drawable/actionbar_separator.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:startColor="#44000000"
+ android:endColor="#AAFFFFFF"
+ android:angle="0" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/actionbar_share.png b/res/drawable/actionbar_share.png
new file mode 100644
index 0000000..f323732
--- /dev/null
+++ b/res/drawable/actionbar_share.png
Binary files differ
diff --git a/res/drawable/bcg_dark.xml b/res/drawable/bcg_dark.xml
new file mode 100644
index 0000000..0acf0e0
--- /dev/null
+++ b/res/drawable/bcg_dark.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="@color/background_dark" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/bcg_dialog_dark.xml b/res/drawable/bcg_dialog_dark.xml
new file mode 100644
index 0000000..73b2276
--- /dev/null
+++ b/res/drawable/bcg_dialog_dark.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#11FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/bcg_dialog_light.xml b/res/drawable/bcg_dialog_light.xml
new file mode 100644
index 0000000..b89730f
--- /dev/null
+++ b/res/drawable/bcg_dialog_light.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#11000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/bcg_light.xml b/res/drawable/bcg_light.xml
new file mode 100644
index 0000000..0acf0e0
--- /dev/null
+++ b/res/drawable/bcg_light.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="@color/background_dark" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/cache_dark.xml b/res/drawable/cache_dark.xml
new file mode 100644
index 0000000..7e87cd7
--- /dev/null
+++ b/res/drawable/cache_dark.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/cache_dark_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/cache_dark_pressed" />
+ <item android:drawable="@drawable/bcg_dark" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/cache_dark_pressed.xml b/res/drawable/cache_dark_pressed.xml
new file mode 100644
index 0000000..593caea
--- /dev/null
+++ b/res/drawable/cache_dark_pressed.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#44FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/cache_light.xml b/res/drawable/cache_light.xml
new file mode 100644
index 0000000..b2c669a
--- /dev/null
+++ b/res/drawable/cache_light.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/cache_light_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/cache_light_pressed" />
+ <item android:drawable="@drawable/bcg_light" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/cache_light_pressed.xml b/res/drawable/cache_light_pressed.xml
new file mode 100644
index 0000000..411f915
--- /dev/null
+++ b/res/drawable/cache_light_pressed.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#44000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/carnero_logo.png b/res/drawable/carnero_logo.png
new file mode 100644
index 0000000..e503164
--- /dev/null
+++ b/res/drawable/carnero_logo.png
Binary files differ
diff --git a/res/drawable/cgeo.png b/res/drawable/cgeo.png
new file mode 100644
index 0000000..126feb3
--- /dev/null
+++ b/res/drawable/cgeo.png
Binary files differ
diff --git a/res/drawable/client_cgeo.png b/res/drawable/client_cgeo.png
new file mode 100644
index 0000000..119f0dd
--- /dev/null
+++ b/res/drawable/client_cgeo.png
Binary files differ
diff --git a/res/drawable/client_handygeocaching.png b/res/drawable/client_handygeocaching.png
new file mode 100644
index 0000000..a842cb5
--- /dev/null
+++ b/res/drawable/client_handygeocaching.png
Binary files differ
diff --git a/res/drawable/client_precaching.png b/res/drawable/client_precaching.png
new file mode 100644
index 0000000..5fd95d6
--- /dev/null
+++ b/res/drawable/client_precaching.png
Binary files differ
diff --git a/res/drawable/compass_arrow.png b/res/drawable/compass_arrow.png
new file mode 100644
index 0000000..a6524d9
--- /dev/null
+++ b/res/drawable/compass_arrow.png
Binary files differ
diff --git a/res/drawable/compass_arrow_mini_black.png b/res/drawable/compass_arrow_mini_black.png
new file mode 100644
index 0000000..682f067
--- /dev/null
+++ b/res/drawable/compass_arrow_mini_black.png
Binary files differ
diff --git a/res/drawable/compass_arrow_mini_white.png b/res/drawable/compass_arrow_mini_white.png
new file mode 100644
index 0000000..2b11847
--- /dev/null
+++ b/res/drawable/compass_arrow_mini_white.png
Binary files differ
diff --git a/res/drawable/compass_overlay.png b/res/drawable/compass_overlay.png
new file mode 100644
index 0000000..98b8fd6
--- /dev/null
+++ b/res/drawable/compass_overlay.png
Binary files differ
diff --git a/res/drawable/compass_rose.png b/res/drawable/compass_rose.png
new file mode 100644
index 0000000..08e2c8c
--- /dev/null
+++ b/res/drawable/compass_rose.png
Binary files differ
diff --git a/res/drawable/compass_underlay.png b/res/drawable/compass_underlay.png
new file mode 100644
index 0000000..7b19442
--- /dev/null
+++ b/res/drawable/compass_underlay.png
Binary files differ
diff --git a/res/drawable/count_bcg.xml b/res/drawable/count_bcg.xml
new file mode 100644
index 0000000..8c7cde4
--- /dev/null
+++ b/res/drawable/count_bcg.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#AAFFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#FF990000" />
+ <corners
+ android:bottomRightRadius="4dp"
+ android:bottomLeftRadius="4dp"
+ android:topLeftRadius="4dp"
+ android:topRightRadius="4dp" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/dialog_button_dark.xml b/res/drawable/dialog_button_dark.xml
new file mode 100644
index 0000000..e36438b
--- /dev/null
+++ b/res/drawable/dialog_button_dark.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/action_button_dark_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/action_button_dark_pressed" />
+ <item android:drawable="@drawable/action_button_dark_dialog" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/dialog_button_light.xml b/res/drawable/dialog_button_light.xml
new file mode 100644
index 0000000..95414ff
--- /dev/null
+++ b/res/drawable/dialog_button_light.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@drawable/action_button_light_pressed" />
+ <item android:state_focused="true" android:drawable="@drawable/action_button_light_pressed" />
+ <item android:drawable="@drawable/action_button_light_dialog" />
+</selector> \ No newline at end of file
diff --git a/res/drawable/favourite_background_dark.xml b/res/drawable/favourite_background_dark.xml
new file mode 100644
index 0000000..b8aa8d3
--- /dev/null
+++ b/res/drawable/favourite_background_dark.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#99FFFFFF" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_green_dark.xml b/res/drawable/favourite_background_green_dark.xml
new file mode 100644
index 0000000..3e1b545
--- /dev/null
+++ b/res/drawable/favourite_background_green_dark.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#9900FF00" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_green_light.xml b/res/drawable/favourite_background_green_light.xml
new file mode 100644
index 0000000..a2070e7
--- /dev/null
+++ b/res/drawable/favourite_background_green_light.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99000000"
+ android:width="2px" />
+ <solid
+ android:color="#9900FF00" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_light.xml b/res/drawable/favourite_background_light.xml
new file mode 100644
index 0000000..60c0b2c
--- /dev/null
+++ b/res/drawable/favourite_background_light.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99000000"
+ android:width="2px" />
+ <solid
+ android:color="#99000000" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_orange_dark.xml b/res/drawable/favourite_background_orange_dark.xml
new file mode 100644
index 0000000..8730487
--- /dev/null
+++ b/res/drawable/favourite_background_orange_dark.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#99FFAA00" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_orange_light.xml b/res/drawable/favourite_background_orange_light.xml
new file mode 100644
index 0000000..89ef726
--- /dev/null
+++ b/res/drawable/favourite_background_orange_light.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99000000"
+ android:width="2px" />
+ <solid
+ android:color="#99FFAA00" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_red_dark.xml b/res/drawable/favourite_background_red_dark.xml
new file mode 100644
index 0000000..2fb580e
--- /dev/null
+++ b/res/drawable/favourite_background_red_dark.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#99FF0000" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/favourite_background_red_light.xml b/res/drawable/favourite_background_red_light.xml
new file mode 100644
index 0000000..b16cb92
--- /dev/null
+++ b/res/drawable/favourite_background_red_light.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99000000"
+ android:width="2px" />
+ <solid
+ android:color="#99FF0000" />
+ <corners
+ android:bottomLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/helper_bcg.xml b/res/drawable/helper_bcg.xml
new file mode 100644
index 0000000..b30f9be
--- /dev/null
+++ b/res/drawable/helper_bcg.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#FF191919" />
+ <corners
+ android:bottomRightRadius="3dp"
+ android:bottomLeftRadius="3dp"
+ android:topLeftRadius="3dp"
+ android:topRightRadius="3dp" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/helper_bluetoothgps.png b/res/drawable/helper_bluetoothgps.png
new file mode 100644
index 0000000..ecae5ee
--- /dev/null
+++ b/res/drawable/helper_bluetoothgps.png
Binary files differ
diff --git a/res/drawable/helper_gpsstatus.png b/res/drawable/helper_gpsstatus.png
new file mode 100644
index 0000000..07c6419
--- /dev/null
+++ b/res/drawable/helper_gpsstatus.png
Binary files differ
diff --git a/res/drawable/helper_locus.png b/res/drawable/helper_locus.png
new file mode 100644
index 0000000..836bb4e
--- /dev/null
+++ b/res/drawable/helper_locus.png
Binary files differ
diff --git a/res/drawable/helper_manual.png b/res/drawable/helper_manual.png
new file mode 100644
index 0000000..c3c43db
--- /dev/null
+++ b/res/drawable/helper_manual.png
Binary files differ
diff --git a/res/drawable/hw_menu.png b/res/drawable/hw_menu.png
new file mode 100644
index 0000000..ba7dee9
--- /dev/null
+++ b/res/drawable/hw_menu.png
Binary files differ
diff --git a/res/drawable/icon_bcg.xml b/res/drawable/icon_bcg.xml
new file mode 100644
index 0000000..864d99a
--- /dev/null
+++ b/res/drawable/icon_bcg.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#80000000" />
+ <corners
+ android:bottomRightRadius="8dp"
+ android:bottomLeftRadius="8dp"
+ android:topLeftRadius="8dp"
+ android:topRightRadius="8dp" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/icon_big.png b/res/drawable/icon_big.png
new file mode 100644
index 0000000..a7d0d1b
--- /dev/null
+++ b/res/drawable/icon_big.png
Binary files differ
diff --git a/res/drawable/image_no_placement.png b/res/drawable/image_no_placement.png
new file mode 100644
index 0000000..d73f7c7
--- /dev/null
+++ b/res/drawable/image_no_placement.png
Binary files differ
diff --git a/res/drawable/image_not_loaded.png b/res/drawable/image_not_loaded.png
new file mode 100644
index 0000000..f37377c
--- /dev/null
+++ b/res/drawable/image_not_loaded.png
Binary files differ
diff --git a/res/drawable/input_bcg_dark.xml b/res/drawable/input_bcg_dark.xml
new file mode 100644
index 0000000..e7029d9
--- /dev/null
+++ b/res/drawable/input_bcg_dark.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66FFFFFF"
+ android:width="1px" />
+ <solid
+ android:color="#22000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/input_bcg_light.xml b/res/drawable/input_bcg_light.xml
new file mode 100644
index 0000000..f9cdae8
--- /dev/null
+++ b/res/drawable/input_bcg_light.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#66000000"
+ android:width="1px" />
+ <solid
+ android:color="#22FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/inventory_background_dark.xml b/res/drawable/inventory_background_dark.xml
new file mode 100644
index 0000000..fce3151
--- /dev/null
+++ b/res/drawable/inventory_background_dark.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99FFFFFF"
+ android:width="2px" />
+ <solid
+ android:color="#AA000000" />
+ <corners
+ android:topLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/inventory_background_light.xml b/res/drawable/inventory_background_light.xml
new file mode 100644
index 0000000..71486c7
--- /dev/null
+++ b/res/drawable/inventory_background_light.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#99000000"
+ android:width="2px" />
+ <solid
+ android:color="#AAFFFFFF" />
+ <corners
+ android:topLeftRadius="5dip" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/list_footer_background.xml b/res/drawable/list_footer_background.xml
new file mode 100644
index 0000000..0994d2c
--- /dev/null
+++ b/res/drawable/list_footer_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/actionbar_background_tile"
+ android:tileMode="repeat" /> \ No newline at end of file
diff --git a/res/drawable/main_about.png b/res/drawable/main_about.png
new file mode 100644
index 0000000..61abcac
--- /dev/null
+++ b/res/drawable/main_about.png
Binary files differ
diff --git a/res/drawable/main_any.png b/res/drawable/main_any.png
new file mode 100644
index 0000000..cea3288
--- /dev/null
+++ b/res/drawable/main_any.png
Binary files differ
diff --git a/res/drawable/main_filter.png b/res/drawable/main_filter.png
new file mode 100644
index 0000000..996d15b
--- /dev/null
+++ b/res/drawable/main_filter.png
Binary files differ
diff --git a/res/drawable/main_live.png b/res/drawable/main_live.png
new file mode 100644
index 0000000..f2cc262
--- /dev/null
+++ b/res/drawable/main_live.png
Binary files differ
diff --git a/res/drawable/main_nearby.png b/res/drawable/main_nearby.png
new file mode 100644
index 0000000..9166267
--- /dev/null
+++ b/res/drawable/main_nearby.png
Binary files differ
diff --git a/res/drawable/main_search.png b/res/drawable/main_search.png
new file mode 100644
index 0000000..c3c1fdc
--- /dev/null
+++ b/res/drawable/main_search.png
Binary files differ
diff --git a/res/drawable/main_settings.png b/res/drawable/main_settings.png
new file mode 100644
index 0000000..a0a624e
--- /dev/null
+++ b/res/drawable/main_settings.png
Binary files differ
diff --git a/res/drawable/main_stored.png b/res/drawable/main_stored.png
new file mode 100644
index 0000000..b595723
--- /dev/null
+++ b/res/drawable/main_stored.png
Binary files differ
diff --git a/res/drawable/map_close_dark.xml b/res/drawable/map_close_dark.xml
new file mode 100644
index 0000000..794736e
--- /dev/null
+++ b/res/drawable/map_close_dark.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#FF000000"
+ android:width="1px" />
+ <solid
+ android:color="#99000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/map_close_light.xml b/res/drawable/map_close_light.xml
new file mode 100644
index 0000000..92a3b9a
--- /dev/null
+++ b/res/drawable/map_close_light.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <stroke
+ android:color="#FFFFFFFF"
+ android:width="1px" />
+ <solid
+ android:color="#99FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/map_status_dark.xml b/res/drawable/map_status_dark.xml
new file mode 100644
index 0000000..bc257ff
--- /dev/null
+++ b/res/drawable/map_status_dark.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:startColor="#00000000"
+ android:centerColor="#66000000"
+ android:endColor="#88000000"
+ android:angle="90" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/map_status_light.xml b/res/drawable/map_status_light.xml
new file mode 100644
index 0000000..a6ae801
--- /dev/null
+++ b/res/drawable/map_status_light.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:startColor="#00FFFFFF"
+ android:centerColor="#66FFFFFF"
+ android:endColor="#88FFFFFF"
+ android:angle="90" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/mark_green.xml b/res/drawable/mark_green.xml
new file mode 100644
index 0000000..1d9ee4a
--- /dev/null
+++ b/res/drawable/mark_green.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#FF009900" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/mark_orange.xml b/res/drawable/mark_orange.xml
new file mode 100644
index 0000000..3931755
--- /dev/null
+++ b/res/drawable/mark_orange.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#FF777700" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/mark_red.xml b/res/drawable/mark_red.xml
new file mode 100644
index 0000000..083fafd
--- /dev/null
+++ b/res/drawable/mark_red.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#FF770000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/mark_red_more.xml b/res/drawable/mark_red_more.xml
new file mode 100644
index 0000000..b9e355e
--- /dev/null
+++ b/res/drawable/mark_red_more.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#FFFF0000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/marker.png b/res/drawable/marker.png
new file mode 100644
index 0000000..4e0e7c7
--- /dev/null
+++ b/res/drawable/marker.png
Binary files differ
diff --git a/res/drawable/marker_cache_ape.png b/res/drawable/marker_cache_ape.png
new file mode 100644
index 0000000..246dada
--- /dev/null
+++ b/res/drawable/marker_cache_ape.png
Binary files differ
diff --git a/res/drawable/marker_cache_ape_disabled.png b/res/drawable/marker_cache_ape_disabled.png
new file mode 100644
index 0000000..5df88ce
--- /dev/null
+++ b/res/drawable/marker_cache_ape_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_ape_found.png b/res/drawable/marker_cache_ape_found.png
new file mode 100644
index 0000000..90eb602
--- /dev/null
+++ b/res/drawable/marker_cache_ape_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_ape_own.png b/res/drawable/marker_cache_ape_own.png
new file mode 100644
index 0000000..a71690c
--- /dev/null
+++ b/res/drawable/marker_cache_ape_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_cito.png b/res/drawable/marker_cache_cito.png
new file mode 100644
index 0000000..a541a54
--- /dev/null
+++ b/res/drawable/marker_cache_cito.png
Binary files differ
diff --git a/res/drawable/marker_cache_cito_disabled.png b/res/drawable/marker_cache_cito_disabled.png
new file mode 100644
index 0000000..4c3bedd
--- /dev/null
+++ b/res/drawable/marker_cache_cito_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_cito_found.png b/res/drawable/marker_cache_cito_found.png
new file mode 100644
index 0000000..4f9416b
--- /dev/null
+++ b/res/drawable/marker_cache_cito_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_cito_own.png b/res/drawable/marker_cache_cito_own.png
new file mode 100644
index 0000000..47124d3
--- /dev/null
+++ b/res/drawable/marker_cache_cito_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_earth.png b/res/drawable/marker_cache_earth.png
new file mode 100644
index 0000000..95f056a
--- /dev/null
+++ b/res/drawable/marker_cache_earth.png
Binary files differ
diff --git a/res/drawable/marker_cache_earth_disabled.png b/res/drawable/marker_cache_earth_disabled.png
new file mode 100644
index 0000000..a12e72a
--- /dev/null
+++ b/res/drawable/marker_cache_earth_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_earth_found.png b/res/drawable/marker_cache_earth_found.png
new file mode 100644
index 0000000..ec6731b
--- /dev/null
+++ b/res/drawable/marker_cache_earth_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_earth_own.png b/res/drawable/marker_cache_earth_own.png
new file mode 100644
index 0000000..9c6b9a3
--- /dev/null
+++ b/res/drawable/marker_cache_earth_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_event.png b/res/drawable/marker_cache_event.png
new file mode 100644
index 0000000..b273b5e
--- /dev/null
+++ b/res/drawable/marker_cache_event.png
Binary files differ
diff --git a/res/drawable/marker_cache_event_disabled.png b/res/drawable/marker_cache_event_disabled.png
new file mode 100644
index 0000000..c88a2ed
--- /dev/null
+++ b/res/drawable/marker_cache_event_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_event_found.png b/res/drawable/marker_cache_event_found.png
new file mode 100644
index 0000000..2925827
--- /dev/null
+++ b/res/drawable/marker_cache_event_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_event_own.png b/res/drawable/marker_cache_event_own.png
new file mode 100644
index 0000000..0d6d9e7
--- /dev/null
+++ b/res/drawable/marker_cache_event_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_gchq.png b/res/drawable/marker_cache_gchq.png
new file mode 100644
index 0000000..01ea439
--- /dev/null
+++ b/res/drawable/marker_cache_gchq.png
Binary files differ
diff --git a/res/drawable/marker_cache_gchq_disabled.png b/res/drawable/marker_cache_gchq_disabled.png
new file mode 100644
index 0000000..139112c
--- /dev/null
+++ b/res/drawable/marker_cache_gchq_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_gchq_found.png b/res/drawable/marker_cache_gchq_found.png
new file mode 100644
index 0000000..ca12c03
--- /dev/null
+++ b/res/drawable/marker_cache_gchq_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_gchq_own.png b/res/drawable/marker_cache_gchq_own.png
new file mode 100644
index 0000000..3fb647b
--- /dev/null
+++ b/res/drawable/marker_cache_gchq_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_letterbox.png b/res/drawable/marker_cache_letterbox.png
new file mode 100644
index 0000000..16ac2f4
--- /dev/null
+++ b/res/drawable/marker_cache_letterbox.png
Binary files differ
diff --git a/res/drawable/marker_cache_letterbox_disabled.png b/res/drawable/marker_cache_letterbox_disabled.png
new file mode 100644
index 0000000..a8a668e
--- /dev/null
+++ b/res/drawable/marker_cache_letterbox_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_letterbox_found.png b/res/drawable/marker_cache_letterbox_found.png
new file mode 100644
index 0000000..def6ddd
--- /dev/null
+++ b/res/drawable/marker_cache_letterbox_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_letterbox_own.png b/res/drawable/marker_cache_letterbox_own.png
new file mode 100644
index 0000000..66bcddd
--- /dev/null
+++ b/res/drawable/marker_cache_letterbox_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_locationless.png b/res/drawable/marker_cache_locationless.png
new file mode 100644
index 0000000..624baf9
--- /dev/null
+++ b/res/drawable/marker_cache_locationless.png
Binary files differ
diff --git a/res/drawable/marker_cache_locationless_disabled.png b/res/drawable/marker_cache_locationless_disabled.png
new file mode 100644
index 0000000..6f5115d
--- /dev/null
+++ b/res/drawable/marker_cache_locationless_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_locationless_found.png b/res/drawable/marker_cache_locationless_found.png
new file mode 100644
index 0000000..5c744b4
--- /dev/null
+++ b/res/drawable/marker_cache_locationless_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_locationless_own.png b/res/drawable/marker_cache_locationless_own.png
new file mode 100644
index 0000000..3e9d96b
--- /dev/null
+++ b/res/drawable/marker_cache_locationless_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_mega.png b/res/drawable/marker_cache_mega.png
new file mode 100644
index 0000000..be17934
--- /dev/null
+++ b/res/drawable/marker_cache_mega.png
Binary files differ
diff --git a/res/drawable/marker_cache_mega_disabled.png b/res/drawable/marker_cache_mega_disabled.png
new file mode 100644
index 0000000..efefd18
--- /dev/null
+++ b/res/drawable/marker_cache_mega_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_mega_found.png b/res/drawable/marker_cache_mega_found.png
new file mode 100644
index 0000000..022f393
--- /dev/null
+++ b/res/drawable/marker_cache_mega_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_mega_own.png b/res/drawable/marker_cache_mega_own.png
new file mode 100644
index 0000000..d754d40
--- /dev/null
+++ b/res/drawable/marker_cache_mega_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_multi.png b/res/drawable/marker_cache_multi.png
new file mode 100644
index 0000000..0d814d1
--- /dev/null
+++ b/res/drawable/marker_cache_multi.png
Binary files differ
diff --git a/res/drawable/marker_cache_multi_disabled.png b/res/drawable/marker_cache_multi_disabled.png
new file mode 100644
index 0000000..7a2f2c5
--- /dev/null
+++ b/res/drawable/marker_cache_multi_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_multi_found.png b/res/drawable/marker_cache_multi_found.png
new file mode 100644
index 0000000..0a36003
--- /dev/null
+++ b/res/drawable/marker_cache_multi_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_multi_own.png b/res/drawable/marker_cache_multi_own.png
new file mode 100644
index 0000000..491ef54
--- /dev/null
+++ b/res/drawable/marker_cache_multi_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_mystery.png b/res/drawable/marker_cache_mystery.png
new file mode 100644
index 0000000..2feaf96
--- /dev/null
+++ b/res/drawable/marker_cache_mystery.png
Binary files differ
diff --git a/res/drawable/marker_cache_mystery_disabled.png b/res/drawable/marker_cache_mystery_disabled.png
new file mode 100644
index 0000000..ea7b9fe
--- /dev/null
+++ b/res/drawable/marker_cache_mystery_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_mystery_found.png b/res/drawable/marker_cache_mystery_found.png
new file mode 100644
index 0000000..1ab1ffc
--- /dev/null
+++ b/res/drawable/marker_cache_mystery_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_mystery_own.png b/res/drawable/marker_cache_mystery_own.png
new file mode 100644
index 0000000..c34e0c5
--- /dev/null
+++ b/res/drawable/marker_cache_mystery_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_traditional.png b/res/drawable/marker_cache_traditional.png
new file mode 100644
index 0000000..01ea439
--- /dev/null
+++ b/res/drawable/marker_cache_traditional.png
Binary files differ
diff --git a/res/drawable/marker_cache_traditional_disabled.png b/res/drawable/marker_cache_traditional_disabled.png
new file mode 100644
index 0000000..139112c
--- /dev/null
+++ b/res/drawable/marker_cache_traditional_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_traditional_found.png b/res/drawable/marker_cache_traditional_found.png
new file mode 100644
index 0000000..ca12c03
--- /dev/null
+++ b/res/drawable/marker_cache_traditional_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_traditional_own.png b/res/drawable/marker_cache_traditional_own.png
new file mode 100644
index 0000000..3fb647b
--- /dev/null
+++ b/res/drawable/marker_cache_traditional_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_virtual.png b/res/drawable/marker_cache_virtual.png
new file mode 100644
index 0000000..be75ce6
--- /dev/null
+++ b/res/drawable/marker_cache_virtual.png
Binary files differ
diff --git a/res/drawable/marker_cache_virtual_disabled.png b/res/drawable/marker_cache_virtual_disabled.png
new file mode 100644
index 0000000..7c933e9
--- /dev/null
+++ b/res/drawable/marker_cache_virtual_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_virtual_found.png b/res/drawable/marker_cache_virtual_found.png
new file mode 100644
index 0000000..69accd6
--- /dev/null
+++ b/res/drawable/marker_cache_virtual_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_virtual_own.png b/res/drawable/marker_cache_virtual_own.png
new file mode 100644
index 0000000..dfaa535
--- /dev/null
+++ b/res/drawable/marker_cache_virtual_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_webcam.png b/res/drawable/marker_cache_webcam.png
new file mode 100644
index 0000000..212848b
--- /dev/null
+++ b/res/drawable/marker_cache_webcam.png
Binary files differ
diff --git a/res/drawable/marker_cache_webcam_disabled.png b/res/drawable/marker_cache_webcam_disabled.png
new file mode 100644
index 0000000..341544a
--- /dev/null
+++ b/res/drawable/marker_cache_webcam_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_webcam_found.png b/res/drawable/marker_cache_webcam_found.png
new file mode 100644
index 0000000..f08b721
--- /dev/null
+++ b/res/drawable/marker_cache_webcam_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_webcam_own.png b/res/drawable/marker_cache_webcam_own.png
new file mode 100644
index 0000000..c8ba409
--- /dev/null
+++ b/res/drawable/marker_cache_webcam_own.png
Binary files differ
diff --git a/res/drawable/marker_cache_wherigo.png b/res/drawable/marker_cache_wherigo.png
new file mode 100644
index 0000000..e366d65
--- /dev/null
+++ b/res/drawable/marker_cache_wherigo.png
Binary files differ
diff --git a/res/drawable/marker_cache_wherigo_disabled.png b/res/drawable/marker_cache_wherigo_disabled.png
new file mode 100644
index 0000000..6729b4c
--- /dev/null
+++ b/res/drawable/marker_cache_wherigo_disabled.png
Binary files differ
diff --git a/res/drawable/marker_cache_wherigo_found.png b/res/drawable/marker_cache_wherigo_found.png
new file mode 100644
index 0000000..debd765
--- /dev/null
+++ b/res/drawable/marker_cache_wherigo_found.png
Binary files differ
diff --git a/res/drawable/marker_cache_wherigo_own.png b/res/drawable/marker_cache_wherigo_own.png
new file mode 100644
index 0000000..d50e419
--- /dev/null
+++ b/res/drawable/marker_cache_wherigo_own.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_flag.png b/res/drawable/marker_waypoint_flag.png
new file mode 100644
index 0000000..8196707
--- /dev/null
+++ b/res/drawable/marker_waypoint_flag.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_pkg.png b/res/drawable/marker_waypoint_pkg.png
new file mode 100644
index 0000000..71ea97a
--- /dev/null
+++ b/res/drawable/marker_waypoint_pkg.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_puzzle.png b/res/drawable/marker_waypoint_puzzle.png
new file mode 100644
index 0000000..42d9842
--- /dev/null
+++ b/res/drawable/marker_waypoint_puzzle.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_stage.png b/res/drawable/marker_waypoint_stage.png
new file mode 100644
index 0000000..dae742e
--- /dev/null
+++ b/res/drawable/marker_waypoint_stage.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_trailhead.png b/res/drawable/marker_waypoint_trailhead.png
new file mode 100644
index 0000000..3db756f
--- /dev/null
+++ b/res/drawable/marker_waypoint_trailhead.png
Binary files differ
diff --git a/res/drawable/marker_waypoint_waypoint.png b/res/drawable/marker_waypoint_waypoint.png
new file mode 100644
index 0000000..50974d3
--- /dev/null
+++ b/res/drawable/marker_waypoint_waypoint.png
Binary files differ
diff --git a/res/drawable/my_location.png b/res/drawable/my_location.png
new file mode 100644
index 0000000..cdb58c7
--- /dev/null
+++ b/res/drawable/my_location.png
Binary files differ
diff --git a/res/drawable/my_location_arrow.png b/res/drawable/my_location_arrow.png
new file mode 100644
index 0000000..c8401d2
--- /dev/null
+++ b/res/drawable/my_location_arrow.png
Binary files differ
diff --git a/res/drawable/my_location_chevron.png b/res/drawable/my_location_chevron.png
new file mode 100644
index 0000000..67b863f
--- /dev/null
+++ b/res/drawable/my_location_chevron.png
Binary files differ
diff --git a/res/drawable/my_location_off.png b/res/drawable/my_location_off.png
new file mode 100644
index 0000000..0266600
--- /dev/null
+++ b/res/drawable/my_location_off.png
Binary files differ
diff --git a/res/drawable/my_location_on.png b/res/drawable/my_location_on.png
new file mode 100644
index 0000000..04bec8f
--- /dev/null
+++ b/res/drawable/my_location_on.png
Binary files differ
diff --git a/res/drawable/separator_dark.xml b/res/drawable/separator_dark.xml
new file mode 100644
index 0000000..ece89e1
--- /dev/null
+++ b/res/drawable/separator_dark.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#22FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/separator_light.xml b/res/drawable/separator_light.xml
new file mode 100644
index 0000000..f57780a
--- /dev/null
+++ b/res/drawable/separator_light.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid
+ android:color="#22000000" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/star_half.png b/res/drawable/star_half.png
new file mode 100644
index 0000000..17eeaf7
--- /dev/null
+++ b/res/drawable/star_half.png
Binary files differ
diff --git a/res/drawable/star_off.png b/res/drawable/star_off.png
new file mode 100644
index 0000000..a7e0c83
--- /dev/null
+++ b/res/drawable/star_off.png
Binary files differ
diff --git a/res/drawable/star_on.png b/res/drawable/star_on.png
new file mode 100644
index 0000000..801928a
--- /dev/null
+++ b/res/drawable/star_on.png
Binary files differ
diff --git a/res/drawable/trackable_all.png b/res/drawable/trackable_all.png
new file mode 100644
index 0000000..8c830d4
--- /dev/null
+++ b/res/drawable/trackable_all.png
Binary files differ
diff --git a/res/drawable/type_ape.png b/res/drawable/type_ape.png
new file mode 100644
index 0000000..3487013
--- /dev/null
+++ b/res/drawable/type_ape.png
Binary files differ
diff --git a/res/drawable/type_cito.png b/res/drawable/type_cito.png
new file mode 100644
index 0000000..56f0e5f
--- /dev/null
+++ b/res/drawable/type_cito.png
Binary files differ
diff --git a/res/drawable/type_earth.png b/res/drawable/type_earth.png
new file mode 100644
index 0000000..356b3b8
--- /dev/null
+++ b/res/drawable/type_earth.png
Binary files differ
diff --git a/res/drawable/type_event.png b/res/drawable/type_event.png
new file mode 100644
index 0000000..93b60fe
--- /dev/null
+++ b/res/drawable/type_event.png
Binary files differ
diff --git a/res/drawable/type_hq.png b/res/drawable/type_hq.png
new file mode 100644
index 0000000..e4f700a
--- /dev/null
+++ b/res/drawable/type_hq.png
Binary files differ
diff --git a/res/drawable/type_letterbox.png b/res/drawable/type_letterbox.png
new file mode 100644
index 0000000..52348f2
--- /dev/null
+++ b/res/drawable/type_letterbox.png
Binary files differ
diff --git a/res/drawable/type_locationless.png b/res/drawable/type_locationless.png
new file mode 100644
index 0000000..50fc83d
--- /dev/null
+++ b/res/drawable/type_locationless.png
Binary files differ
diff --git a/res/drawable/type_mega.png b/res/drawable/type_mega.png
new file mode 100644
index 0000000..9551892
--- /dev/null
+++ b/res/drawable/type_mega.png
Binary files differ
diff --git a/res/drawable/type_multi.png b/res/drawable/type_multi.png
new file mode 100644
index 0000000..5bcfd31
--- /dev/null
+++ b/res/drawable/type_multi.png
Binary files differ
diff --git a/res/drawable/type_mystery.png b/res/drawable/type_mystery.png
new file mode 100644
index 0000000..f462d5d
--- /dev/null
+++ b/res/drawable/type_mystery.png
Binary files differ
diff --git a/res/drawable/type_traditional.png b/res/drawable/type_traditional.png
new file mode 100644
index 0000000..e3e1a4b
--- /dev/null
+++ b/res/drawable/type_traditional.png
Binary files differ
diff --git a/res/drawable/type_virtual.png b/res/drawable/type_virtual.png
new file mode 100644
index 0000000..14bc704
--- /dev/null
+++ b/res/drawable/type_virtual.png
Binary files differ
diff --git a/res/drawable/type_webcam.png b/res/drawable/type_webcam.png
new file mode 100644
index 0000000..922fddd
--- /dev/null
+++ b/res/drawable/type_webcam.png
Binary files differ
diff --git a/res/drawable/type_wherigo.png b/res/drawable/type_wherigo.png
new file mode 100644
index 0000000..96318f6
--- /dev/null
+++ b/res/drawable/type_wherigo.png
Binary files differ
diff --git a/res/drawable/user_location.png b/res/drawable/user_location.png
new file mode 100644
index 0000000..e1bde6e
--- /dev/null
+++ b/res/drawable/user_location.png
Binary files differ
diff --git a/res/drawable/user_location_active.png b/res/drawable/user_location_active.png
new file mode 100644
index 0000000..d7d22d2
--- /dev/null
+++ b/res/drawable/user_location_active.png
Binary files differ
diff --git a/res/drawable/waypoint_flag.png b/res/drawable/waypoint_flag.png
new file mode 100644
index 0000000..123ec84
--- /dev/null
+++ b/res/drawable/waypoint_flag.png
Binary files differ
diff --git a/res/drawable/waypoint_pkg.png b/res/drawable/waypoint_pkg.png
new file mode 100644
index 0000000..1a901f0
--- /dev/null
+++ b/res/drawable/waypoint_pkg.png
Binary files differ
diff --git a/res/drawable/waypoint_puzzle.png b/res/drawable/waypoint_puzzle.png
new file mode 100644
index 0000000..a659f36
--- /dev/null
+++ b/res/drawable/waypoint_puzzle.png
Binary files differ
diff --git a/res/drawable/waypoint_stage.png b/res/drawable/waypoint_stage.png
new file mode 100644
index 0000000..52e0481
--- /dev/null
+++ b/res/drawable/waypoint_stage.png
Binary files differ
diff --git a/res/drawable/waypoint_trailhead.png b/res/drawable/waypoint_trailhead.png
new file mode 100644
index 0000000..1aca26f
--- /dev/null
+++ b/res/drawable/waypoint_trailhead.png
Binary files differ
diff --git a/res/drawable/waypoint_waypoint.png b/res/drawable/waypoint_waypoint.png
new file mode 100644
index 0000000..91b69a9
--- /dev/null
+++ b/res/drawable/waypoint_waypoint.png
Binary files differ
diff --git a/res/layout/about.xml b/res/layout/about.xml
new file mode 100644
index 0000000..e32445e
--- /dev/null
+++ b/res/layout/about.xml
@@ -0,0 +1,218 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <ImageView
+ android:layout_width="200dip"
+ android:layout_height="200dip"
+ android:layout_margin="10dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/carnero_logo" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginTop="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/quote" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="right"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/powered_by" />
+ </LinearLayout>
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/about_donate" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal" >
+ <Button style="@style/button"
+ android:id="@+id/donation_more"
+ android:layout_width="180dip"
+ android:singleLine="false"
+ android:lines="2"
+ android:onClick="donateMore"
+ android:text="@string/about_donation_more" />
+ <Button style="@style/button"
+ android:id="@+id/donation_less"
+ android:layout_width="100dip"
+ android:singleLine="false"
+ android:lines="2"
+ android:onClick="donateLess"
+ android:text="@string/about_donation_less" />
+ </LinearLayout>
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/about_detail" />
+ </RelativeLayout>
+ <TextView android:id="@+id/author"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="author"
+ android:text="@string/author" />
+ <TextView android:id="@+id/support"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="support"
+ android:text="@string/support" />
+ <TextView android:id="@+id/website"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="website"
+ android:text="@string/website" />
+ <TextView android:id="@+id/facebook"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="facebook"
+ android:text="@string/facebook" />
+ <TextView android:id="@+id/twitter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="twitter"
+ android:text="@string/twitter" />
+ <TextView android:id="@+id/nutshellmanual"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="false"
+ android:focusable="true"
+ android:clickable="true"
+ android:onClick="nutshellmanual"
+ android:text="@string/nutshellmanual" />
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/about_contributors" />
+ </RelativeLayout>
+ <TextView android:id="@+id/contributors"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="7dip"
+ android:layout_gravity="left"
+ android:paddingLeft="3dip"
+ android:textSize="14dip"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link"
+ android:textColor="?text_color"
+ android:text="@string/contributors" />
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/about_changelog" />
+ </RelativeLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="7dip"
+ android:layout_gravity="left"
+ android:paddingLeft="3dip"
+ android:textSize="12dip"
+ android:textColor="?text_color"
+ android:text="@string/changelog" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/address_button.xml b/res/layout/address_button.xml
new file mode 100644
index 0000000..5369282
--- /dev/null
+++ b/res/layout/address_button.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_map"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:padding="5dip" >
+ <Button style="@style/button"
+ android:id="@+id/button"
+ android:singleLine="false"
+ android:gravity="left" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/addresses.xml b/res/layout/addresses.xml
new file mode 100644
index 0000000..286a0f0
--- /dev/null
+++ b/res/layout/addresses.xml
@@ -0,0 +1,24 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/address_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/auth.xml b/res/layout/auth.xml
new file mode 100644
index 0000000..ff4cc2f
--- /dev/null
+++ b/res/layout/auth.xml
@@ -0,0 +1,86 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="7dip" >
+ <ImageView
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:maxWidth="64dip"
+ android:maxHeight="64dip"
+ android:scaleType="fitXY"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="7dip"
+ android:layout_marginBottom="7dip"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:src="@drawable/icon_big" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left|center_vertical"
+ android:gravity="left|center_vertical"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/about_auth_1" />
+ </LinearLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="left|center_vertical"
+ android:gravity="left|center_vertical"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/about_auth_2" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="7dip" >
+ <Button style="@style/button"
+ android:id="@+id/start"
+ android:text="@string/auth_authorize" />
+ <EditText style="@style/edittext"
+ android:id="@+id/pin"
+ android:visibility="gone"
+ android:inputType="number"
+ android:hint="@string/auth_pin_hint" />
+ <Button style="@style/button"
+ android:id="@+id/pin_button"
+ android:visibility="gone"
+ android:text="@string/auth_finish" />
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/cache.xml b/res/layout/cache.xml
new file mode 100644
index 0000000..6c7de6b
--- /dev/null
+++ b/res/layout/cache.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cc="http://schemas.android.com/apk/res/cgeo.geocaching"
+ android:id="@+id/one_cache"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?background_color" >
+ <RelativeLayout android:id="@+id/one_checkbox"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:paddingBottom="7dip"
+ android:paddingTop="7dip"
+ android:background="?background_color" >
+ <CheckBox android:id="@+id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="5dip"
+ android:gravity="left|center_horizontal" />
+ </RelativeLayout>
+ <RelativeLayout android:id="@+id/one_info"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:paddingBottom="7dip"
+ android:paddingTop="7dip"
+ android:background="?background_color" >
+ <ImageView android:id="@+id/found_mark"
+ android:visibility="gone"
+ android:layout_width="2dip"
+ android:layout_height="30dip"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:scaleType="fitXY"
+ android:src="@drawable/mark_green" />
+ <ImageView android:id="@+id/offline_mark"
+ android:visibility="gone"
+ android:layout_width="4dip"
+ android:layout_height="30dip"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:scaleType="fitXY"
+ android:src="@drawable/mark_red" />
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="110dip"
+ android:layout_marginLeft="10px"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:paddingRight="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="18dip"
+ android:textColor="?text_color" />
+ <TextView android:id="@+id/info"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="28dip"
+ android:layout_marginRight="110dip"
+ android:layout_marginLeft="10dip"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:paddingRight="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="?text_color_grey" />
+ <RelativeLayout android:id="@+id/direction_layout"
+ android:visibility="gone"
+ android:layout_width="78dip"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="1dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="30dip" >
+ <view class="cgeo.geocaching.cgDistanceView"
+ android:id="@+id/distance"
+ android:layout_width="78dip"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="16dip"
+ android:textColor="?text_color"
+ android:gravity="center" />
+ <view class="cgeo.geocaching.cgCompassMini"
+ android:id="@+id/direction"
+ android:layout_width="78dip"
+ android:layout_height="28px"
+ android:layout_marginTop="21dip"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center"
+ android:minWidth="28px"
+ android:minHeight="28px"
+ android:gravity="center"
+ cc:skin="?compass" />
+ </RelativeLayout>
+ <RelativeLayout android:id="@+id/dirimg_layout"
+ android:visibility="gone"
+ android:layout_width="78dip"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="1dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="30dip" >
+ <ImageView android:id="@+id/dirimg"
+ android:layout_width="55dip"
+ android:layout_height="30dip"
+ android:layout_centerInParent="true"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@null" />
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="28dip"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginTop="1dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="2dip" >
+ <RelativeLayout android:id="@+id/inventory"
+ android:visibility="gone"
+ android:layout_width="28dip"
+ android:layout_height="22dip"
+ android:layout_marginTop="2dip"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_gravity="center"
+ android:background="?inventory" >
+ </RelativeLayout>
+ <TextView android:id="@+id/favourite"
+ android:layout_width="28dip"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dip"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:paddingLeft="3dip"
+ android:paddingRight="3dip"
+ android:paddingBottom="1dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textStyle="bold"
+ android:background="?favourite"
+ android:textColor="?text_color" />
+ </RelativeLayout>
+ </RelativeLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/cache_item.xml b/res/layout/cache_item.xml
new file mode 100644
index 0000000..34f91cd
--- /dev/null
+++ b/res/layout/cache_item.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="3dip" >
+ <TextView android:id="@+id/name"
+ android:layout_width="80dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left|top"
+ android:layout_marginRight="4dip"
+ android:gravity="right"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="end"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ <TextView android:id="@+id/value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="2dip"
+ android:layout_marginLeft="83dip"
+ android:layout_marginRight="6dip"
+ android:layout_gravity="left|top"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/cache_layout.xml b/res/layout/cache_layout.xml
new file mode 100644
index 0000000..59507eb
--- /dev/null
+++ b/res/layout/cache_layout.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="3dip" >
+ <TextView android:id="@+id/name"
+ android:layout_width="80dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left|top"
+ android:layout_marginRight="4dip"
+ android:gravity="right"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="end"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ <LinearLayout android:id="@+id/stars"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="2dip"
+ android:layout_marginLeft="83dip"
+ android:layout_marginRight="6dip"
+ android:layout_gravity="left|top" >
+ <TextView android:id="@+id/value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="5dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <TextView android:id="@+id/addition"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:textSize="11dip"
+ android:textColor="?text_color_grey" />
+ </LinearLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/caches.xml b/res/layout/caches.xml
new file mode 100644
index 0000000..5dcd500
--- /dev/null
+++ b/res/layout/caches.xml
@@ -0,0 +1,45 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title"
+ android:clickable="true"
+ android:onClick="selectList" />
+ <ProgressBar style="@style/action_bar_progress"
+ android:visibility="gone" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_map"
+ android:onClick="goMap" />
+ <View style="@style/action_bar_separator" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ListView android:id="@android:id/list"
+ android:visibility="gone"
+ android:layout_above="@+id/counter"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_margin="0dip"
+ android:padding="0dip"
+ android:dividerHeight="1dip"
+ android:background="?background_color"
+ android:cacheColorHint="?background_color" />
+ <RelativeLayout android:id="@+id/loading"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="5dip" >
+ <ProgressBar style="@android:style/Widget.ProgressBar.Large.Inverse"
+ android:layout_width="76dip"
+ android:layout_height="76dip"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ android:indeterminate="true" />
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/caches_footer.xml b/res/layout/caches_footer.xml
new file mode 100644
index 0000000..5042688
--- /dev/null
+++ b/res/layout/caches_footer.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/more_caches"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="8dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="16dip"
+ android:textColor="@color/just_white"
+ android:text="@string/caches_no_cache"
+ android:background="@drawable/list_footer_background" /> \ No newline at end of file
diff --git a/res/layout/date.xml b/res/layout/date.xml
new file mode 100644
index 0000000..4ea2fb1
--- /dev/null
+++ b/res/layout/date.xml
@@ -0,0 +1,9 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <DatePicker android:id="@+id/picker"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dip" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/detail.xml b/res/layout/detail.xml
new file mode 100644
index 0000000..0cb6881
--- /dev/null
+++ b/res/layout/detail.xml
@@ -0,0 +1,231 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_compass"
+ android:onClick="goCompass" />
+ <View style="@style/action_bar_separator" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView android:id="@+id/details_list_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ <ImageView android:id="@+id/map_preview"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="80dip"
+ android:layout_gravity="center"
+ android:layout_marginBottom="5dip"
+ android:gravity="center"
+ android:scaleType="centerCrop"
+ android:src="@null" />
+ <LinearLayout android:id="@+id/details_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ <LinearLayout android:id="@+id/offline_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_offline" />
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+ <TextView android:id="@+id/offline_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="130dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <Button style="@style/button_small"
+ android:id="@+id/offline_refresh"
+ android:visibility="gone"
+ android:layout_width="60dip"
+ android:layout_marginRight="71dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_offline_refresh" />
+ <Button style="@style/button_small"
+ android:id="@+id/offline_store"
+ android:layout_width="60dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_offline_store" />
+ </RelativeLayout>
+ </LinearLayout>
+ <LinearLayout android:id="@+id/attributes_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_attributes" />
+ </RelativeLayout>
+ <TextView android:id="@+id/attributes"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/inventory_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_inventory" />
+ </RelativeLayout>
+ <TextView android:id="@+id/inventory"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/desc_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_description" />
+ </RelativeLayout>
+ <TextView android:id="@+id/shortdesc"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ <TextView android:id="@+id/description"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dip"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ <Button style="@style/button_small"
+ android:id="@+id/show_description"
+ android:visibility="gone"
+ android:text="@string/cache_description_long" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/waypoints_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_waypoints" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/waypoints"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ <Button style="@style/button_small"
+ android:id="@+id/add_waypoint"
+ android:text="@string/cache_waypoints_add" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout android:id="@+id/hint_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_hint" />
+ </RelativeLayout>
+ <TextView android:id="@+id/hint"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/log_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_logs" />
+ </RelativeLayout>
+ <HorizontalScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="5dip"
+ android:paddingBottom="5dip" >
+ <TextView android:id="@+id/logcount"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ </HorizontalScrollView>
+ <LinearLayout android:id="@+id/log_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/googlemap.xml b/res/layout/googlemap.xml
new file mode 100644
index 0000000..330c185
--- /dev/null
+++ b/res/layout/googlemap.xml
@@ -0,0 +1,52 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ProgressBar style="@style/action_bar_progress"
+ android:visibility="gone" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ <TextView android:id="@+id/number"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:gravity="center_horizontal"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="@color/text_icon"
+ android:background="@drawable/icon_bcg" />
+ <view class="cgeo.geocaching.googlemaps.googleMapView" android:id="@+id/map"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:keepScreenOn="true"
+ android:enabled="true"
+ android:clickable="true"
+ android:apiKey="@string/maps_api_key" />
+ <ImageView android:id="@+id/my_position"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_margin="5dip"
+ android:padding="5dip"
+ android:src="@drawable/my_location_off" />
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/gpx.xml b/res/layout/gpx.xml
new file mode 100644
index 0000000..1c7bc81
--- /dev/null
+++ b/res/layout/gpx.xml
@@ -0,0 +1,22 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_margin="0dip"
+ android:padding="0dip"
+ android:dividerHeight="1dip"
+ android:background="?background_color"
+ android:cacheColorHint="?background_color" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/gpx_item.xml b/res/layout/gpx_item.xml
new file mode 100644
index 0000000..8c0ac7b
--- /dev/null
+++ b/res/layout/gpx_item.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/button_map"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_margin="3dip"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:paddingBottom="7dip"
+ android:paddingTop="7dip"
+ android:orientation="vertical"
+ android:background="?background_color" >
+ <TextView android:id="@+id/filepath"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollHorizontally="true"
+ android:textSize="12dip"
+ android:gravity="right"
+ android:lines="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?text_color_grey" />
+ <TextView android:id="@+id/filename"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollHorizontally="true"
+ android:textSize="22dip"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textColor="?text_color" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/helpers.xml b/res/layout/helpers.xml
new file mode 100644
index 0000000..aa43adf
--- /dev/null
+++ b/res/layout/helpers.xml
@@ -0,0 +1,185 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+<!-- ** -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical"
+ android:onClick="installManual" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/helper_manual_title" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:orientation="horizontal" >
+ <ImageView
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_margin="1dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/helper_manual" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/helper_manual_description" />
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical"
+ android:onClick="installLocus" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/helper_locus_title" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:orientation="horizontal" >
+ <ImageView
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_margin="1dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/helper_locus" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/helper_locus_description" />
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical"
+ android:onClick="installGpsStatus" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/helper_gpsstatus_title" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:orientation="horizontal" >
+ <ImageView
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_margin="1dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/helper_gpsstatus" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/helper_gpsstatus_description" />
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical"
+ android:onClick="installBluetoothGps" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/helper_bluetoothgps_title" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:orientation="horizontal" >
+ <ImageView
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_margin="1dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/helper_bluetoothgps" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/helper_bluetoothgps_description" />
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/image_item.xml b/res/layout/image_item.xml
new file mode 100644
index 0000000..6988d87
--- /dev/null
+++ b/res/layout/image_item.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/map_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center" /> \ No newline at end of file
diff --git a/res/layout/init.xml b/res/layout/init.xml
new file mode 100644
index 0000000..3f4d893
--- /dev/null
+++ b/res/layout/init.xml
@@ -0,0 +1,600 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_geocaching" />
+ </RelativeLayout>
+ <TextView android:id="@+id/legal_note"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/legal_note" />
+ <EditText style="@style/edittext"
+ android:id="@+id/username"
+ android:hint="@string/init_username" />
+ <EditText style="@style/edittext"
+ android:id="@+id/password"
+ android:hint="@string/init_password"
+ android:password="true" />
+ <Button style="@style/button"
+ android:id="@+id/log_me_in"
+ android:text="@string/init_login" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_gcvote" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/passvote"
+ android:hint="@string/init_passvote"
+ android:password="true" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_go4cache" />
+ </RelativeLayout>
+ <TextView android:id="@+id/about_go4cache"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/about_go4cache" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:orientation="horizontal"
+ android:padding="3dip" >
+ <CheckBox android:id="@+id/publicloc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_go4cache_connect" />
+ </LinearLayout>
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_twitter" />
+ </RelativeLayout>
+ <TextView android:id="@+id/about_twitter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/about_twitter" />
+ <Button style="@style/button"
+ android:id="@+id/authorize_twitter"
+ android:text="@string/init_twitter_authorize" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:orientation="horizontal"
+ android:padding="3dip" >
+ <CheckBox android:id="@+id/twitter_option"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_twitter_publish" />
+ </LinearLayout>
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_signature" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/signature"
+ android:hint="@string/init_signature"
+ android:singleLine="false"
+ android:lines="3"
+ android:scrollHorizontally="false" />
+ <LinearLayout android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:orientation="vertical" >
+ <Button style="@style/button"
+ android:id="@+id/signature_help"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textSize="14dip"
+ android:text="@string/init_signature_help_button" />
+ </LinearLayout>
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_other" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_margin="3dip"
+ android:orientation="vertical"
+ android:padding="3dip" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/skin"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_skin" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/address"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_address" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/captcha"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_captcha" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/useenglish"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_useenglish" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/exclude"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_exclude" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/disabled"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_disabled" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/offline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_offline" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/units"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_units" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/gnav"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_nav" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/autoload"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_autoload" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/livelist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_livelist" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <CheckBox android:id="@+id/browser"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/init_browser" />
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_altitude" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/altitude"
+ android:singleLine="true"
+ android:lines="1"
+ android:scrollHorizontally="true" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/init_altitude_description" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_mapsources" />
+ </RelativeLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/init_mapsources_description" />
+ <Spinner android:id="@+id/mapsource"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/init_mapsource_select" />
+ <EditText style="@style/edittext"
+ android:id="@+id/mapfile"
+ android:singleLine="true"
+ android:lines="1"
+ android:scrollHorizontally="true" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_sendToCgeo" />
+ </RelativeLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/init_sendToCgeo_name" />
+ <EditText style="@style/edittext"
+ android:id="@+id/webDeviceName"
+ android:singleLine="true"
+ android:lines="1"
+ android:maxLength="15"
+ android:scrollHorizontally="true" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/init_sendToCgeo_description" />
+ <Button style="@style/button"
+ android:id="@+id/sendToCgeo_register"
+ android:text="@string/init_sendToCgeo_register" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/init_backup" />
+ </RelativeLayout>
+ <TextView android:id="@+id/backup_last"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@null" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="3dip"
+ android:orientation="horizontal"
+ android:padding="3dip" >
+ <Button style="@style/button"
+ android:id="@+id/backup_backup"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="@string/init_backup_backup"
+ android:onClick="backup" />
+ <Button style="@style/button"
+ android:id="@+id/backup_restore"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="@string/init_backup_restore"
+ android:onClick="restore" />
+ </LinearLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:textColorLink="?text_color_link"
+ android:linksClickable="true"
+ android:text="@string/init_backup_note" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/list_create_dialog.xml b/res/layout/list_create_dialog.xml
new file mode 100644
index 0000000..b805249
--- /dev/null
+++ b/res/layout/list_create_dialog.xml
@@ -0,0 +1,8 @@
+<?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" >
+ <EditText style="@style/edittext_dialog"
+ android:id="@+id/text" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/log_item.xml b/res/layout/log_item.xml
new file mode 100644
index 0000000..3af56e0
--- /dev/null
+++ b/res/layout/log_item.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="3dip" >
+ <TextView android:id="@+id/author"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_gravity="left|top"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="18dip"
+ android:textColor="?text_color" />
+ <LinearLayout
+ android:layout_width="82dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="22dip"
+ android:layout_gravity="left|top"
+ android:orientation="horizontal" >
+ <LinearLayout
+ android:layout_width="80dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|top"
+ android:padding="3dip"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/added"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ <TextView android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ <TextView android:id="@+id/count"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ </LinearLayout>
+ <ImageView android:id="@+id/found_mark"
+ android:visibility="gone"
+ android:layout_width="2dip"
+ android:layout_height="fill_parent"
+ android:layout_centerVertical="true"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:scaleType="fitXY"
+ android:src="@drawable/mark_green" />
+ <ImageView android:id="@+id/dnf_mark"
+ android:visibility="gone"
+ android:layout_width="2dip"
+ android:layout_height="fill_parent"
+ android:layout_centerVertical="true"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:scaleType="fitXY"
+ android:src="@drawable/mark_red" />
+ <ImageView android:id="@+id/disabled_mark"
+ android:visibility="gone"
+ android:layout_width="2dip"
+ android:layout_height="fill_parent"
+ android:layout_centerVertical="true"
+ android:layout_marginTop="2dip"
+ android:layout_marginBottom="2dip"
+ android:scaleType="fitXY"
+ android:src="@drawable/mark_red_more" />
+ </LinearLayout>
+ <TextView android:id="@+id/log"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="22dip"
+ android:layout_marginLeft="82dip"
+ android:layout_gravity="left"
+ android:gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644
index 0000000..012612f
--- /dev/null
+++ b/res/layout/main.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/mainscreen"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_icon_cgeo"
+ android:onClick="showAbout" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_search"
+ android:onClick="goSearch" />
+ <View style="@style/action_bar_separator" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="45dip"
+ android:layout_centerInParent="true"
+ android:gravity="center"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_margin="4dip"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal" >
+ <LinearLayout android:id="@+id/map"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip"
+ android:orientation="vertical" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_live" />
+ <TextView
+ style="@style/icon_mainscreen_text"
+ android:text="@string/live_map_button" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/nearest"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip"
+ android:orientation="vertical" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_nearby" />
+ <TextView
+ style="@style/icon_mainscreen_text"
+ android:text="@string/caches_nearby_button" />
+ </LinearLayout>
+ <RelativeLayout android:id="@+id/search_offline"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip" >
+ <TextView android:id="@+id/offline_count"
+ style="@style/icon_mainscreen_count" />
+ <LinearLayout
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_alignParentTop="true" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_stored" />
+ <TextView
+ style="@style/icon_mainscreen_text"
+ android:text="@string/stored_caches_button" />
+ </LinearLayout>
+ </RelativeLayout>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_margin="4dip"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal" >
+ <LinearLayout android:id="@+id/advanced_button"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip"
+ android:orientation="vertical" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_search" />
+ <TextView
+ style="@style/icon_mainscreen_text"
+ android:text="@string/advanced_search_button" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/any_button"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip"
+ android:orientation="vertical" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_any" />
+ <TextView
+ style="@style/icon_mainscreen_text"
+ android:text="@string/any_button" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/filter_button"
+ android:layout_width="74dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dip"
+ android:orientation="vertical" >
+ <View
+ style="@style/icon_mainscreen"
+ android:background="@drawable/main_filter" />
+ <TextView android:id="@+id/filter_button_title"
+ style="@style/icon_mainscreen_text"
+ android:text="@null" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+<!-- ** -->
+ <RelativeLayout android:id="@+id/helper"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:layout_marginBottom="48dip"
+ android:background="@drawable/helper_bcg" >
+ <ImageView
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:layout_margin="4dip"
+ android:scaleType="center"
+ android:src="@drawable/actionbar_manual" />
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="34dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="4dip"
+ android:textSize="14dip"
+ android:textColor="@color/text_icon"
+ android:text="@string/helper" />
+ </RelativeLayout>
+<!-- ** -->
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
+ android:orientation="vertical">
+ <TextView android:id="@+id/nav_location"
+ style="@style/location_current"
+ android:text="@string/loc_trying" />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="16dip" >
+ <TextView android:id="@+id/nav_type"
+ style="@style/location_current_type" />
+ <TextView android:id="@+id/nav_accuracy"
+ style="@style/location_current_accuracy" />
+ <TextView android:id="@+id/nav_satellites"
+ style="@style/location_current_satellites" />
+ </RelativeLayout>
+ </LinearLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/map_static.xml b/res/layout/map_static.xml
new file mode 100644
index 0000000..410ad3f
--- /dev/null
+++ b/res/layout/map_static.xml
@@ -0,0 +1,24 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/maps_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/map_static_item.xml b/res/layout/map_static_item.xml
new file mode 100644
index 0000000..057ff72
--- /dev/null
+++ b/res/layout/map_static_item.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/map_image"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:scaleType="centerCrop"
+ android:padding="3dip"
+ android:gravity="center" /> \ No newline at end of file
diff --git a/res/layout/mfmap.xml b/res/layout/mfmap.xml
new file mode 100644
index 0000000..addf0ed
--- /dev/null
+++ b/res/layout/mfmap.xml
@@ -0,0 +1,51 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ProgressBar style="@style/action_bar_progress"
+ android:visibility="gone" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ <TextView android:id="@+id/number"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:gravity="center_horizontal"
+ android:paddingLeft="5dip"
+ android:paddingRight="5dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="@color/text_icon"
+ android:background="@drawable/icon_bcg" />
+ <view class="cgeo.geocaching.mapsforge.mfMapView" android:id="@+id/mfmap"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:keepScreenOn="true"
+ android:enabled="true"
+ android:clickable="true" />
+ <ImageView android:id="@+id/my_position"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_margin="5dip"
+ android:padding="5dip"
+ android:src="@drawable/my_location_off" />
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/navigate.xml b/res/layout/navigate.xml
new file mode 100644
index 0000000..f8b52d4
--- /dev/null
+++ b/res/layout/navigate.xml
@@ -0,0 +1,90 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+ <TextView android:id="@+id/destination"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="destination" />
+ <TextView android:id="@+id/heading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginLeft="3dip"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:textSize="26dip"
+ android:textColor="?text_color"
+ android:text="@null" />
+ <TextView android:id="@+id/distance"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginRight="3dip"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="right"
+ android:textSize="26dip"
+ android:textColor="?text_color"
+ android:text="@null" />
+ <view class="cgeo.geocaching.cgCompass"
+ android:id="@+id/rose"
+ android:layout_width="fill_parent"
+ android:layout_height="295dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginRight="1dip"
+ android:layout_marginLeft="1dip"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerInParent="true"
+ android:keepScreenOn="true"
+ android:gravity="center"
+ android:padding="4dip"
+ android:minWidth="289dip"
+ android:minHeight="289dip" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
+ android:orientation="vertical">
+ <TextView android:id="@+id/nav_location"
+ style="@style/location_current"
+ android:text="@string/loc_trying" />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="16dip" >
+ <TextView android:id="@+id/nav_type"
+ style="@style/location_current_type"
+ android:textColor="?text_color_grey" />
+ <TextView android:id="@+id/nav_accuracy"
+ style="@style/location_current_accuracy"
+ android:textColor="?text_color_grey" />
+ <TextView android:id="@+id/nav_satellites"
+ style="@style/location_current_satellites"
+ android:textColor="?text_color_grey" />
+ </RelativeLayout>
+ </LinearLayout>
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/point.xml b/res/layout/point.xml
new file mode 100644
index 0000000..701c21c
--- /dev/null
+++ b/res/layout/point.xml
@@ -0,0 +1,53 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_coordinates" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/latitude"
+ android:hint="latitude" />
+ <EditText style="@style/edittext"
+ android:id="@+id/longitude"
+ android:hint="longitude" />
+ <Button style="@style/button"
+ android:id="@+id/current"
+ android:text="@string/waypoint_my_coordinates" />
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_direction_rel" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/bearing"
+ android:inputType="numberDecimal"
+ android:hint="@string/waypoint_bearing" />
+ <EditText style="@style/edittext"
+ android:id="@+id/distance"
+ android:hint="@string/waypoint_distance" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/popup.xml b/res/layout/popup.xml
new file mode 100644
index 0000000..2ed587c
--- /dev/null
+++ b/res/layout/popup.xml
@@ -0,0 +1,74 @@
+<?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"
+ android:background="?background_color_transparent" >
+ <LinearLayout style="@style/action_bar">
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_compass"
+ android:onClick="goCompass" />
+ </LinearLayout>
+ <ScrollView android:id="@+id/details_list_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/details_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ <LinearLayout android:id="@+id/more_details_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <Button style="@style/button_small"
+ android:id="@+id/more_details"
+ android:text="@string/popup_more" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/offline_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+ <TextView android:id="@+id/offline_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="130dip"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <Button style="@style/button_small"
+ android:id="@+id/offline_refresh"
+ android:visibility="gone"
+ android:layout_width="60dip"
+ android:layout_marginRight="71dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_offline_refresh" />
+ <Button style="@style/button_small"
+ android:id="@+id/offline_store"
+ android:layout_width="60dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/cache_offline_store" />
+ </RelativeLayout>
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/recaptcha_dialog.xml b/res/layout/recaptcha_dialog.xml
new file mode 100644
index 0000000..47a63ca
--- /dev/null
+++ b/res/layout/recaptcha_dialog.xml
@@ -0,0 +1,28 @@
+<?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" >
+ <ImageView android:id="@+id/image"
+ android:layout_width="220dip"
+ android:layout_height="42dip"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@null" />
+ <EditText style="@style/edittext_dialog"
+ android:id="@+id/text"
+ android:hint="@string/caches_recaptcha_hint"
+ android:inputType="textNoSuggestions" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="7dip"
+ android:layout_gravity="left"
+ android:paddingLeft="3dip"
+ android:textSize="12dip"
+ android:textColor="@color/text_grey_dark"
+ android:text="@string/caches_recaptcha_explanation" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/search.xml b/res/layout/search.xml
new file mode 100644
index 0000000..e845246
--- /dev/null
+++ b/res/layout/search.xml
@@ -0,0 +1,131 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_coordinates" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/latitude"
+ android:hint="latitude"
+ android:imeOptions="actionGo" />
+ <EditText style="@style/edittext"
+ android:id="@+id/longitude"
+ android:hint="longitude"
+ android:imeOptions="actionGo" />
+ <Button style="@style/button"
+ android:id="@+id/search_coordinates"
+ android:text="@string/search_coordinates_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_address" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/address"
+ android:hint="@string/search_address"
+ android:imeOptions="actionGo" />
+ <Button style="@style/button"
+ android:id="@+id/search_address"
+ android:text="@string/search_address_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_gc" />
+ </RelativeLayout>
+ <AutoCompleteTextView style="@style/edittext"
+ android:id="@+id/geocode"
+ android:hint="@string/search_gc"
+ android:imeOptions="actionGo"
+ android:text="GC"
+ android:inputType="textCapCharacters" />
+ <Button style="@style/button"
+ android:id="@+id/display_geocode"
+ android:text="@string/search_gc_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_kw" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/keyword"
+ android:hint="@string/search_kw_prefill"
+ android:imeOptions="actionGo" />
+ <Button style="@style/button"
+ android:id="@+id/search_keyword"
+ android:text="@string/search_kw_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_fbu" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/username"
+ android:hint="@string/search_fbu_prefill"
+ android:imeOptions="actionGo" />
+ <Button style="@style/button"
+ android:id="@+id/search_username"
+ android:text="@string/search_fbu_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_hbu" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/owner"
+ android:hint="@string/search_hbu_prefill"
+ android:imeOptions="actionGo" />
+ <Button style="@style/button"
+ android:id="@+id/search_owner"
+ android:text="@string/search_hbu_button" />
+<!-- ** -->
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/search_tb" />
+ </RelativeLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/trackable"
+ android:hint="@string/search_tb_hint"
+ android:imeOptions="actionGo"
+ android:inputType="textCapCharacters" />
+ <Button style="@style/button"
+ android:id="@+id/display_trackable"
+ android:text="@string/search_tb_button" />
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/spoiler_item.xml b/res/layout/spoiler_item.xml
new file mode 100644
index 0000000..9913a8f
--- /dev/null
+++ b/res/layout/spoiler_item.xml
@@ -0,0 +1,20 @@
+<?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:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:id="@+id/title"
+ android:text="@null" />
+ </RelativeLayout>
+ <TextView android:id="@+id/description"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/spoilers.xml b/res/layout/spoilers.xml
new file mode 100644
index 0000000..ef6bb39
--- /dev/null
+++ b/res/layout/spoilers.xml
@@ -0,0 +1,24 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/spoiler_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/star.xml b/res/layout/star.xml
new file mode 100644
index 0000000..d370ace
--- /dev/null
+++ b/res/layout/star.xml
@@ -0,0 +1,9 @@
+<?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_margin="1dip"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:scaleType="fitXY"
+ android:src="@drawable/star_off" />
diff --git a/res/layout/touch.xml b/res/layout/touch.xml
new file mode 100644
index 0000000..ed8c9e3
--- /dev/null
+++ b/res/layout/touch.xml
@@ -0,0 +1,89 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ProgressBar style="@style/action_bar_progress"
+ android:visibility="gone" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button style="@style/button"
+ android:id="@+id/type"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="type" />
+ <Button style="@style/button"
+ android:id="@+id/date"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="date" />
+ </LinearLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/tracking"
+ android:inputType="textCapCharacters"
+ android:hint="@string/trackable_code" />
+ <EditText style="@style/edittext"
+ android:id="@+id/log"
+ android:hint="log"
+ android:singleLine="false"
+ android:lines="5"
+ android:capitalize="sentences" />
+ <LinearLayout android:id="@+id/tweet_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:visibility="gone" >
+ <CheckBox android:id="@+id/tweet"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/visit_tweet" />
+ </LinearLayout>
+ <Button style="@style/button"
+ android:id="@+id/post"
+ android:text="@string/log_post" />
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/trackable_button.xml b/res/layout/trackable_button.xml
new file mode 100644
index 0000000..f06c703
--- /dev/null
+++ b/res/layout/trackable_button.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:padding="5dip" >
+ <Button style="@style/button"
+ android:id="@+id/button" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/trackable_detail.xml b/res/layout/trackable_detail.xml
new file mode 100644
index 0000000..5efe8a5
--- /dev/null
+++ b/res/layout/trackable_detail.xml
@@ -0,0 +1,107 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView android:id="@+id/details_list_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/details_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ <LinearLayout android:id="@+id/goal_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/trackable_goal" />
+ </RelativeLayout>
+ <TextView android:id="@+id/goal"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/details_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/trackable_details" />
+ </RelativeLayout>
+ <TextView android:id="@+id/details"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="10dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:linksClickable="true"
+ android:textColorLink="?text_color_link" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/image_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/trackable_image" />
+ </RelativeLayout>
+ <LinearLayout android:id="@+id/image"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dip"
+ android:padding="3dip"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout android:id="@+id/log_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_logs" />
+ </RelativeLayout>
+ <LinearLayout android:id="@+id/log_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/trackable_icon.xml b/res/layout/trackable_icon.xml
new file mode 100644
index 0000000..019918b
--- /dev/null
+++ b/res/layout/trackable_icon.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="22dip"
+ android:layout_height="22dip"
+ android:layout_gravity="center_vertical|center_horizontal"
+ android:layout_centerInParent="true"
+ android:scaleType="fitXY"
+ android:src="@drawable/trackable_all" />
diff --git a/res/layout/trackable_image.xml b/res/layout/trackable_image.xml
new file mode 100644
index 0000000..b1a685a
--- /dev/null
+++ b/res/layout/trackable_image.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/trackable_image"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:scaleType="center"
+ android:layout_marginBottom="3dip" /> \ No newline at end of file
diff --git a/res/layout/trackable_logitem.xml b/res/layout/trackable_logitem.xml
new file mode 100644
index 0000000..b006531
--- /dev/null
+++ b/res/layout/trackable_logitem.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="3dip" >
+ <TextView android:id="@+id/author"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_gravity="left|top"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="18dip"
+ android:textColor="?text_color" />
+ <LinearLayout
+ android:layout_width="102dip"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="22dip"
+ android:layout_gravity="left|top"
+ android:orientation="horizontal" >
+ <LinearLayout
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|top"
+ android:padding="3dip"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/added"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ <TextView android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ <TextView android:id="@+id/location"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color_headline" />
+ </LinearLayout>
+ </LinearLayout>
+ <TextView android:id="@+id/log"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="22dip"
+ android:layout_marginLeft="102dip"
+ android:layout_gravity="left"
+ android:gravity="left"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/trackables.xml b/res/layout/trackables.xml
new file mode 100644
index 0000000..832b13c
--- /dev/null
+++ b/res/layout/trackables.xml
@@ -0,0 +1,27 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout android:id="@+id/trackable_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/visit.xml b/res/layout/visit.xml
new file mode 100644
index 0000000..43e4209
--- /dev/null
+++ b/res/layout/visit.xml
@@ -0,0 +1,142 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ProgressBar style="@style/action_bar_progress"
+ android:visibility="gone" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button style="@style/button"
+ android:id="@+id/type"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="type" />
+ <Button style="@style/button"
+ android:id="@+id/date"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="date" />
+ </LinearLayout>
+ <EditText style="@style/edittext"
+ android:id="@+id/log"
+ android:hint="@string/log_new_log_text"
+ android:singleLine="false"
+ android:lines="5"
+ android:capitalize="sentences" />
+ <LinearLayout android:id="@+id/tweet_box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:visibility="gone" >
+ <CheckBox android:id="@+id/tweet"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:padding="1px"
+ android:gravity="center" />
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="left"
+ android:paddingRight="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@string/visit_tweet" />
+ </LinearLayout>
+ <Button style="@style/button"
+ android:id="@+id/post"
+ android:text="@string/log_post" />
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_log_offline" />
+ </RelativeLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button style="@style/button"
+ android:id="@+id/save"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="@string/log_save" />
+ <Button style="@style/button"
+ android:id="@+id/clear"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:text="@string/log_clear" />
+ </LinearLayout>
+ </LinearLayout>
+ <LinearLayout android:id="@+id/inventory_box"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dip"
+ android:layout_marginBottom="10dip"
+ android:orientation="vertical" >
+ <RelativeLayout style="@style/separator_horizontal_layout" >
+ <View style="@style/separator_horizontal" />
+ <TextView style="@style/separator_horizontal_headline"
+ android:text="@string/cache_inventory" />
+ </RelativeLayout>
+ <LinearLayout android:id="@+id/inventory"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+ </LinearLayout>
+ <LinearLayout android:id="@+id/inventory_changeall"
+ android:visibility="gone"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="right"
+ android:orientation="vertical" >
+ <Button style="@style/button"
+ android:visibility="gone"
+ android:id="@+id/changebutton"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="10dip"
+ android:layout_marginRight="10dip"
+ android:layout_marginBottom="5dip"
+ android:layout_alignParentRight="true"
+ android:gravity="right"
+ android:textSize="14dip"
+ android:text="@string/log_tb_changeall" />
+ </LinearLayout>
+ </LinearLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/visit_trackable.xml b/res/layout/visit_trackable.xml
new file mode 100644
index 0000000..2ad97a6
--- /dev/null
+++ b/res/layout/visit_trackable.xml
@@ -0,0 +1,53 @@
+<?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_marginBottom="5dip"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:paddingBottom="10dip"
+ android:orientation="horizontal" >
+ <LinearLayout android:id="@+id/info"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="2"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <TextView android:id="@+id/trackcode"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_gravity="left"
+ android:gravity="left"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ </LinearLayout>
+ <TextView android:id="@+id/action"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="right"
+ android:gravity="center"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+</LinearLayout>
diff --git a/res/layout/waypoint.xml b/res/layout/waypoint.xml
new file mode 100644
index 0000000..658c11a
--- /dev/null
+++ b/res/layout/waypoint.xml
@@ -0,0 +1,95 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:id="@+id/compass"
+ android:src="@drawable/actionbar_compass"
+ android:onClick="goCompass" />
+ <View style="@style/action_bar_separator"
+ android:id="@+id/separator"
+ />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <TextView android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ <TextView android:id="@+id/identification"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ </LinearLayout>
+ <TextView android:id="@+id/coordinates"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <TextView android:id="@+id/note"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:padding="3dip"
+ android:textSize="14dip"
+ android:textColor="?text_color" />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+ <Button style="@style/button_small"
+ android:id="@+id/delete"
+ android:visibility="gone"
+ android:layout_width="60dip"
+ android:layout_marginRight="71dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/waypoint_delete" />
+ <Button style="@style/button_small"
+ android:id="@+id/edit"
+ android:layout_width="60dip"
+ android:layout_alignParentRight="true"
+ android:text="@string/waypoint_edit" />
+ </RelativeLayout>
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/waypoint_item.xml b/res/layout/waypoint_item.xml
new file mode 100644
index 0000000..a2bffff
--- /dev/null
+++ b/res/layout/waypoint_item.xml
@@ -0,0 +1,57 @@
+<?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:orientation="vertical"
+ android:layout_marginBottom="3dip" >
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|top"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="14dip"
+ android:textColor="?text_color"
+ android:text="@null" />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:orientation="horizontal" >
+ <TextView android:id="@+id/type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ <TextView android:id="@+id/identification"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:padding="3dip"
+ android:lines="1"
+ android:singleLine="true"
+ android:scrollHorizontally="true"
+ android:ellipsize="marquee"
+ android:textSize="12dip"
+ android:textColor="?text_color_headline"
+ android:text="@null" />
+ </LinearLayout>
+ <TextView android:id="@+id/note"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:padding="3dip"
+ android:textSize="12dip"
+ android:textColor="?text_color" />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/waypoint_new.xml b/res/layout/waypoint_new.xml
new file mode 100644
index 0000000..1c8ac42
--- /dev/null
+++ b/res/layout/waypoint_new.xml
@@ -0,0 +1,56 @@
+<?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"
+ android:background="?background_color" >
+ <LinearLayout style="@style/action_bar">
+ <ImageView style="@style/action_bar_action"
+ android:onClick="goHome" />
+ <View style="@style/action_bar_separator" />
+ <TextView style="@style/action_bar_title" />
+ <ImageView style="@style/action_bar_action"
+ android:src="@drawable/actionbar_manual"
+ android:onClick="goManual" />
+ </LinearLayout>
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="4dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_marginTop="10dip"
+ android:orientation="vertical" >
+ <EditText style="@style/edittext"
+ android:id="@+id/latitude"
+ android:hint="latitude" />
+ <EditText style="@style/edittext"
+ android:id="@+id/longitude"
+ android:hint="longitude" />
+ <Button style="@style/button"
+ android:id="@+id/current"
+ android:text="@string/waypoint_my_coordinates" />
+ <EditText style="@style/edittext"
+ android:id="@+id/bearing"
+ android:inputType="numberDecimal"
+ android:hint="@string/waypoint_bearing" />
+ <EditText style="@style/edittext"
+ android:id="@+id/distance"
+ android:hint="@string/waypoint_distance" />
+ <AutoCompleteTextView style="@style/edittext"
+ android:id="@+id/name"
+ android:hint="@string/waypoint_name" />
+ <EditText style="@style/edittext"
+ android:id="@+id/note"
+ android:hint="@string/waypoint_note"
+ android:singleLine="false"
+ android:lines="6"
+ android:capitalize="sentences" />
+ <Button style="@style/button"
+ android:id="@+id/add_waypoint"
+ android:text="@string/waypoint_save" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
new file mode 100644
index 0000000..a8c55a4
--- /dev/null
+++ b/res/values-cs/strings.xml
@@ -0,0 +1,497 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompas</string>
+
+ <!-- basics -->
+ <string name="cache">keš</string>
+ <string name="detail">detail</string>
+ <string name="search">vyhledávání</string>
+ <string name="settings">nastavení</string>
+ <string name="about">o aplikaci</string>
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Sdílet odkaz ke keši</string>
+
+ <!-- caches -->
+ <string name="all">všechny kešky</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">neznámá keš</string>
+ <string name="letterbox">dopisní schránka</string>
+ <string name="event">událost</string>
+ <string name="mega">mega-událost</string>
+ <string name="earth">earthcache</string>
+ <string name="cito">událost cache in trash out</string>
+ <string name="webcam">webcam keš</string>
+ <string name="virtual">virtuální keš</string>
+ <string name="wherigo">wherigo keš</string>
+ <string name="lostfound">ztraceno a nalezeno</string>
+ <string name="ape">keš projektu ape</string>
+ <string name="gchq">ústředí groundspeaku</string>
+ <string name="gps">gps cache exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">cíl</string>
+ <string name="wp_stage">část multi-keše</string>
+ <string name="wp_puzzle">otázka</string>
+ <string name="wp_pkg">parkoviště</string>
+ <string name="wp_trailhead">rozcestník</string>
+ <string name="wp_waypoint">referenční bod</string>
+
+ <!-- logs -->
+ <string name="log_found">nález</string>
+ <string name="log_dnf">nenalezeno</string>
+ <string name="log_note">poznámka</string>
+ <string name="log_published">zveřejněno</string>
+ <string name="log_enabled">aktivováno</string>
+ <string name="log_disabled">deaktivováno</string>
+ <string name="log_attend">zúčastní se</string>
+ <string name="log_attended">účastnil se</string>
+ <string name="log_retrieved">vytažen z keše</string>
+ <string name="log_grabbed">převzat</string>
+ <string name="log_maintained">udržována</string>
+ <string name="log_maintenance_needed">vyžaduje údržbu</string>
+ <string name="log_maintenance_owner">údržba</string>
+ <string name="log_update">změna souřadnic</string>
+ <string name="log_archived">archivace</string>
+ <string name="log_needs_archived">vyžaduje archivaci</string>
+ <string name="log_discovered">nalezen</string>
+ <string name="log_reviewed">poznámka kontroly</string>
+ <string name="log_tb_nothing">beze změny</string>
+ <string name="log_tb_visit">návštěva</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_saving">ukládání logu</string>
+ <string name="log_clear">vyčistit</string>
+ <string name="log_post">odeslat log</string>
+ <string name="log_post_rate">odeslat log a hlasovat</string>
+ <string name="log_post_no_rate">odeslat log a nehlasovat</string>
+ <string name="log_add">přidat</string>
+ <string name="log_date">datum</string>
+ <string name="log_time">čas</string>
+ <string name="log_date_time">datum a čas</string>
+ <string name="log_rating">hlasovat</string>
+ <string name="log_no_rating">nehlasovat</string>
+ <string name="log_stars_1">1 hvězdička</string>
+ <string name="log_stars_2">2 hvězdičky</string>
+ <string name="log_stars_3">3 hvězdičky</string>
+ <string name="log_stars_4">4 hvězdičky</string>
+ <string name="log_stars_5">5 hvězdiček</string>
+ <string name="log_webcam">vyfocen webkamerou</string>
+ <string name="log_new_log">Log</string>
+ <string name="log_new_log_text">text logu</string>
+
+ <!-- errors -->
+ <string name="err_none">ok</string>
+ <string name="err_start">komunikace nezačala</string>
+ <string name="err_parse">selhalo čtení logovací stránky</string>
+ <string name="err_server">selhalo připojení k serveru geocaching.com (server umřel?)</string>
+ <string name="err_login">nejsou uložené žádné přihlašovací údaje</string>
+ <string name="err_login_failed">promiňte, ale c:geo se nemůže přihlásit.</string>
+ <string name="err_unknown">nastala neznámá chyba</string>
+ <string name="err_comm">nastala neznámá chyba při komunikaci</string>
+ <string name="err_missing_auth">nevyplněné uživatelské jméno a/nebo heslo.</string>
+ <string name="err_wrong">uložené přihlašovací údaje jsou špatné</string>
+ <string name="err_license">uživatel nepotvrdil souhlas s licenčním ujednáním serveru Geocaching.com</string>
+ <string name="err_store">c:geo nemůže uložit keš.</string>
+ <string name="err_drop">c:geo nemůže smazat keš.</string>
+ <string name="err_title_problem">problém</string>
+ <string name="err_detail_open">c:geo nedokáže načíst detaily keše.</string>
+ <string name="err_detail_cache">c:geo nedokáže načíst detaily keše. Je to opravdu keš?</string>
+ <string name="err_detail_cache_find">c:geo nemůže najít keš</string>
+ <string name="err_detail_cache_find_some">c:geo nemůže najít požadovanou keš.</string>
+ <string name="err_detail_cache_find_any">c:geo nemůže najít žádnou keš.</string>
+ <string name="err_detail_cache_find_next">c:geo nemůže najít další keš.</string>
+ <string name="err_detail_cache_forgot">c:geo zapomnělo, jakou keš chcete zobrazit.</string>
+ <string name="err_detail_cache_forgot_visit">c:geo zapomělo, jakou keš jste pohlížel.</string>
+ <string name="err_detail_cache_language">c:geo nemůže přečíst některé detaily. Prosím zkontrolujte, zda máte web Geocaching.com nastavený na anglický jazyk. c:geo zatím bohužel nedokáže přečíst jiné jazyky.</string>
+ <string name="err_detail_no_spoiler">c:geo nenašlo žádný obrázek pro tuto keš.</string>
+ <string name="err_detail_no_map_static">c:geo nenašlo žádnou statickou mapu pro tuto keš.</string>
+ <string name="err_detail_still_removing">Ještě odstraňuji keš.</string>
+ <string name="err_detail_still_saving">Ještě ukládám keš.</string>
+ <string name="err_detail_still_refreshing">Ještě aktualizuji keš.</string>
+ <string name="err_radar_title">Radar není nainstalován.</string>
+ <string name="err_radar_message">Tato funkce vyžaduje aplikaci Radar. Chcete ji nainstalovat?</string>
+ <string name="err_radar_market">c:geo nedokáže spustit Android Market a vyhledat aplikaci Radar.</string>
+ <string name="err_radar_generic">c:geo nedokáže spustit aplikaci Radar. Je nainstalovaná?</string>
+ <string name="err_navigation_no">c:geo nemůže najít žádnou podporovanou navigaci.</string>
+ <string name="err_application_no">c:geo nemůže najít žádnou použitelnou aplikaci.</string>
+ <string name="err_auth_initialize">c:geo nedokázalo zahájit autorizaci.</string>
+ <string name="err_auth_process">Autorizace selhala.</string>
+ <string name="err_cannot_log_visit">c:geo nemá dostatek informací pro zapsání návštěvy. Prosím udělejte to z kompletního detailu keše.</string>
+ <string name="err_init_cleared">c:geo nedokázalo smazat přihlašovací údaje.</string>
+ <string name="err_no_chaches">c:geo nedokázalo načíst keši nebo keše.</string>
+ <string name="err_download_fail">c:geo nemůže načíst keši, protože</string>
+ <string name="err_update_fail">nepodařilo se aktualizovat uraženou vzdálenost</string>
+ <string name="err_list_load_fail">c:geo nemůže načíst seznam keší</string>
+ <string name="err_store_failed">c:geo nemůže uložit keš</string>
+ <string name="err_refresh_failed">c:geo nemůže obnovit keš</string>
+ <string name="err_drop_failed">c:geo nemůže smazat keš</string>
+ <string name="err_dwld_details_failed">c:geo nemůže stáhnout detaily keše</string>
+ <string name="err_dwld_details_failed_reason">c:geo nemůže načíst podrobnosti o keši, protože</string>
+ <string name="err_load_descr_failed">c:geo nemůže stáhnout popis keše.</string>
+ <string name="err_location_unknown">c:geo nezná souřadnice keše</string>
+ <string name="err_tb_display">"C:geo nemůže zobrazit trackable. Je to opravdu trackable?</string>
+ <string name="err_tb_details_open">C:geo nemůže otevřít podrobnosti k trackable.</string>
+ <string name="err_tb_details_download">C:geo nemůže stáhnout podronsti k trackable z důvodu</string>
+ <string name="err_tb_forgot">C:geo zapomělo, který trackable jste chtěli.</string>
+ <string name="err_tb_forgot_saw">C:geo zapomělo, který trackable jste prohlíželi.</string>
+ <string name="err_tb_find">c:geo nemůže najít trackable.</string>
+ <string name="err_tb_find_that">c:geo nemůže najít toto trackable.</string>
+ <string name="err_waypoint_cache_unknown">c:geo neví k jeké keši chcete přidat bod trasy.</string>
+ <string name="err_waypoint_unknown">c:geo zapomělo jaký bod trasy chcete zobrazit.</string>
+ <string name="err_waypoint_add_failed">c:geo nemůže přidat bod trasy.</string>
+ <string name="err_waypoint_load_failed">c:geo nemůže načíst bod trasy.</string>
+ <string name="err_waypoint_delete_failed">c:geo nemůže smazat bod trasy.</string>
+ <string name="err_point_unknown_position">c:geo neví kde jste.</string>
+ <string name="err_point_no_position_given_title">popis je požadovaný</string>
+ <string name="err_point_no_position_given">Vyplňte alespoň šířku nebo délku nebo vzdálenost a směr. Můžete také vyplnit všechny čtyři pole.</string>
+ <string name="err_point_curr_position_unavailable">c:geo stále nemá aktuální polohu. Prosím, čekejte...</string>
+ <string name="err_point_bear_and_dist_title">Potřebujete poradit?</string>
+ <string name="err_point_bear_and_dist">Vyplňte jak směru a vzdálenosti. Úhel je úhel 0 - 360 stupňů vzhledem k severu. Vzdálenost s nebo bez jednotek.</string>
+ <string name="err_point_location_error">c:geo nemůže získat polohu bodu cesty.</string>
+ <string name="err_navigation_not_found">c:geo nemůže najít žádnou podporovanou navigaci.</string>
+ <string name="err_log_load_data">c:geo nemůže načíst data potřebná pro zalogování návštěvy.</string>
+ <string name="err_log_load_data_again">c:geo nemůže načíst data potřebná pro zalogování návštěvy. Zkouší to znovu.</string>
+ <string name="err_log_load_data_still">c:geo stále načítá data potřebná pro zalogování návštěvy. Prosím počkejte chvilku.</string>
+ <string name="err_log_failed_server">c:geo nemohlo odeslat log, protože server neodpovídá.</string>
+ <string name="err_log_post_failed">c:geo nemohlo odeslat log.</string>
+ <string name="err_log_post_failed_because">c:geo nemohlo odeslat log z důvodu</string>
+ <string name="err_search_address_no_match">c:geo nenašlo žádné odpovídající místo</string>
+ <string name="err_search_address_forgot">c:geo zapomělo adresu, kterou se pokoušíte najít.</string>
+ <string name="err_search_address">vyhledávání míst</string>
+ <string name="err_parse_lat">c:geo nemůže dopočítat šířku.</string>
+ <string name="err_parse_lon">c:geo nemůže dopočítat délku.</string>
+ <string name="err_parse_bear">c:geo nemůže dopočítat směr.</string>
+ <string name="err_parse_dist">c:geo nemůže dopočítat vzdálenost.</string>
+ <string name="warn_save_nothing">není nic k uložení.</string>
+ <string name="warn_no_cache_coord">Nejní žádná keš se souřadnicemi.</string>
+ <string name="warn_no_coordinates">Nezískány souřadnice</string>
+ <string name="warn_no_keyword">žádná klíčová slova nenalezena</string>
+ <string name="warn_no_username">žádné uživatelské jméno nenalezeno</string>
+ <string name="warn_search_help_title">Potřebujete pomoct?</string>
+ <string name="warn_search_help_address">"Zadejte adresu nebo jméno oblasti. Například použijte název ulice \"Radlicka 100, Praha, Ceska republika\", název města \"Berlín\" nebo použijte název místa \"Yellowstone Park\".</string>
+ <string name="warn_search_help_gccode">Zadejte kód keše. Například \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Zadejte slovo, které je použito v názvu keše, kterou se pokoušíte najít.</string>
+ <string name="warn_search_help_user">Zadejte jméno uživatele z Geocaching.com.</string>
+ <string name="warn_search_help_tb">Zadejte kód trackable. Například \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">prosím vyplňte nějaký text do logu.</string>
+ <string name="info_altitude">Současná nadmořská výška</string>
+ <string name="info_distance">uražená vzdálenost</string>
+ <string name="info_distance_cleared">uražená vzdálenost byla smazána</string>
+ <string name="info_since">\n(od</string>
+ <string name="info_log_posted">c:geo úspěšně zaslalo log.</string>
+ <string name="info_log_saved">c:geo úspěšně uložilo log.</string>
+ <string name="info_log_cleared">Log byl vyprázdněn.</string>
+ <string name="info_log_type_changed">Typ logu byl změněn!</string>
+
+ <!-- location service -->
+ <string name="loc_last">poslední známá</string>
+ <string name="loc_net">síť</string>
+ <string name="loc_gps">gps</string>
+ <string name="loc_sat">sat</string>
+ <string name="loc_trying">zjišťuji pozici</string>
+ <string name="loc_no_addr">neznámá adresa</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">o aplikaci</string>
+ <string name="menu_settings">nastavení</string>
+ <string name="menu_filter">filtr</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">aktivní mapa</string>
+ <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="about_button">o aplikaci</string>
+ <string name="settings_button">nastavení</string>
+ <string name="type">typ</string>
+ <string name="now_searching">vyhledávám</string>
+
+ <!-- caches -->
+ <string name="caches_searching">vyhledávání keší</string>
+ <string name="caches_no_cache">žádná keš</string>
+ <string name="caches_more_caches">další keše</string>
+ <string name="caches_more_caches_no">žádné další keše</string>
+ <string name="caches_downloading">stahuji keše...\nETA:</string>
+ <string name="caches_progress_loading_title">načítám keše</string>
+ <string name="caches_progress_loading_text">Keš uložena v přístroji</string>
+ <string name="caches_eta_ltm">méně než minutu</string>
+ <string name="caches_eta_mins">minuty</string>
+ <string name="caches_eta_min">minuta</string>
+ <string name="caches_no_caches">(žádné keše)</string>
+ <string name="caches_store_offline">uložit pro offline</string>
+ <string name="caches_store_selected">uložit vybrané</string>
+ <string name="caches_stored">uložené</string>
+ <string name="caches_on_map">zobrazit na mapě</string>
+ <string name="caches_select">vybrat ze seznamu</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_nearby">blízké</string>
+ <string name="caches_drop_selected">odebrat vybrané</string>
+ <string name="caches_drop_selected_ask">Opravdu chcete smazat vybrané keše z přístroje?</string>
+ <string name="caches_drop_all">odebrat vše</string>
+ <string name="caches_drop_all_ask">Opravdu chcete smazat všechny keše z přístroje?</string>
+ <string name="caches_drop_stored">odebrat uložené</string>
+ <string name="caches_refresh_selected">aktualizovat vybrané</string>
+ <string name="caches_refresh_all">aktualizovat vše</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Opište text z obrázků. Je to důležité pro stažení souřadnic keší.</string>
+ <string name="caches_recaptcha_hint">Text z obrázku</string>
+ <string name="caches_recaptcha_continue">pokračovat</string>
+
+ <!-- about -->
+ <string name="about_changelog">změny</string>
+ <string name="about_donate">podpora vývoje</string>
+ <string name="about_detail">detaily</string>
+ <string name="about_donation_less">darujte\nméně</string>
+ <string name="about_donation_more">podpořte\nvývoj</string>
+ <string name="about_contributors">přispěvatelé</string>
+
+ <!-- init -->
+ <string name="init_geocaching">geocaching.com</string>
+ <string name="init_gcvote">gcvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">twitter</string>
+ <string name="init_username">uživatelské heslo</string>
+ <string name="init_password">heslo</string>
+ <string name="init_passvote">heslo</string>
+ <string name="init_login">zkontrolovat</string>
+ <string name="init_login_popup">přihlášení</string>
+ <string name="init_login_popup_working">přihlašování na geocaching.com...</string>
+ <string name="init_login_popup_ok">přihlášení proběhlo</string>
+ <string name="init_login_popup_failed">přihlášení neproběhlo</string>
+ <string name="init_login_popup_failed_reason">přihlášení neproběhlo, protože</string>
+ <string name="init_legal">poznámka</string>
+ <string name="init_go4cache_connect">připojit k Go 4 Cache</string>
+ <string name="init_twitter_authorize">autorizovat c:geo</string>
+ <string name="init_twitter_publish">nový status při nálezu keše</string>
+ <string name="init_signature">podpis</string>
+ <string name="init_other">další možnosti</string>
+ <string name="init_skin">světlý skin (vyžaduje restart)</string>
+ <string name="init_transparent">průhledná úvodní obrazovka</string>
+ <string name="init_address">adresa na úvodní obrazovce</string>
+ <string name="init_exclude">nezobrazovat vlastní a nalezené keše</string>
+ <string name="init_disabled">nezobrazovat zrušené keše</string>
+ <string name="init_offline">ukládat mapy pro offline použití</string>
+ <string name="init_units">používat imperiální jednotky vzdálenosti</string>
+ <string name="init_nav">používat Google Navigation</string>
+ <string name="init_autoload">automaticky stahovat dlouhé popisy</string>
+ <string name="init_livelist">zobrazovat směr v seznamu keší</string>
+ <string name="init_browser">tvářit se jako běžný webový prohlížeč</string>
+ <string name="init_clear">smazat přihlašovací údaje</string>
+ <string name="init_cleared">c:geo smazalo přihlašovací údaje.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">twitter</string>
+ <string name="auth_authorize">autorizovat c:geo</string>
+ <string name="auth_start">zahájit autorizaci</string>
+ <string name="auth_again">znovu autorizovat</string>
+ <string name="auth_pin_hint">pin přidělený twitterem</string>
+ <string name="auth_finish">dokončit</string>
+ <string name="auth_dialog_wait">Čekám na Twitter...</string>
+ <string name="auth_dialog_pin_title">pin kód</string>
+ <string name="auth_dialog_pin_message">Prosím, napište PIN kód který Vám byl přidelen Twitterem. Je potřeba pro dokončení autorizace.</string>
+ <string name="auth_dialog_completed">c:geo nyní může posílat zprávy na Váš Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">žádná keš</string>
+ <string name="cache_count_one">jedna keš</string>
+ <string name="cache_count_more">keší</string>
+ <string name="cache_offline">offline</string>
+ <string name="cache_offline_refresh">obnovit</string>
+ <string name="cache_offline_drop">smazat</string>
+ <string name="cache_offline_store">uložit</string>
+ <string name="cache_offline_stored">uložena v zařízení</string>
+ <string name="cache_offline_not_ready">není připravena\npro použití offline</string>
+ <string name="cache_offline_time_about">přibližně před</string>
+ <string name="cache_offline_time_mins">minutami</string>
+ <string name="cache_offline_time_mins_few">několika minutami</string>
+ <string name="cache_offline_time_hour">jednou hodinou</string>
+ <string name="cache_offline_time_hours">hodinami</string>
+ <string name="cache_offline_time_days">dny</string>
+ <string name="cache_premium">placený účet</string>
+ <string name="cache_attributes">atributy</string>
+ <string name="cache_inventory">inventář</string>
+ <string name="cache_log_offline">offline log</string>
+ <string name="cache_description">popis</string>
+ <string name="cache_description_long">dlouhý popis</string>
+ <string name="cache_waypoints">body trasy</string>
+ <string name="cache_waypoints_add">přidat bod</string>
+ <string name="cache_hint">nápověda</string>
+ <string name="cache_logs">logbook</string>
+ <string name="cache_dialog_loading_details">načítám detaily keše...</string>
+ <string name="cache_dialog_loading_description">načítám popis keše...</string>
+ <string name="cache_dialog_offline_save_title">offline</string>
+ <string name="cache_dialog_offline_save_message">Ukládám keš pro použití offline...</string>
+ <string name="cache_dialog_offline_drop_title">offline</string>
+ <string name="cache_dialog_offline_drop_message">Odstraňuji keš z paměti zařízení...</string>
+ <string name="cache_dialog_refresh_title">aktualizace</string>
+ <string name="cache_dialog_refresh_message">Aktualizuji detaily keše...</string>
+ <string name="cache_menu_navigate">navigovat</string>
+ <string name="cache_menu_compass">kompas</string>
+ <string name="cache_menu_tbt">turn-by-turn</string>
+ <string name="cache_menu_radar">radar</string>
+ <string name="cache_menu_map">zobrazit na mapě</string>
+ <string name="cache_menu_map_ext">zobrazit na jiné mapě</string>
+ <string name="cache_menu_map_static">statické mapy</string>
+ <string name="cache_menu_map_short">mapy</string>
+ <string name="cache_menu_map_ext_short">Ext. mapy</string>
+ <string name="cache_menu_browser">otevřít v prohlížečí</string>
+ <string name="cache_menu_visit">zapsat návštěvu</string>
+ <string name="cache_menu_spoilers">obrázky</string>
+ <string name="cache_menu_around">keš v okolí</string>
+ <string name="cache_menu_event">přidat do kalendáře</string>
+ <string name="cache_menu_details">detaily</string>
+ <string name="cache_status">status</string>
+ <string name="cache_status_offline_log">připravený log</string>
+ <string name="cache_status_found">nalezena</string>
+ <string name="cache_status_archived">archivována</string>
+ <string name="cache_status_disabled">zrušena</string>
+ <string name="cache_status_premium">pouze pro platící uživatele</string>
+ <string name="cache_geocode">gc kód</string>
+ <string name="cache_name">název</string>
+ <string name="cache_type">typ</string>
+ <string name="cache_distance">vzdálenost</string>
+ <string name="cache_difficulty">obtížnost</string>
+ <string name="cache_terrain">terén</string>
+ <string name="cache_rating">hodnocení</string>
+ <string name="cache_owner">zakladatel</string>
+ <string name="cache_hidden">skryta</string>
+ <string name="cache_event">datum</string>
+ <string name="cache_location">místo</string>
+ <string name="cache_coordinates">souřadnice</string>
+ <string name="cache_calendars">vyberte kalendář</string>
+ <string name="cache_spoiler_images_title">Spoiler images</string>
+ <string name="cache_spoiler_images_loading">Loading spoiler images...</string>
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">hledání .gpx souborů\nv</string>
+ <string name="gpx_import_loading_stored">nahrávání keší z .gpx souboru\nuloženo:</string>
+ <string name="gpx_import_no_files">c:geo nenašlo žádný .gpx soubor</string>
+ <string name="gpx_import_caches_imported">keše importovány</string>
+ <string name="gpx_import_searching">vyhledávání .gpx souborů</string>
+ <string name="gpx_import_loading">nahrávání keší z .gpx souboru</string>
+ <string name="gpx_import_title">Import GPX</string>
+ <string name="gpx_import_title_reading_file">čtení souboru</string>
+ <string name="gpx_import_title_searching">hledání</string>
+ <string name="gpx_import_title_caches_imported">výsledek</string>
+
+ <!-- event -->
+ <string name="event_success">Událost byla přidána do kalendáře</string>
+ <string name="event_fail">Nepodařilo se vložit událost do kalendáře</string>
+
+ <!-- popup -->
+ <string name="popup_more">více detailů</string>
+ <string name="popup_offline">offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Bod trasy</string>
+ <string name="waypoint_custom">vlastní</string>
+ <string name="waypoint_my_coordinates">aktuální poloha</string>
+ <string name="waypoint_bearing">směr</string>
+ <string name="waypoint_distance">vzdálenost</string>
+ <string name="waypoint_name">název</string>
+ <string name="waypoint_edit">upravit</string>
+ <string name="waypoint_delete">smazat</string>
+ <string name="waypoint_edit_title">úprava waypointu</string>
+ <string name="waypoint_add_title">nový bod trasy</string>
+ <string name="waypoint_note">poznámka</string>
+ <string name="waypoint_save">uložit</string>
+ <string name="waypoint_loading">načítání bodu trasy...</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">informovat o nálezu na twitteru</string>
+
+ <!-- map -->
+ <string name="map_map">Mapa</string>
+ <string name="map_live">aktivní mapa</string>
+ <string name="map_view_satellite">satelitní pohled</string>
+ <string name="map_view_map">pohled do mapy</string>
+ <string name="map_trail_show">zobrazit záznam trasy</string>
+ <string name="map_trail_hide">skrýt záznam trasy</string>
+ <string name="map_live_enable">povolit aktuální polohu</string>
+ <string name="map_live_disable">zakázat aktuální polohu</string>
+ <string name="map_static_title">statické mapy</string>
+ <string name="map_static_loading">načítání statických map...</string>
+
+ <!-- search -->
+ <string name="search_coordinates">souřadnice</string>
+ <string name="search_coordinates_button">hledat podle souřadnic</string>
+ <string name="search_address">adresa</string>
+ <string name="search_address_button">hledat podle adresy</string>
+ <string name="search_gc">geokód</string>
+ <string name="search_gc_button">hledat podle geokódu</string>
+ <string name="search_kw">klíčová slova</string>
+ <string name="search_kw_prefill">klíčové slovo</string>
+ <string name="search_kw_button">hledat podle klíčového slova</string>
+ <string name="search_kw_caches">keše podle klíčového slova</string>
+ <string name="search_caches_found_by">keše nalezeny</string>
+ <string name="search_caches_hidden_by">keše skryty</string>
+ <string name="search_fbu">nalezeno uživatelem</string>
+ <string name="search_fbu_prefill">uživatelské jméno</string>
+ <string name="search_fbu_button">hledat podle nálezce</string>
+ <string name="search_hbu">skryto uživatelem</string>
+ <string name="search_hbu_prefill">vlastník</string>
+ <string name="search_hbu_button">hledat podle vlastníka</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">identifikace trackable</string>
+ <string name="search_tb_button">vyhledávání trackable</string>
+ <string name="search_destination">cíl</string>
+ <string name="search_direction_rel">od této polohy</string>
+ <string name="search_lat">šířka</string>
+ <string name="search_lon">délka</string>
+ <string name="search_caches">hledat keše</string>
+ <string name="search_caches_near">keše v okolí</string>
+ <string name="search_address_started">vyhledávání míst</string>
+ <string name="search_address_result">místa nalezena</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">načítání detailů...</string>
+ <string name="trackable_log_touch">hlášení zahlédnutí</string>
+ <string name="trackable_browser_open">otevřít v prohlížeči</string>
+ <string name="trackable_goal">cíl</string>
+ <string name="trackable_details">detaily</string>
+ <string name="trackable_image">obrázek</string>
+ <string name="trackable_code">TB-kód</string>
+ <string name="trackable_name">název</string>
+ <string name="trackable_type">typ</string>
+ <string name="trackable_owner">vlastník</string>
+ <string name="trackable_spotted">Spotted</string>
+ <string name="trackable_origin">původ</string>
+ <string name="trackable_unknown">neznámý</string>
+ <string name="trackable_released">vypuštění</string>
+ <string name="trackable_touch">dotyk</string>
+
+ <!-- navigation -->
+ <string name="navigation">navigace</string>
+ <string name="compass_title">kompas</string>
+ <string name="use_gps">použít GPS</string>
+ <string name="use_compass">použít kompas</string>
+ <string name="destination_select">vyberte cíl</string>
+ <string name="destination_set">cíl nastaven</string>
+
+ <!-- license -->
+ <string name="license">Licence</string>
+ <string name="license_show">zobrazit licenci</string>
+ <string name="license_dismiss">zamítnutí</string>
+
+ <!-- next things -->
+ <string name="legal_note">Před používáním služeb serveru geocaching.com je potřeba souhlasit s <a href="http://www.geocaching.com/about/disclaimer.aspx">licenčním ujednáním Groundspeaku</a>.</string>
+ <string name="author">autor: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">podpora: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">web: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="about_go4cache">Služba<b>Go 4 cache</b>umožňuje sledovat v reálném čase ostatní kačery na mapě (v <b>c:geo</b>nebo v prohlížeči). Můžete se tak podívat třeba na to, jakou kešku právě hledají. Připojením ke službě <b>Go 4 cache</b>umožníte aplikaci <b>c:geo</b>zveřejňovat Vaši aktuální polohu (pouze pokud <b>c:geo</b>běží).</string>
+ <string name="about_twitter">Chcete aby <b>c:geo</b>napsalo na Váš Twitter pokaždé, když zapíšete nález kešky? </string>
+ <string name="about_auth_1">Pomocí následujícího procesu můžete aplikaci <b>c:geo</b>umožnit odesílání příspěvků na Váš Twitter. </string>
+ <string name="about_auth_2">Tapnutím na tlačítko "zahájit autorizaci" celý proces začne. Tento proces otevře webovou stránku Twitteru, kde se budete muset přihlásit a tlačítkem Accept pak umožnit aplikaci <b>c:geo</b>přístup k Vašemu Twitteru. Twitter Vám přidělí PIN kód pokud tapnete na Accept. Tento kód zkopírujte a vložte do aplikace <b>c:geo</b>. A potvrďte. To je vše.</string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
new file mode 100644
index 0000000..21ee843
--- /dev/null
+++ b/res/values-da/strings.xml
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompas</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detaljer</string>
+ <string name="search">Søg</string>
+ <string name="settings">Indstillinger</string>
+ <string name="about">Om c:geo</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Del link til cache</string>
+
+ <!-- caches -->
+ <string name="all">Alle cacher</string>
+ <string name="traditional">Traditionel cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Ukendt cache</string>
+ <string name="letterbox">Letterbox-hybrid</string>
+ <string name="event">Event-cache</string>
+ <string name="mega">Megaevent-cache</string>
+ <string name="earth">Earth-cache</string>
+ <string name="cito">Cache in trash out-event</string>
+ <string name="webcam">Webcam-cache</string>
+ <string name="virtual">Virtuel cache</string>
+ <string name="wherigo">Wherigo-cache</string>
+ <string name="lostfound">Lost &amp; found-cache</string>
+ <string name="ape">Project ape-cache</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">GPS cache-udstilling</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Mål</string>
+ <string name="wp_stage">multi-cache post</string>
+ <string name="wp_puzzle">Spørgsmål</string>
+ <string name="wp_pkg">Parkering</string>
+ <string name="wp_trailhead">Sti</string>
+ <string name="wp_waypoint">Referencepunkt</string>
+
+ <!-- logs -->
+ <string name="log_found">Fundet</string>
+ <string name="log_dnf">Ikke fundet</string>
+ <string name="log_note">Note</string>
+ <string name="log_published">Offentliggjort</string>
+ <string name="log_enabled">Aktiveret</string>
+ <string name="log_disabled">Deaktiveret</string>
+ <string name="log_attend">Deltager</string>
+ <string name="log_attended">Deltog</string>
+ <string name="log_retrieved">Hentet</string>
+ <string name="log_grabbed">Taget fra andet sted</string>
+ <string name="log_maintained">Vedligeholdt</string>
+ <string name="log_maintenance_needed">Mangler vedligeholdelse</string>
+ <string name="log_maintenance_owner">Vedligeholdelse</string>
+ <string name="log_update">Nye koordinater</string>
+ <string name="log_archived">Arkiveret</string>
+ <string name="log_needs_archived">Mangler arkiveret</string>
+ <string name="log_discovered">Set</string>
+ <string name="log_reviewed">Godkendernote</string>
+ <string name="log_tb_nothing">Gør intet</string>
+ <string name="log_tb_visit">Besøg</string>
+ <string name="log_tb_drop">Læg her</string>
+ <string name="log_save">Gem</string>
+ <string name="log_clear">Fjern</string>
+ <string name="log_webcam">Webcamfoto taget</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Forbindelse ikke oprettet</string>
+ <string name="err_parse">Login-side kan ikke indlæses</string>
+ <string name="err_server">Kan ikke forbinde til geocaching.com (server eller forbindelsesfejl?)</string>
+ <string name="err_login">Ingen login gemt</string>
+ <string name="err_unknown">Ukendt fejl</string>
+ <string name="err_comm">Ukendt forbindelsesfejl</string>
+ <string name="err_wrong">Fejl i login</string>
+ <string name="err_license">Bruger accepterer betingelser på Geocaching.com</string>
+ <string name="err_store">Beklager, c:geo kan ikke gemme cachen.</string>
+ <string name="err_drop">Beklager, c:geo kan ikke slette cachen.</string>
+ <string name="err_title_problem">Problem</string>
+ <string name="err_detail_open">Beklager, 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_forgot">Beklager, c:geo husker ikke hvilken cache du ønskede.</string>
+ <string name="err_detail_cache_language">c:geo kan ikke læse alle cachedetaljer. Tjek om geocaching.com er sat til engelsk. Desværre kan c:geo ikke forstå andre sprog.</string>
+ <string name="err_detail_no_spoiler">c:geo fandt ingen spoilerbilleder til denne cache.</string>
+ <string name="err_detail_no_map_static">c:geo fandt ingen statiske kort til denne cache.</string>
+ <string name="err_detail_still_removing">Fjerner stadig cachen.</string>
+ <string name="err_detail_still_saving">Gemmer stadig cachen.</string>
+ <string name="err_detail_still_refreshing">Indlæser stadig cachen.</string>
+ <string name="err_radar_title">Radar er ikke installeret.</string>
+ <string name="err_radar_message">Denne funktion kræver Radar. Ønsker du at installere Radar?</string>
+ <string name="err_radar_market">c:geo kan ikke åbne Android Marked for at søge efter Radar.</string>
+ <string name="err_radar_generic">Beklager, c:geo kan ikke starte Radar. Er den installeret?</string>
+ <string name="err_navigation_no">c:geo kan ikke finde understøttet navigation.</string>
+ <string name="err_application_no">c:geo kan ikke finde en passende applikation.</string>
+ <string name="err_auth_initialize">Beklager, c:geo kan ikke gennemføre godkendelsen.</string>
+ <string name="err_auth_process">Godkendelse fejlede.</string>
+ <string name="err_cannot_log_visit">c:geo har ikke nok informationer til at logge besøg. Log fra "Alle detaljer".</string>
+ <string name="err_init_cleared">Beklager, c:geo kan ikke slette login.</string>
+ <string name="err_no_chaches">Beklager, c:geo kan ikke indlæse cachen.</string>
+ <string name="err_download_fail">Beklager, c:geo kan ikke hente cachen pga. </string>
+ <string name="err_update_fail">Kan ikke opdatere rejsedistance.</string>
+
+ <string name="warn_save_nothing">Der er ikke noget at gemme.</string>
+ <string name="warn_no_cache_coord">Der er ingen cache med disse koordinater.</string>
+
+ <string name="info_altitude">Nuværende højde</string>
+ <string name="info_distance">Rejsedistance</string>
+ <string name="info_distance_cleared">Rejsedistance er slettet.</string>
+ <string name="info_since">\n(Siden </string>
+
+ <!-- location service -->
+ <string name="loc_last">Sidst kendte</string>
+ <string name="loc_net">Netværk</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Lokaliserer</string>
+ <string name="loc_no_addr">Ukendt adresse</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Om c:geo</string>
+ <string name="menu_settings">Indstillinger</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live-kort</string>
+ <string name="caches_nearby_button">I nærheden</string>
+ <string name="advanced_search_button">Søg</string>
+ <string name="stored_caches_button">Gemte</string>
+ <string name="any_button">Alle destinationer</string>
+ <string name="about_button">Om</string>
+ <string name="settings_button">Indstillinger</string>
+ <string name="type">Type</string>
+ <string name="now_searching">Søger</string>
+
+ <!-- caches -->
+ <string name="caches_no_cache">Ingen cache</string>
+ <string name="caches_more_caches">Flere cacher</string>
+ <string name="caches_more_caches_no">Ikke flere cacher</string>
+ <string name="caches_downloading">Henter cacher...\nETA: </string>
+ <string name="caches_eta_ltm">Under et minut</string>
+ <string name="caches_eta_mins"> minutter</string>
+ <string name="caches_no_caches"> (ingen cacher)</string>
+ <string name="caches_store_offline">Gem Offline</string>
+ <string name="caches_on_map">Vis på kort</string>
+ <string name="caches_select">Vælg fra liste</string>
+
+ <!-- about -->
+ <string name="about_changelog">Ændringslog</string>
+ <string name="about_donate">Donér</string>
+ <string name="about_detail">Detaljer</string>
+ <string name="about_donation_less">Donér\nmindre</string>
+ <string name="about_donation_more">Donér\nudvikling</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Brugernavn</string>
+ <string name="init_password">Password</string>
+ <string name="init_passvote">Password</string>
+ <string name="init_login">Check login</string>
+ <string name="init_legal">Juridisk note</string>
+ <string name="init_go4cache_connect">Forbind til Go 4 Cache</string>
+ <string name="init_twitter_authorize">Godkend c:geo</string>
+ <string name="init_twitter_publish">Offentliggør status når cache er fundet</string>
+ <string name="init_signature">Signatur</string>
+ <string name="init_other">Andre indstillinger</string>
+ <string name="init_skin">Light skin (genstart af c:geo nødvendig)</string>
+ <string name="init_transparent">Transparent c:geo hovedskærm</string>
+ <string name="init_address">Vis adresse på hovedskærm</string>
+ <string name="init_exclude">Udelad egne og fundne cacher</string>
+ <string name="init_disabled">Udelad deaktiverede cacher</string>
+ <string name="init_offline">Gem kort til offlinebrug</string>
+ <string name="init_units">Benyt britiske afstandsmål</string>
+ <string name="init_nav">Benyt Google Navigation</string>
+ <string name="init_autoload">Auto-indlæs lang cachebeskrivelse</string>
+ <string name="init_livelist">Vis retning til cacher i lister</string>
+ <string name="init_browser">Identificer c:geo som standardbrowser</string>
+ <string name="init_cleared">c:geo slettede login-informationer.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Godkend c:geo</string>
+ <string name="auth_start">Start godkendelse</string>
+ <string name="auth_again">Start igen</string>
+ <string name="auth_pin_hint">PIN tildelt af Twitter</string>
+ <string name="auth_finish">Færdig</string>
+ <string name="auth_dialog_wait">Venter på Twitter...</string>
+ <string name="auth_dialog_pin_title">PIN-kode</string>
+ <string name="auth_dialog_pin_message">Indtast PIN-kode fra Twitter. PIN er påkrævet for at gennemføre godkendelse.</string>
+ <string name="auth_dialog_completed">c:geo er nu godkendt til at poste beskeder på Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Ingen cache</string>
+ <string name="cache_count_one">En cache</string>
+ <string name="cache_count_more">Cacher</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Genindlæs</string>
+ <string name="cache_offline_drop">Fjern</string>
+ <string name="cache_offline_store">Gem</string>
+ <string name="cache_offline_stored">Gemt i telefon</string>
+ <string name="cache_offline_not_ready">Ikke klar\ntil offline brug</string>
+ <string name="cache_offline_time_about">For</string>
+ <string name="cache_offline_time_mins">minutter siden</string>
+ <string name="cache_offline_time_mins_few">få minutter siden</string>
+ <string name="cache_offline_time_hour">en time siden</string>
+ <string name="cache_offline_time_hours">timer siden</string>
+ <string name="cache_offline_time_days">dage siden</string>
+ <string name="cache_attributes">Attributter</string>
+ <string name="cache_inventory">Inventar</string>
+ <string name="cache_log_offline">Offline log</string>
+ <string name="cache_description">Beskrivelse</string>
+ <string name="cache_description_long">Lang beskrivelse</string>
+ <string name="cache_waypoints">Waypoints</string>
+ <string name="cache_waypoints_add">Tilføj waypoint</string>
+ <string name="cache_hint">Hint</string>
+ <string name="cache_logs">Logbog</string>
+ <string name="cache_dialog_loading_details">Indlæser cachedetaljer...</string>
+ <string name="cache_dialog_loading_description">Indlæser cachebeskrivelse...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Gemmer cache til offlinebrug...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Fjerner cache fra hukommelsen...</string>
+ <string name="cache_dialog_refresh_title">Genindlæs</string>
+ <string name="cache_dialog_refresh_message">Genindlæser cachedetaljer...</string>
+ <string name="cache_menu_navigate">Naviger</string>
+ <string name="cache_menu_compass">Kompas</string>
+ <string name="cache_menu_tbt">Vejvisning</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Vis på kort</string>
+ <string name="cache_menu_map_ext">Vis på ext. kort</string>
+ <string name="cache_menu_map_static">Statiske kort</string>
+ <string name="cache_menu_browser">Åbn i browser</string>
+ <string name="cache_menu_visit">Log besøg</string>
+ <string name="cache_menu_spoilers">Spoilerbilleder</string>
+ <string name="cache_menu_around">Cacher i nærheden</string>
+ <string name="cache_menu_event">Tilføj til kalender</string>
+ <string name="cache_menu_details">Detaljer</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Log gemt</string>
+ <string name="cache_status_found">Fundet</string>
+ <string name="cache_status_archived">Arkiveret</string>
+ <string name="cache_status_disabled">Deaktiveret</string>
+ <string name="cache_status_premium">Kun premium-medlemmer</string>
+ <string name="cache_geocode">GC-code</string>
+ <string name="cache_type">Type</string>
+ <string name="cache_distance">Distance</string>
+ <string name="cache_difficulty">Sværhed</string>
+ <string name="cache_terrain">Terræn</string>
+ <string name="cache_rating">Vurdering</string>
+ <string name="cache_owner">Ejer</string>
+ <string name="cache_hidden">Gemt</string>
+ <string name="cache_event">Dato</string>
+ <string name="cache_location">Lokation</string>
+ <string name="cache_coordinates">Koordinater</string>
+ <string name="cache_calendars">Vælg kalender</string>
+
+ <!-- event -->
+ <string name="event_success">Eventcache tilføjet til kalender</string>
+ <string name="event_fail">Kan ikke tilføje eventcache til kalender</string>
+
+ <!-- popup -->
+ <string name="popup_more">Flere detaljer</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_custom">Tilpasset</string>
+ <string name="waypoint_my_coordinates">Mine koordinater</string>
+ <string name="waypoint_bearing">Retning</string>
+ <string name="waypoint_distance">Afstand</string>
+ <string name="waypoint_name">Navn</string>
+ <string name="waypoint_edit">Rediger</string>
+ <string name="waypoint_delete">Slet</string>
+ <string name="waypoint_edit_title">Rediger waypoint</string>
+ <string name="waypoint_add_title">Tilføj waypoint</string>
+ <string name="waypoint_note">Note</string>
+ <string name="waypoint_save">Gem</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Post fund på Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Kort</string>
+ <string name="map_live">Live-kort</string>
+ <string name="map_view_satellite">Satellit-view</string>
+ <string name="map_view_map">Kort-view</string>
+ <string name="map_trail_show">Vis spor</string>
+ <string name="map_trail_hide">Skjul spor</string>
+ <string name="map_live_enable">Aktivér live</string>
+ <string name="map_live_disable">Deaktivér live</string>
+
+ <!-- search -->
+ <string name="search_coordinates">Koordinater</string>
+ <string name="search_coordinates_button">Søg fra koordinater</string>
+ <string name="search_address">Adresse</string>
+ <string name="search_address_button">Søg adresse</string>
+ <string name="search_gc">Geocode</string>
+ <string name="search_gc_button">Søg geocode</string>
+ <string name="search_kw">Nøgleord</string>
+ <string name="search_kw_prefill">Nøgleord</string>
+ <string name="search_kw_button">Søg efter nøgleord</string>
+ <string name="search_fbu">Fundet af bruger</string>
+ <string name="search_fbu_prefill">Brugernavn</string>
+ <string name="search_fbu_button">Søg brugernavn</string>
+ <string name="search_hbu">Gemt af bruger</string>
+ <string name="search_hbu_prefill">Ejer</string>
+ <string name="search_hbu_button">Søg ejer</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">Trackable id</string>
+ <string name="search_tb_button">Søg trackable</string>
+ <string name="search_destination">Destination</string>
+ <string name="search_direction_rel">Fra denne position</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigation</string>
+
+ <!-- next things -->
+ <string name="legal_note">For at benytte geocaching.com, skal betingelserne i <a href="http://www.geocaching.com/about/termsofuse.aspx">"Groundspeak disclaimer"</a> accepteres.</string>
+ <string name="author">Udviklet af: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Hjemmeside: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="about_go4cache">Servicen <b>Go 4 Cache</b> viser andre geocachere på kortet (i <b>c:geo</b> eller i browser) i realtime. Servicen kan f.eks. vise hvilken cache de er på vej hen til. Ved forbindelse til <b>Go 4 Cache</b> tillader du at <b>c:geo</b> offentliggør din position når du geocacher (kun når <b>c:geo</b> er startet).</string>
+ <string name="about_twitter">Skal <b>c:geo</b> sende status til Twitter hvergang du logger en cache?</string>
+ <string name="about_auth_1">Med denne proces tillader du at <b>c:geo</b> får adgang til din Twitter.</string>
+ <string name="about_auth_2">Klik på \"godkend c:geo\" knappen for at starte godkendelsesprocessen. Det vil åbne Twitter i en webbrowser. Log ind på siden og tillad <b>c:geo</b> at tilgå din Twitter. Når godkendt, vil Twitter vise en PIN-kode. Denne PIN skal tastes ind i <b>c:geo</b> og bekræftes.</string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
new file mode 100644
index 0000000..ce90bbd
--- /dev/null
+++ b/res/values-de/strings.xml
@@ -0,0 +1,747 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo Kompass</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detail</string>
+ <string name="search">Suche</string>
+ <string name="settings">Einstellungen</string>
+ <string name="helpers">Nützliche Apps</string>
+ <string name="about">Über c:geo</string>
+ <string name="helper">Du willst mehr über <b>c:geo</b> erfahren?\nSchaue in die Bedienungsanleitung.</string>
+ <string name="database_error_title">Problem mit der Datenbank</string>
+ <string name="database_error_message">c:geo konnte nicht mit der lokalen Datenbank verbinden.\nBitte später erneut versuchen. Wenn dies öfter geschieht, lösche die c:geo-Daten unter Einstellungen / Anwendungen / c:geo oder installiere c:geo erneut und entschuldige die Unannehmlichkeiten!</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Link versenden</string>
+
+ <!-- caches -->
+ <string name="all">Alle Caches</string>
+ <string name="all_types">Alle Cachetypen</string>
+ <string name="traditional">Traditional Cache</string>
+ <string name="multi">Multi-Cache</string>
+ <string name="mystery">Mystery-Cache</string>
+ <string name="letterbox">Letterbox Hybrid</string>
+ <string name="event">Event-Cache</string>
+ <string name="mega">Mega Event-Cache</string>
+ <string name="earth">Earth-Cache</string>
+ <string name="cito">Cache in Trash out Event</string>
+ <string name="webcam">Webcam-Cache</string>
+ <string name="virtual">Virtual-Cache</string>
+ <string name="wherigo">Wherigo-Cache</string>
+ <string name="lostfound">Lost &amp; Found</string>
+ <string name="ape">Project Ape-Cache</string>
+ <string name="gchq">Groundspeak HQ</string>
+ <string name="gps">GPS Cache Exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Final</string>
+ <string name="wp_stage">Station eines Multi-Cache</string>
+ <string name="wp_puzzle">Station mit Frage</string>
+ <string name="wp_pkg">Parkplatz</string>
+ <string name="wp_trailhead">Ausgangspunkt</string>
+ <string name="wp_waypoint">Referenzpunkt</string>
+
+ <!-- logs -->
+ <string name="log_found">Gefunden</string>
+ <string name="log_dnf">Nicht gefunden</string>
+ <string name="log_note">Bemerkung</string>
+ <string name="log_published">Veröffentlicht</string>
+ <string name="log_enabled">Aktiviert</string>
+ <string name="log_disabled">Deaktiviert</string>
+ <string name="log_attend">Werde teilnehmen</string>
+ <string name="log_attended">Habe teilgenommen</string>
+ <string name="log_retrieved">Mitgenommen</string>
+ <string name="log_placed">Abgelegt</string>
+ <string name="log_grabbed">Woanders gefunden</string>
+ <string name="log_maintained">Wartung durchgeführt</string>
+ <string name="log_maintenance_needed">Benötigt Wartung</string>
+ <string name="log_maintenance_owner">Wartung</string>
+ <string name="log_update">Geänderte Koordinaten</string>
+ <string name="log_archived">Archiviert</string>
+ <string name="log_needs_archived">Sollte archiviert werden</string>
+ <string name="log_discovered">Gesehen</string>
+ <string name="log_reviewed">Überprüft</string>
+ <string name="log_taken">Cache besucht</string>
+ <string name="log_tb_nothing">Keine Aktion</string>
+ <string name="log_tb_visit">Besuchen</string>
+ <string name="log_tb_drop">Ablegen</string>
+ <string name="log_tb_changeall">Alle ändern</string>
+ <string name="log_save">Speichern</string>
+ <string name="log_saving">Log wird gespeichert...</string>
+ <string name="log_clear">Leeren</string>
+ <string name="log_post">Loggen</string>
+ <string name="log_post_rate">Loggen &amp; bewerten</string>
+ <string name="log_post_no_rate">Loggen ohne Bewertung</string>
+ <string name="log_add">Hinzufügen</string>
+ <string name="log_date">Datum</string>
+ <string name="log_time">Uhrzeit</string>
+ <string name="log_date_time">Datum &amp; Uhrzeit</string>
+ <string name="log_rating">Bewertung</string>
+ <string name="log_no_rating">Keine Bewertung</string>
+ <string name="log_stars_1">1 Stern</string>
+ <string name="log_stars_2">2 Sterne</string>
+ <string name="log_stars_3">3 Sterne</string>
+ <string name="log_stars_4">4 Sterne</string>
+ <string name="log_stars_5">5 Sterne</string>
+ <string name="log_webcam">Webcam-Foto gemacht</string>
+ <string name="log_new_log">Loggen</string>
+ <string name="log_new_log_text">Log-Text</string>
+ <string name="log_announcement">Ankündigung</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">OK</string>
+ <string name="err_start">Kommunikation nicht gestartet</string>
+ <string name="err_parse">Parsing der Anmeldung gescheitert</string>
+ <string name="err_server">Verbindung zu geocaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string>
+ <string name="err_login">Keine Anmeldedaten gespeichert.</string>
+ <string name="err_login_failed">Login fehlgeschlagen.</string>
+ <string name="err_unknown">Unbekannter Fehler</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_license">Die Geocaching.com Nutzungsbedingungen wurden nicht akzeptiert. c:geo kann deshalb keine Koordinaten laden.</string>
+ <string name="err_store">c:geo konnte den Cache nicht speichern.</string>
+ <string name="err_drop">c:geo konnte den Cache nicht löschen.</string>
+ <string name="err_title_problem">Problem</string>
+ <string name="err_detail_open">c:geo konnte die Cache-Details nicht öffnen.</string>
+ <string name="err_detail_cache">c:geo konnte diesen Cache nicht darstellen. Ist es wirklich ein Cache?</string>
+ <string name="err_detail_cache_find">c:geo konnte keinen Cache finden.</string>
+ <string name="err_detail_cache_find_some">c:geo konnte diesen Cache nicht finden.</string>
+ <string name="err_detail_cache_find_any">c:geo konnte keine Caches finden.</string>
+ <string name="err_detail_cache_find_next">c:geo konnte die nächsten Caches nicht finden.</string>
+ <string name="err_detail_cache_forgot">c:geo hat vergessen, welcher Cache aufgerufen werden sollte.</string>
+ <string name="err_detail_cache_forgot_visit">c:geo hat vergessen, welchen Cache Sie besucht haben.</string>
+ <string name="err_detail_cache_language">c:geo konnte manche Details des Caches nicht lesen. Bitte überprüfen, ob geocaching.com auf "English" gestellt wurde. Leider versteht c:geo keine andere Spracheinstellungen.</string>
+ <string name="err_detail_no_spoiler">c:geo hat kein Hinweisbild für diesen Cache gefunden.</string>
+ <string name="err_detail_no_map_static">c:geo hat keine statische Karte für diesen Cache gefunden.</string>
+ <string name="err_detail_not_load_map_static">c:geo konnte die statische Karte nicht laden.</string>
+ <string name="err_detail_still_removing">c:geo löscht diesen Cache noch immer.</string>
+ <string name="err_detail_still_saving">c:geo speichert diesen Cache noch immer.</string>
+ <string name="err_detail_still_refreshing">c:geo versucht noch immer diesen Cache zu aktualiseren.</string>
+ <string name="err_radar_title">Radar-Anwendung ist nicht installiert.</string>
+ <string name="err_radar_message">Diese Funktion benötigt die Radar-Anwendung. Soll diese installiert werden?</string>
+ <string name="err_radar_market">c:geo konnte den Android Market nicht starten, um nach der Radar-Anwendung zu suchen.</string>
+ <string name="err_radar_generic">c:geo konnte die Radar Anwendung nicht starten. Ist sie installiert?</string>
+ <string name="err_navigation_no">c:geo konnte keine unterstützte Art der Navigation finden.</string>
+ <string name="err_application_no">c:geo konnte keine passende Anwendung finden.</string>
+ <string name="err_auth_initialize">c:geo konnte die Autorisierung nicht initialisieren.</string>
+ <string name="err_auth_process">Autorisierung fehlgeschlagen.</string>
+ <string name="err_cannot_log_visit">c:geo hat nicht genügend Informationen um den Besuch zu loggen. Bitte über die Cache-Details versuchen.</string>
+ <string name="err_init_cleared">c:geo konnte die Anmeldedaten nicht entfernen.</string>
+ <string name="err_no_chaches">c:geo konnte die Caches nicht laden.</string>
+ <string name="err_download_fail">c:geo konnte keine Caches laden, weil </string>
+ <string name="err_update_fail">Update der gereisten Strecke fehlgeschlagen.</string>
+ <string name="err_list_load_fail">Laden der Cacheliste fehlgeschlagen.</string>
+ <string name="err_store_failed">Speichern des Caches fehlgeschlagen.</string>
+ <string name="err_refresh_failed">Aktualisierung fehlgeschlagen.</string>
+ <string name="err_drop_failed">Löschen des Caches fehlgeschlagen.</string>
+ <string name="err_dwld_details_failed">Download der Cache-Details fehlgeschlagen.</string>
+ <string name="err_dwld_details_failed_reason">Download der Cache-Details fehlgeschlagen, wegen</string>
+ <string name="err_load_descr_failed">Laden der Cachebeschreibung fehlgeschlagen.</string>
+ <string name="err_location_unknown">c:geo erkennt die Position des Caches nicht.</string>
+ <string name="err_manual_title">Anleitung ist nicht installiert.</string>
+ <string name="err_manual_message">Bedienungsanleitung für c:geo ist auf dem Gerät nicht vorhanden. Jetzt installieren?</string>
+ <string name="err_manual_market">c:geo konnte den Android Market nicht starten, um nach der Anleitung zu suchen.</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 Details des Trackables nicht öffnen.</string>
+ <string name="err_tb_details_download">c:geo konnte Details des Trackables nicht laden, weil</string>
+ <string name="err_tb_forgot">c:geo hat den gewünschten Trackable vergessen.</string>
+ <string name="err_tb_forgot_saw">c:geo hat vergessen, welchen Trackable Sie gesehen haben.</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>
+ <string name="err_waypoint_unknown">c:geo hat vergessen, welchen Wegpunkt du ansehen wolltest.</string>
+ <string name="err_waypoint_add_failed">c:geo konnte den Wegpunkt nicht hinzufügen.</string>
+ <string name="err_waypoint_load_failed">c:geo konnte den Wegpunkt nicht laden.</string>
+ <string name="err_waypoint_delete_failed">c:geo konnte den Wegpunkt nicht löschen.</string>
+ <string name="err_point_unknown_position">c:geo konnte deinen 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</string>
+ <string name="err_point_location_error">c:geo konnte den Ort des Wegpunkts nicht erkennen.</string>
+ <string name="err_navigation_not_found">c:geo konnte keine Navigation auf dem Gerät finden.</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äd gerade die benötigten Daten. Bitte kurz warten.</string>
+ <string name="err_log_failed_server">c:geo konnte Log nicht senden, weil der Server nicht antwortete.</string>
+ <string name="err_log_post_failed">c:geo konnte Log nicht absenden.</string>
+ <string name="err_log_post_failed_because">c:geo konnte Log nicht absenden, wegen </string>
+
+ <string name="err_search_address_no_match">Keinen passenden Ort gefunden.</string>
+ <string name="err_search_address_forgot">c:geo hat die Adresse vergessen, die du suchst.</string>
+ <string name="err_search_address">Suche nach Orten</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>
+ <string name="err_parse_bear">c:geo konnte die Richtung nicht verarbeiten.</string>
+ <string name="err_parse_dist">c:geo konnte die Entfernung nicht verarbeiten.</string>
+
+ <string name="warn_save_nothing">Es gibt nichts zum speichern.</string>
+ <string name="warn_no_cache_coord">Es gibt hier keinen Cache mit Koordinaten.</string>
+ <string name="warn_no_coordinates">Keine Koordinaten angegeben.</string>
+ <string name="warn_no_keyword">Kein Stichwort angegeben.</string>
+ <string name="warn_no_username">Kein Benutzername angegeben.</string>
+ <string name="warn_search_help_title">Hilfe benötigt?</string>
+ <string name="warn_search_help_address">Adresse oder Ort eingeben, z.B. Straßenname und Ort \"Dorfstraße 333, Berlin, Deutschland\", Ort \"Berlin\" oder den Namen eines beliebigen Ortes wie z.B. \"Tiergarten\".</string>
+ <string name="warn_search_help_gccode">Geocode eingeben. z.B. \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Stichwörter eingeben, die im Namen des zu suchenden Caches enthalten sind.</string>
+ <string name="warn_search_help_user">Name eines Benutzers auf Geocaching.com eingeben.</string>
+ <string name="warn_search_help_tb">Code des Trackables eingeben, z.B. \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">Bitte Text einfügen.</string>
+
+ <string name="info_altitude">Momentane Höhe</string>
+ <string name="info_distance">Gereiste Strecke</string>
+ <string name="info_distance_cleared">Gereiste Strecke wurde gelöscht.</string>
+ <string name="info_since">\n(seit </string>
+
+ <string name="info_log_posted">Log erfolgreich gesendet.</string>
+ <string name="info_log_saved">Log erfolgreich gespeichert.</string>
+ <string name="info_log_cleared">Log wurde geleert.</string>
+ <string name="info_log_type_changed">Logtyp wurde verändert!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Letzte Position</string>
+ <string name="loc_net">Netzwerk</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">SAT</string>
+ <string name="loc_trying">Lokalisierung</string>
+ <string name="loc_no_addr">Adresse unbekannt</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Über c:geo</string>
+ <string name="menu_helpers">Nützliche Apps</string>
+ <string name="menu_settings">Einstellungen</string>
+ <string name="menu_history">Verlauf</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live-Karte</string>
+ <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="about_button">Über c:geo</string>
+ <string name="settings_button">Einstellungen</string>
+ <string name="type">Filter</string>
+ <string name="now_searching">Suche...</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Suche nach Caches</string>
+ <string name="caches_no_cache">Kein Cache</string>
+ <string name="caches_more_caches">Mehr Caches laden</string>
+ <string name="caches_more_caches_no">Keine weiteren Caches</string>
+ <string name="caches_more_caches_loading">Lade Caches...</string>
+ <string name="caches_downloading">Lade Caches...\nGeschätzte Zeit: </string>
+ <string name="caches_progress_loading_title">Lade Caches</string>
+ <string name="caches_progress_loading_text">Gespeicherte Caches</string>
+ <string name="caches_eta_ltm">Weniger als eine Minute</string>
+ <string name="caches_eta_mins"> Minuten</string>
+ <string name="caches_eta_min"> Minute</string>
+ <string name="caches_no_caches"> (keine Caches)</string>
+ <string name="caches_store_offline">Für Offline speichern</string>
+ <string name="caches_store_selected">Ausgewählte speichern</string>
+ <string name="caches_stored">Gespeichert</string>
+ <string name="caches_history">Verlauf</string>
+ <string name="caches_on_map">Zeige auf Karte</string>
+ <string name="caches_sort">Sortierung</string>
+ <string name="caches_sort_title">Sortieren nach</string>
+ <string name="caches_sort_distance">Entfernung</string>
+ <string name="caches_sort_difficulty">Schwierigkeit</string>
+ <string name="caches_sort_terrain">Gelände</string>
+ <string name="caches_sort_size">Größe</string>
+ <string name="caches_sort_favorites">Beliebtheit</string>
+ <string name="caches_sort_name">Name</string>
+ <string name="caches_sort_gccode">GC-Code (Alter)</string>
+ <string name="caches_sort_rating">Bewertung</string>
+ <string name="caches_sort_vote">Eigene Bewertung</string>
+ <string name="caches_sort_inventory">Inventaranzahl</string>
+ <string name="caches_select">Wähle von Liste</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_drop_selected">Ausgewählte löschen</string>
+ <string name="caches_drop_selected_ask">Bist du sicher, dass die ausgewählten Caches vom Gerät gelöscht werden sollen?</string>
+ <string name="caches_drop_all">Alle löschen</string>
+ <string name="caches_drop_all_ask">Bist du sicher, dass alle Caches von dieser Liste gelöscht werden sollen?</string>
+ <string name="caches_drop_stored">Gespeicherte löschen</string>
+ <string name="caches_drop_progress">Entferne Caches...</string>
+ <string name="caches_refresh_selected">Ausgewählte aktualisieren</string>
+ <string name="caches_refresh_all">Alle aktualisieren</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Bitte Text vom Bild abschreiben. Wichtig, um Koordinaten des Caches laden zu können. Optional, kann in den Einstellungen deaktiviert werden.</string>
+ <string name="caches_recaptcha_hint">Text vom Bild</string>
+ <string name="caches_recaptcha_continue">Fortfahren</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">Liste</string>
+ <string name="list_menu_create">Neue Liste</string>
+ <string name="list_menu_drop">Aktuelle Liste löschen</string>
+ <string name="list_menu_change">Andere Liste anzeigen</string>
+ <string name="list_title">Liste wählen</string>
+ <string name="list_inbox">Standardliste</string>
+ <string name="list_wpt">Wegpunkte</string>
+ <string name="list_dialog_create_title">Neue Liste</string>
+ <string name="list_dialog_create">Erstellen</string>
+ <string name="list_dialog_cancel">Abbrechen</string>
+ <string name="list_dialog_create_ok">Neue Liste wurde erstellt</string>
+ <string name="list_dialog_create_err">c:geo konnte die neue Liste nicht erstellen</string>
+ <string name="list_dialog_remove_title">Liste entfernen</string>
+ <string name="list_dialog_remove_description">Aktuelle Liste löschen? Alle Caches dieser Liste werden in die Standardliste verschoben.</string>
+ <string name="list_dialog_remove">Entfernen</string>
+ <string name="list_dialog_remove_ok">Liste wurde gelöscht</string>
+ <string name="list_dialog_remove_err">c:geo konnte die Liste nicht löschen</string>
+
+ <!-- about -->
+ <string name="about_changelog">Änderungen</string>
+ <string name="about_donate">Spenden</string>
+ <string name="about_detail">Details</string>
+ <string name="about_donation_less">Kleinere\nSpende</string>
+ <string name="about_donation_more">Spenden für\nEntwicklung</string>
+ <string name="about_contributors">Mitwirkende</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Benutzername</string>
+ <string name="init_password">Passwort</string>
+ <string name="init_passvote">Passwort</string>
+ <string name="init_login">Anmeldedaten überprüfen</string>
+ <string name="init_login_popup">Login</string>
+ <string name="init_login_popup_working">Bei geocaching.com anmelden...</string>
+ <string name="init_login_popup_ok">Login erfolgreich.</string>
+ <string name="init_login_popup_failed">Login fehlgeschlagen.</string>
+ <string name="init_login_popup_failed_reason">Login fehlgeschlagen wegen </string>
+ <string name="init_legal">Impressum</string>
+ <string name="init_go4cache_connect">Mit Go 4 Cache verbinden</string>
+ <string name="init_twitter_authorize">c:geo autorisieren</string>
+ <string name="init_twitter_publish">Status veröffentlichen wenn ein Cache gefunden wurde</string>
+ <string name="init_signature">Signatur</string>
+ <string name="init_signature_help_button">Hilfe</string>
+ <string name="init_signature_help_title">Tipps und Tricks für die Signatur</string>
+ <string name="init_signature_help_text">Verfasse eine Signatur für deinen Logtext.\nErlaubte Platzhalter sind: [DATE], [TIME], [USER] &amp; [NUMBER]. Diese werden beim Einfügen der Signatur durch ihre Werte ersetzt.</string>
+ <string name="init_languages">Übersetzung</string>
+ <string name="init_languages_description">Welche Sprachen verstehst du? (zweistelliger Code)</string>
+ <string name="init_languages_hint">de en es</string>
+ <string name="init_translate">Beschreibung &amp; Hint übersetzen</string>
+ <string name="init_other">Weitere Optionen</string>
+ <string name="init_skin">Helle Oberfläche (Neustart erforderlich)</string>
+ <string name="init_transparent">Transparenten Startbildschirm verwenden</string>
+ <string name="init_address">Position am Startbildschirm anzeigen</string>
+ <string name="init_captcha">Zeige CAPTCHA wenn notwendig</string>
+ <string name="init_useenglish">c:geo auf Englisch nutzen (Neustart erforderlich)</string>
+ <string name="init_exclude">Eigene und gefundene Caches ausblenden</string>
+ <string name="init_disabled">Deaktivierte Caches ausblenden</string>
+ <string name="init_offline">Statische Karten für Offline-Verwendung speichern</string>
+ <string name="init_units">Imperiale Einheiten (Meilen/Fuß)</string>
+ <string name="init_nav">Google Navigation verwenden</string>
+ <string name="init_autoload">Ausführliche Beschreibung automatisch laden</string>
+ <string name="init_livelist">Richtung zum Cache in der Cache-Liste anzeigen</string>
+ <string name="init_browser">c:geo als normalen Internet-Browser tarnen</string>
+ <string name="init_altitude">Höhenkorrektur</string>
+ <string name="init_altitude_description">Falls das GPS eine falsche Höhe ermittelt, kannst du diese durch Angabe eines positiven oder negativen Wertes in Metern korrigieren.</string>
+ <string name="init_clear">Login zurücksetzen</string>
+ <string name="init_cleared">c:geo hat die Anmeldedaten gelöscht.</string>
+ <string name="init_backup">Sicherung</string>
+ <string name="init_backup_backup">Sicherung</string>
+ <string name="init_backup_note">Hinweis: Diese Option sichert die Datenbank von c:geo. Nur Caches und Wegpunkte werden gesichert, keine Einstellungen. Login-Daten und Passwörter werden die App nicht verlassen.</string>
+ <string name="init_backup_restore">Wiederherstellung</string>
+ <string name="init_backup_success">Datenbank von c:geo wurde erfolgreich in Datei geschrieben</string>
+ <string name="init_backup_failed">Sicherung der Datenbank fehlgeschlagen.</string>
+ <string name="init_restore_success">Wiederherstellung beendet.</string>
+ <string name="init_restore_failed">Wiederherstellung fehlgeschlagen.</string>
+ <string name="init_backup_last">Backup verfügbar von</string>
+ <string name="init_backup_last_no">Keine Datei mit Datenbanksicherung gefunden.</string>
+ <string name="init_mapsettings">Karten-Einstellungen</string> <!-- since: 2.26 RC3 -->
+ <string name="init_mapsettings_description">Du kannst statt Google Maps alternativ Karten von OpenStreetMap nutzen. Du benötigst dafür eine Kartendatei zur Offline-Darstellung (siehe http://code.google.com/p/mapsforge/ für mehr Details)</string> <!-- since: 2.26 RC3 -->
+ <string name="init_mfmaps">Benutze OpenStreetMap</string> <!-- since: 2.26 RC3 -->
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">c:geo autorisieren</string>
+ <string name="auth_start">Starte Autorisierung</string>
+ <string name="auth_again">Neustarten</string>
+ <string name="auth_pin_hint">Twitter-PIN</string>
+ <string name="auth_finish">Fertig</string>
+ <string name="auth_dialog_wait">Warten auf Twitter...</string>
+ <string name="auth_dialog_pin_title">PIN Code</string>
+ <string name="auth_dialog_pin_message">Bitte den Twitter-PIN-Code eingeben, dies ist notwendig um die Autorisierung abzuschließen.</string>
+ <string name="auth_dialog_completed">c:geo ist nun autorisiert, Tweets bei Twitter zu erstellen.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Kein Cache</string>
+ <string name="cache_count_one">Ein Cache</string>
+ <string name="cache_count_more">Caches</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Aktualisieren</string>
+ <string name="cache_offline_drop">Löschen</string>
+ <string name="cache_offline_store">Speichern</string>
+ <string name="cache_offline_stored">Auf dem Gerät gespeichert</string>
+ <string name="cache_offline_not_ready">Nicht offline verfügbar</string>
+ <string name="cache_offline_time_about">vor etwa</string>
+ <string name="cache_offline_time_mins">Minuten</string>
+ <string name="cache_offline_time_mins_few">vor ein paar Minuten</string>
+ <string name="cache_offline_time_hour">einer Stunde</string>
+ <string name="cache_offline_time_hours">Stunden</string>
+ <string name="cache_offline_time_days">Tagen</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Attribute</string>
+ <string name="cache_inventory">Inventar</string>
+ <string name="cache_log_offline">Offline-Log</string>
+ <string name="cache_description">Beschreibung</string>
+ <string name="cache_description_long">Ausführliche Beschreibung</string>
+ <string name="cache_waypoints">Wegpunkte</string>
+ <string name="cache_waypoints_add">Wegpunkt hinzufügen</string>
+ <string name="cache_hint">Hinweis</string>
+ <string name="cache_logs">Logbuch</string>
+ <string name="cache_dialog_loading_details">Lade Cache-Details...</string>
+ <string name="cache_dialog_loading_description">Lade Cache-Beschreibung...</string>
+ <string name="cache_dialog_offline_save_title">Offline-Verwendung</string>
+ <string name="cache_dialog_offline_save_message">Speichere Cache für Offline-Verwendung...</string>
+ <string name="cache_dialog_offline_drop_title">Offline-Verwendung</string>
+ <string name="cache_dialog_offline_drop_message">Lösche Cache vom Gerät...</string>
+ <string name="cache_dialog_refresh_title">Aktualisieren</string>
+ <string name="cache_dialog_refresh_message">Aktualisieren der Cachedetails...</string>
+ <string name="cache_menu_navigate">Navigieren</string>
+ <string name="cache_menu_compass">Kompass</string>
+ <string name="cache_menu_tbt">GoogleMaps Navigation</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Auf Karte zeigen</string>
+ <string name="cache_menu_map_static">Statische Karte</string>
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_ext">Auf ext. Karte zeigen</string>
+ <string name="cache_menu_map_short">Karte</string>
+ <string name="cache_menu_map_ext_short">Externe Karte</string>
+ <string name="cache_menu_browser">Im Browser öffnen</string>
+ <string name="cache_menu_visit">Besuch loggen</string>
+ <string name="cache_menu_spoilers">Hinweisbild</string>
+ <string name="cache_menu_around">Caches im Umkreis</string>
+ <string name="cache_menu_event">Zum Kalender hinzufügen</string>
+ <string name="cache_menu_details">Details</string>
+ <string name="cache_menu_share">Weiterleiten</string>
+ <string name="cache_menu_move_list">Auf andere Liste verschieben</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Gespeicherter Log</string>
+ <string name="cache_status_found">Gefunden</string>
+ <string name="cache_status_archived">Archiviert</string>
+ <string name="cache_status_disabled">Deaktiviert</string>
+ <string name="cache_status_premium">Nur für Premium-Mitglieder</string>
+ <string name="cache_geocode">GC-Code</string>
+ <string name="cache_name">Name</string>
+ <string name="cache_type">Typ</string>
+ <string name="cache_distance">Entfernung</string>
+ <string name="cache_difficulty">Schwierigkeit</string>
+ <string name="cache_terrain">Terrain</string>
+ <string name="cache_rating">Bewertung</string>
+ <string name="cache_rating_of">von</string>
+ <string name="cache_favourite">Favorit</string>
+ <string name="cache_owner">Besitzer</string>
+ <string name="cache_hidden">Versteckt</string>
+ <string name="cache_event">Zeitangabe</string>
+ <string name="cache_location">Bundesland</string>
+ <string name="cache_coordinates">Koordinaten</string>
+ <string name="cache_elevation">Höhe</string>
+ <string name="cache_calendars">Kalender auswählen</string>
+ <string name="cache_spoiler_images_title">Spoilerbilder</string>
+ <string name="cache_spoiler_images_loading">Lade Spoilerbilder...</string>
+ <string name="cache_log_types">Logs</string>
+ <string name="cache_coordinates_no">Dieser Cache hat keine Koordinaten.</string> <!-- since: 2.26 RC2 -->
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Suche nach GPX-Dateien\nin</string>
+ <string name="gpx_import_loading_stored">Lade Caches aus GPX-Datei\nGespeichert:</string>
+ <string name="gpx_import_no_files">c:geo hat keine GPX-Dateien gefunden.</string>
+ <string name="gpx_import_caches_imported">Caches importiert.</string>
+ <string name="gpx_import_searching">Suche nach GPX-Dateien</string>
+ <string name="gpx_import_loading">Lade Caches aus GPX-Datei</string>
+ <string name="gpx_import_title">Importiere GPX-Datei</string>
+ <string name="gpx_import_title_reading_file">Lese Datei</string>
+ <string name="gpx_import_title_searching">Suche</string>
+ <string name="gpx_import_title_caches_imported">Ergebnis</string>
+
+ <!-- event -->
+ <string name="event_success">Event-Cache zum Kalender hinzugefügt</string>
+ <string name="event_fail">Fehler beim Hinzufügen des Event-Cache zum Kalender</string>
+
+ <!-- popup -->
+ <string name="popup_more">Mehr Details</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint">Wegpunkt</string>
+ <string name="waypoint_title">Wegpunkt</string>
+ <string name="waypoint_custom">Benutzerdefiniert</string>
+ <string name="waypoint_my_coordinates">Meine Koordinaten</string>
+ <string name="waypoint_bearing">Richtung</string>
+ <string name="waypoint_distance">Entfernung</string>
+ <string name="waypoint_name">Name</string>
+ <string name="waypoint_edit">Bearbeiten</string>
+ <string name="waypoint_delete">Löschen</string>
+ <string name="waypoint_edit_title">Wegpunkt bearbeiten</string>
+ <string name="waypoint_add_title">Wegpunkt hinzufügen</string>
+ <string name="waypoint_note">Notiz</string>
+ <string name="waypoint_save">Speichern</string>
+ <string name="waypoint_loading">Lade Wegpunkt...</string>
+ <string name="waypoint_unknown_coordinates">Unbekannte Koordinaten</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Diesen Eintrag auf Twitter veröffentlichen</string>
+
+ <!-- map -->
+ <string name="map_map">Karte</string>
+ <string name="map_live">Live-Karte</string>
+ <string name="map_view_satellite">Satellit</string>
+ <string name="map_view_map">Karte</string>
+ <string name="map_trail_show">Spur einblenden</string>
+ <string name="map_trail_hide">Spur ausblenden</string>
+ <string name="map_circles_show">Kreise anzeigen</string> <!-- since: 2.23 RC3 -->
+ <string name="map_circles_hide">Kreise verbergen</string> <!-- since: 2.23 RC3 -->
+ <string name="map_live_enable">Live einschalten</string>
+ <string name="map_live_disable">Live ausschalten</string>
+ <string name="map_static_title">Statische Karte</string>
+ <string name="map_static_loading">Lade statische Karte...</string>
+ <string name="map_token_err">c:geo konnte nur Teildaten herunterladen, die Koordinaten der Caches könnten verkehrt sein.</string> <!-- since: 2.26 RC3 -->
+
+ <!-- search -->
+ <string name="search_bar_hint">Suche nach Caches</string>
+ <string name="search_bar_desc">Caches (GC-Code, Stichwort), Trackables (TB-Code)</string>
+ <string name="search_coordinates">Koordinaten</string>
+ <string name="search_coordinates_button">Suche mit Koordinaten</string>
+ <string name="search_address">Adresse</string>
+ <string name="search_address_button">Suche mit Adresse</string>
+ <string name="search_gc">Geocode</string>
+ <string name="search_gc_button">Suche mit Geocode</string>
+ <string name="search_kw">Stichworte</string>
+ <string name="search_kw_prefill">Stichwörter</string>
+ <string name="search_kw_button">Suche mit Stichwörtern</string>
+ <string name="search_kw_caches">Caches nach Stichwort</string>
+ <string name="search_caches_found_by">Caches gefunden von</string>
+ <string name="search_caches_hidden_by">Caches versteckt von</string>
+ <string name="search_fbu">Gefunden von</string>
+ <string name="search_fbu_prefill">Benutzer</string>
+ <string name="search_fbu_button">Suche mit Benutzername</string>
+ <string name="search_hbu">Versteckt von</string>
+ <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_button">Suche nach Trackable</string>
+ <string name="search_destination">Ziel</string>
+ <string name="search_direction_rel">Vom aktuellen Standort</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Suche nach Caches</string>
+ <string name="search_caches_near">Caches in der Nähe</string>
+ <string name="search_address_started">Suche nach Orten</string>
+ <string name="search_address_result">Gefundene Orte</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">Lade Details des Trackable...</string>
+ <string name="trackable_log_touch">Logge Fund</string>
+ <string name="trackable_browser_open">Öffne im Browser</string>
+ <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_name">Name</string>
+ <string name="trackable_type">Typ</string>
+ <string name="trackable_owner">Eigentümer</string>
+ <string name="trackable_spotted">Zuletzt erspäht</string>
+ <string name="trackable_spotted_in_cache">In</string>
+ <string name="trackable_spotted_at_user">Bei</string>
+ <string name="trackable_spotted_unknown_location">Unbekannter Ort</string>
+ <string name="trackable_spotted_owner">Beim Besitzer</string>
+ <string name="trackable_origin">Ursprungsort</string>
+ <string name="trackable_unknown">Unbekannt</string>
+ <string name="trackable_released">Ausgesetzt</string>
+ <string name="trackable_distance">Gereiste Strecke</string>
+ <string name="trackable_touch">Trackable-Aktion</string>
+
+ <!-- user -->
+ <string name="user_menu_title">Über</string>
+ <string name="user_menu_view_hidden">Versteckte Caches</string>
+ <string name="user_menu_view_found">Gefundene Caches</string>
+ <string name="user_menu_open_browser">Profil im Browser öffnen</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigation</string>
+ <string name="compass_title">Kompass</string>
+ <string name="use_gps">GPS nutzen</string>
+ <string name="use_compass">Kompass nutzen</string>
+ <string name="destination_select">Ziel auswählen</string>
+ <string name="destination_set">Ziel setzen</string>
+
+ <!-- license -->
+ <string name="license">Lizenz</string>
+ <string name="license_show">Zeige Lizenz</string>
+ <string name="license_dismiss">Ablehnen</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">Anleitung</string>
+ <string name="helper_manual_description">Umfangreiche Anleitung für c:geo mit Beschreibung aller Möglichkeiten dieser App (auch versteckte).</string>
+ <string name="helper_locus_title">Locus</string>
+ <string name="helper_locus_description">Sehr gute App für Online- und Offline-Karten (nur Rasterkarten) mit vielen weiteren Funktionen wie z.B. Trackaufzeichnung, POIs und vieles mehr.</string>
+ <string name="helper_gpsstatus_title">GPS Status</string>
+ <string name="helper_gpsstatus_description">Das Radar dieser App kann in c:geo verwendet und zusätzlich viele GPS-bezogene Information abgerufen werden.</string>
+ <string name="helper_bluetoothgps_title">Bluetooth GPS</string>
+ <string name="helper_bluetoothgps_description">Ermöglicht ein externes GPS zu verwenden, um die Standortgenauigkeit zu erhöhen und die Batterie zu schonen.</string>
+
+ <!-- attributes (permissions -> allowed, not allowed) -->
+ <string name="attribute_dogs_yes">Hunde erlaubt</string>
+ <string name="attribute_dogs_no">Hunde nicht erlaubt</string>
+ <string name="attribute_bicycles_yes">Fahrräder erlaubt</string>
+ <string name="attribute_bicycles_no">Fahrräder nicht erlaubt</string>
+ <string name="attribute_motorcycles_yes">Motorräder erlaubt</string>
+ <string name="attribute_motorcycles_no">Motorräder nicht erlaubt</string>
+ <string name="attribute_quads_yes">Quads erlaubt</string>
+ <string name="attribute_quads_no">Quads nicht erlaubt</string>
+ <string name="attribute_jeeps_yes">Geländefahrzeuge erlaubt</string>
+ <string name="attribute_jeeps_no">Geländefahrzeuge nicht erlaubt</string>
+ <string name="attribute_snowmobiles_yes">Schneemobile erlaubt</string>
+ <string name="attribute_snowmobiles_no">Schneemobile nicht erlaubt</string>
+ <string name="attribute_horses_yes">Pferde erlaubt</string>
+ <string name="attribute_horses_no">Pferde nicht erlaubt</string>
+ <string name="attribute_campfires_yes">Lagerfeuer erlaubt</string>
+ <string name="attribute_campfires_no">Lagerfeuer nicht erlaubt</string>
+ <string name="attribute_rv_yes">Wohnmobile erlaubt</string>
+ <string name="attribute_rv_no">Wohnmobile nicht erlaubt</string>
+
+ <!-- attributes (conditions -> yes, no) -->
+ <string name="attribute_kids_yes">für Kinder geeignet</string>
+ <string name="attribute_kids_no">nicht für Kinder geeignet</string>
+ <string name="attribute_onehour_yes">benötigt weniger als eine Stunde</string>
+ <string name="attribute_onehour_no">benötigt mehr als eine Stunde</string>
+ <string name="attribute_scenic_yes">herrliche Aussicht</string>
+ <string name="attribute_scenic_no">keine besondere Aussicht</string>
+ <string name="attribute_hiking_yes">anstrengender Marsch</string>
+ <string name="attribute_hiking_no">kein anstrengender Marsch</string>
+ <string name="attribute_climbing_yes">schwierige Kletterei</string>
+ <string name="attribute_climbing_no">keine schwierige Kletterei</string>
+ <string name="attribute_wading_yes">Waten möglicherweise nötig</string>
+ <string name="attribute_wading_no">Waten nicht nötig</string>
+ <string name="attribute_swimming_yes">Schwimmen möglicherweise nötig</string>
+ <string name="attribute_swimming_no">Schwimmen nicht nötig</string>
+ <string name="attribute_available_yes">zu jeder Zeit erreichbar</string>
+ <string name="attribute_available_no">nicht zu jeder Zeit erreichbar</string>
+ <string name="attribute_night_yes">nachts empfohlen</string>
+ <string name="attribute_night_no">nachts nicht empfohlen</string>
+ <string name="attribute_winter_yes">im Winter zugänglich</string>
+ <string name="attribute_winter_no">im Winter nicht zugänglich</string>
+ <string name="attribute_stealth_yes">heimlich vorgehen</string>
+ <string name="attribute_stealth_no">Heimlichkeit nicht notwendig</string>
+ <string name="attribute_firstaid_yes">muss gewartet werden</string>
+ <string name="attribute_firstaid_no">muss nicht gewartet werden</string>
+ <string name="attribute_cow_yes">Achtung, Tierzucht</string>
+ <string name="attribute_cow_no">keine Tierzucht</string>
+ <string name="attribute_field_puzzle_yes">Geländerätsel</string>
+ <string name="attribute_field_puzzle_no">kein Geländerätsel</string>
+ <string name="attribute_nightcache_yes">Nacht-Cache</string>
+ <string name="attribute_nightcache_no">kein Nacht-Cache</string>
+ <string name="attribute_parkngrab_yes">halten und mitnehmen</string>
+ <string name="attribute_parkngrab_no">kein halten und mitnehmen</string>
+ <string name="attribute_abandonedbuilding_yes">leerstehendes Gebäude</string>
+ <string name="attribute_abandonedbuilding_no">kein leerstehendes Gebäude</string>
+ <string name="attribute_hike_short_yes">kurzer Marsch (weniger als 1 km)</string>
+ <string name="attribute_hike_short_no">kein kurzer Marsch</string>
+ <string name="attribute_hike_med_yes">mittlerer Marsch (1 bis 10 km)</string>
+ <string name="attribute_hike_med_no">kein mittlerer Marsch</string>
+ <string name="attribute_hike_long_yes">langer Marsch (mehr als 10 km)</string>
+ <string name="attribute_hike_long_no">kein langer Marsch</string>
+ <string name="attribute_landf_yes">\'Lost and found\' Tour</string>
+ <string name="attribute_landf_no">keine \'Lost and found\' Tour</string>
+ <string name="attribute_sponsored_yes">gesponserter Cache</string>
+ <string name="attribute_sponsored_no">nicht gesponserter Cache</string>
+
+ <!-- attributes (equipment -> required, not required) -->
+ <string name="attribute_fee_yes">Eintrittsgeld notwendig</string>
+ <string name="attribute_fee_no">kein Eintrittsgeld notwendig</string>
+ <string name="attribute_rappelling_yes">Kletterausrüstung notwendig</string>
+ <string name="attribute_rappelling_no">Kletterausrüstung nicht notwendig</string>
+ <string name="attribute_boat_yes">Boot notwendig</string>
+ <string name="attribute_boat_no">Boot nicht notwendig</string>
+ <string name="attribute_scuba_yes">Tauchausrüstung notwendig</string>
+ <string name="attribute_scuba_no">Tauchausrüstung nicht notwendig</string>
+ <string name="attribute_flashlight_yes">Taschenlampe notwendig</string>
+ <string name="attribute_flashlight_no">Taschenlampe nicht notwendig</string>
+ <string name="attribute_UV_yes">UV-Taschenlampe notwendig</string>
+ <string name="attribute_UV_no">UV-Taschenlampe nicht notwendig</string>
+ <string name="attribute_snowshoes_yes">Schneeschuhe notwendig</string>
+ <string name="attribute_snowshoes_no">Schneeschuhe nicht notwendig</string>
+ <string name="attribute_skiis_yes">Ski notwendig</string>
+ <string name="attribute_skiis_no">Ski nicht notwendig</string>
+ <string name="attribute_s_tool_yes">Besondere Werkzeuge notwendig</string>
+ <string name="attribute_s_tool_no">Besondere Werkzeuge nicht notwendig</string>
+ <string name="attribute_wirelessbeacon_yes">Radiosignal</string>
+ <string name="attribute_wirelessbeacon_no">kein Radiosignal</string>
+
+ <!-- attributes (hazards -> present, not present) -->
+ <string name="attribute_poisonoak_yes">giftige Pflanzen</string>
+ <string name="attribute_poisonoak_no">keine giftige Pflanzen</string>
+ <string name="attribute_dangerousanimals_yes">gefährliche Tiere</string>
+ <string name="attribute_dangerousanimals_no">keine gefährlichen Tiere</string>
+ <string name="attribute_ticks_yes">Zecken</string>
+ <string name="attribute_ticks_no">keine Zecken</string>
+ <string name="attribute_mine_yes">verlassene Minen</string>
+ <string name="attribute_mine_no">keine verlassenen Minen</string>
+ <string name="attribute_cliff_yes">Kliff/Abhang</string>
+ <string name="attribute_cliff_no">kein Kliff/Abhang</string>
+ <string name="attribute_hunting_yes">Jagdgebiet</string>
+ <string name="attribute_hunting_no">kein Jagdgebiet</string>
+ <string name="attribute_danger_yes">Gefährliches Gebiet</string>
+ <string name="attribute_danger_no">kein gefährliches Gebiet</string>
+ <string name="attribute_thorn_yes">Dornen</string>
+ <string name="attribute_thorn_no">keine Dornen</string>
+
+ <!-- attributes (facilities -> yes, no) -->
+ <string name="attribute_wheelchair_yes">rollstuhlgängig</string>
+ <string name="attribute_wheelchair_no">nicht rollstuhlgängig</string>
+ <string name="attribute_parking_yes">Parkplatz vorhanden</string>
+ <string name="attribute_parking_no">kein Parkplatz vorhanden</string>
+ <string name="attribute_public_yes">öffentliche Verkehrsmittel</string>
+ <string name="attribute_public_no">keine öffentlichen Verkehrsmittel</string>
+ <string name="attribute_water_yes">Trinkwasser in der Nähe</string>
+ <string name="attribute_water_no">kein Trinkwasser in der Nähe</string>
+ <string name="attribute_restrooms_yes">öffentliche Toiletten in der Nähe</string>
+ <string name="attribute_restrooms_no">keine öffentliche Toiletten in der Nähe</string>
+ <string name="attribute_phone_yes">Telefon in der Nähe</string>
+ <string name="attribute_phone_no">Telefon in der Nähe</string>
+ <string name="attribute_picnic_yes">Picknicktische in der Nähe</string>
+ <string name="attribute_picnic_no">keine Picknicktische in der Nähe</string>
+ <string name="attribute_camping_yes">Camping möglich</string>
+ <string name="attribute_camping_no">Camping nicht möglich</string>
+ <string name="attribute_stroller_yes">mit Kinderwagen erreichbar</string>
+ <string name="attribute_stroller_no">nicht mit Kinderwagen erreichbar</string>
+ <string name="attribute_fuel_yes">Tankstelle in der Nähe</string>
+ <string name="attribute_fuel_no">keine Tankstelle in der Nähe</string>
+ <string name="attribute_food_yes">Lebensmittel in der Nähe</string>
+ <string name="attribute_food_no">keine Lebensmittel in der Nähe</string>
+
+ <!-- next things -->
+ <string name="legal_note">Um die Dienste von Geocaching.com nutzen zu können, müssen die <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeak-Nutzungsbedingungen</a> (englisch) akzeptiert werden.</string>
+ <string name="quote">Um Geocachen einfacher zu machen, um es Anwendern bequemer zu machen.</string>
+ <string name="powered_by">carnero</string>
+ <string name="author">Autor: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Website: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="nutshellmanual">Benutzung: <a href="http://cgeo.carnero.cc/manual/">c:geo Kurzanleitung</a></string>
+ <string name="about_go4cache">Service <b>Go 4 cache</b> erlaubt es, andere Geocacher in Echtzeit auf der Karte zu sehen (in <b>c:geo</b> oder im Browser). Es kann beispielsweise anzeigen, welchen Cache sie suchen. <b>Go 4 cache</b> erlaubt <b>c:geo</b> die aktuelle Position zu veröffentlichen (nur wenn <b>c:geo</b> ausgeführt wird).</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="about_auth_1">Der folgende Prozess erlaubt es <b>c:geo</b> auf den persönlichen Twitter-Account zuzugreifen, wenn zugestimmt wird.</string>
+ <string name="about_auth_2">Ein Klick auf \"Starte Autorisierung\" öffnet eine Twitter-Seite in einem Browserfenster. Durch die Anmeldung und die Bestätigung wird <b>c:geo</b> ermöglicht, auf den persönlichen Twitter-Account zuzugreifen. Wird dies bestätigt, nennt Twitter eine numerische PIN, diese muss kopiert und in <b>c:geo</b> eingefügt werden. Das ist alles.</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
new file mode 100644
index 0000000..89aadc4
--- /dev/null
+++ b/res/values-es/strings.xml
@@ -0,0 +1,606 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo brújula</string>
+
+ <!-- basics -->
+ <string name="cache">Escondite</string>
+ <string name="detail">Detalle</string>
+ <string name="search">Buscar</string>
+ <string name="settings">Ajustes</string>
+ <string name="helpers">¿Qué instalar?</string>
+ <string name="about">Sobre c:geo</string>
+ <string name="helper">Si quieres aprender cosas sobre <b>c:geo</b>?\nEcha un ojo a nuestro manual.</string>
+ <string name="database_error_title">Problema con la base de datos</string>
+ <string name="database_error_message">c:geo no se ha podido conectar a la base de datos interna.\nIntenta arrancar c:geo un poco más tarde. Si has visto este mensaje muchas veces, ve a los ajustes del teléfono / Aplicaciones / c:geo y pulsa el botçon borrar datos. O desinstálalo e instálalo de nuevo. Lamentamos los problemas.</string>
+
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Compartir enlace a escondite</string>
+
+ <!-- caches -->
+ <string name="all">Todos</string>
+ <string name="all_types">Todos los escondites</string>
+ <string name="traditional">Tradicionales</string>
+ <string name="multi">Multis</string>
+ <string name="mystery">Desconocidos</string>
+ <string name="letterbox">Buzón híbrido</string>
+ <string name="event">Por pistas</string>
+ <string name="mega">Mega-eventos</string>
+ <string name="earth">Educativos (Earth)</string>
+ <string name="cito">Limpieza de escondites</string>
+ <string name="webcam">Webcams</string>
+ <string name="virtual">Virtuales</string>
+ <string name="wherigo">Wherigo</string>
+ <string name="lostfound">Perdidos y encontrados</string>
+ <string name="ape">Proyecto APE</string>
+ <string name="gchq">Groundspeak HQ</string>
+ <string name="gps">Exhibición de escondites GPS </string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Ubicación final</string>
+ <string name="wp_stage">Etapa de multi escondite</string>
+ <string name="wp_puzzle">Preguntar sin contestar</string>
+ <string name="wp_pkg">Zona de aparcamiento</string>
+ <string name="wp_trailhead">Sendero</string>
+ <string name="wp_waypoint">Punto de referencia</string>
+
+ <!-- logs -->
+ <string name="log_found">Encontrado</string>
+ <string name="log_dnf">No encontrado</string>
+ <string name="log_note">Nota</string>
+ <string name="log_published">Publicado</string>
+ <string name="log_enabled">Activo</string>
+ <string name="log_disabled">Inactivo</string>
+ <string name="log_attend">Iré</string>
+ <string name="log_attended">Asistí</string>
+ <string name="log_retrieved">Obtenido</string>
+ <string name="log_placed">Colocado</string>
+ <string name="log_grabbed">Guardado en alguna parte</string>
+ <string name="log_maintained">Mantenimiento efectuado</string>
+ <string name="log_maintenance_needed">Necesita mantenimiento</string>
+ <string name="log_maintenance_owner">Mantenimiento</string>
+ <string name="log_update">Coordenadas actualizadas</string>
+ <string name="log_archived">Archivado</string>
+ <string name="log_needs_archived">Necesita ser archivado</string>
+ <string name="log_discovered">Descubierto</string>
+ <string name="log_reviewed">Nota del revisor</string>
+ <string name="log_taken">Visita</string>
+ <string name="log_tb_nothing">No hacer nada</string>
+ <string name="log_tb_visit">Visita</string>
+ <string name="log_tb_drop">Colocar aquí</string>
+ <string name="log_tb_changeall">Cambiar todo</string>
+ <string name="log_save">Guardar</string>
+ <string name="log_saving">Guardando registo...</string>
+ <string name="log_clear">Limpiar</string>
+ <string name="log_post">Enviar registro</string>
+ <string name="log_post_rate">Enviar registro y puntuación</string>
+ <string name="log_post_no_rate">Enviar registro sin puntuar</string>
+ <string name="log_add">Añadir</string>
+ <string name="log_date">Fecha</string>
+ <string name="log_time">Hora</string>
+ <string name="log_date_time">Fecha y hora</string>
+ <string name="log_rating">Puntuación</string>
+ <string name="log_no_rating">Sin puntuación</string>
+ <string name="log_stars_1">1 estrella</string>
+ <string name="log_stars_2">2 estrellas</string>
+ <string name="log_stars_3">3 estrellas</string>
+ <string name="log_stars_4">4 estrellas</string>
+ <string name="log_stars_5">5 estrellas</string>
+ <string name="log_webcam">Foto de webcam tomada</string>
+ <string name="log_new_log">Registro</string>
+ <string name="log_new_log_text">Texto del registro</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Aceptar</string>
+ <string name="err_start">Comunicación no iniciada</string>
+ <string name="err_parse">Error procesando la página de acceso</string>
+ <string name="err_server">Error conectando a geocaching.com (¿servidor o conexión caidos?)</string>
+ <string name="err_login">No hay información de acceso guardada</string>
+ <string name="err_login_failed">Lo siento, c:geo no puede conectarse.</string>
+ <string name="err_unknown">Error desconocido</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_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_store">Lo siento, c:geo no puede almacenar el escondite.</string>
+ <string name="err_drop">Lo siento, c:geo no puede omitir el escondite.</string>
+ <string name="err_title_problem">Problema</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_cache_find_next">Lo siento, c:geo no puede encontrar los siguientes escondites.</string>
+ <string name="err_detail_cache_forgot">Lo siento, c:geo ha olvidado el escondite que quieres.</string>
+ <string name="err_detail_cache_forgot_visit">Lo siento, c:geo ha olvidado que escondite has visitado.</string>
+ <string name="err_detail_cache_language">c:geo no puede leer algunos detalles del escondite. Verifica que la web geocaching.com website esté configurada en inglés. por desgracia, c:geo no entiende otras localizaciones.</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_still_removing">Seguir borrando este escondite.</string>
+ <string name="err_detail_still_saving">Seguir guardando este escondite.</string>
+ <string name="err_detail_still_refreshing">Seguir recargando este escondite.</string>
+ <string name="err_radar_title">El radar no está instalado.</string>
+ <string name="err_radar_message">Esta acción requiere instalar el radar. ¿Quieres instalarlo?</string>
+ <string name="err_radar_market">c:geo no puede cargar el Android Market Para buscar la aplicación Radar.</string>
+ <string name="err_radar_generic">Lo siento, c:geo no puede arrancar el Radar. ¿Está instalado?</string>
+ <string name="err_navigation_no">c:geo no encuentra ninguna navegación soportada.</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_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_init_cleared">Lo siento, c:geo no puede borrar la información registrada.</string>
+ <string name="err_no_chaches">Lo siento, c:geo no ha podido abrir el/los escondite/s</string>
+ <string name="err_download_fail">Lo siento, c:geo no ha podido descargar escondites a causa de </string>
+ <string name="err_update_fail">Error al actualizar la distancia recorrida.</string>
+ <string name="err_list_load_fail">Lo siento, c:geo no ha podido cargar la lista de escondites.</string>
+ <string name="err_store_failed">Lo siento, c:geo no puede guardar el escondite.</string>
+ <string name="err_refresh_failed">Lo siento, c:geo no puede actualizar el escondite.</string>
+ <string name="err_drop_failed">Lo siento, c:geo no puede omitir el escondite.</string>
+ <string name="err_dwld_details_failed">Lo siento, c:geo no ha podido descargar los detalles del escondite.</string>
+ <string name="err_dwld_details_failed_reason">Lo siento, c:geo no ha podido descargar los detalles del escondite debido a </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_manual_title">El manual no está instalado.</string>
+ <string name="err_manual_message">El manual de c:geo no se encuentra en tu dispositivo.¿Debería instalarse?</string>
+ <string name="err_manual_market">c:geo No puede abrir el Android MArket para buscar el manual.</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_details_download">Lo siento, c:geo no ha podido descargar los detalles del rastreable a causa de</string>
+ <string name="err_tb_forgot">Lo siento, c:geo ha olvidado qué rastreable quieres.</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_unknown">Lo siento, c:geo ha olvidado qué punto de referencia quieres visualizar.</string>
+ <string name="err_waypoint_add_failed">Lo siento, c:geo no ha podido añadir tu punto de referencia.</string>
+ <string name="err_waypoint_load_failed">Lo siento, c:geo no ha podido cargar el punto de referencia.</string>
+ <string name="err_waypoint_delete_failed">Lo siento, c:geo no puede borrar el punto de referencia.</string>
+ <string name="err_point_unknown_position">Lo siento, c:geo n puedo identificar donde 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_point_location_error">Lo siento, c:geo no puede ubicar ese punto de referencia.</string>
+ <string name="err_navigation_not_found">c:geo no encuentra ninguna navegación soportada.</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_failed_server">Lo siento, c:geo no ha podido enviar el registro porque el servidor no responde.</string>
+ <string name="err_log_post_failed">Lo siento, c:geo no ha podido enviar el registro.</string>
+ <string name="err_log_post_failed_because">Lo siento, c:geo no ha podido enviar el registro porque </string>
+
+ <string name="err_search_address_no_match">Lo siento, c:geo no encuentra ningún lugar coincidente.</string>
+ <string name="err_search_address_forgot">Lo siento, c:geo ha olvidado la dirección que buscabas.</string>
+ <string name="err_search_address">Buscando lugares</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_bear">Lo siento, c:geo no puede procesar la orientación.</string>
+ <string name="err_parse_dist">Lo siento, c:geo can\'t no puede procesar la distancia.</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_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_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>
+
+ <string name="info_altitude">Altitud actual</string>
+ <string name="info_distance">Distancia recorrida</string>
+ <string name="info_distance_cleared">La distancia recorrida ha sido borrada.</string>
+ <string name="info_since">\n(desde </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_cleared">Registro borrado.</string>
+ <string name="info_log_type_changed">¡El tipo de registro ha sido cambiado!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Última conocida</string>
+ <string name="loc_net">Red</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Intentando ubicar</string>
+ <string name="loc_no_addr">Dirección desconocida</string>
+
+ <!-- standard menu -->
+ <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_filter">Filtro</string>
+
+ <!-- main screen -->
+ <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="about_button">Sobre</string>
+ <string name="settings_button">Ajustes</string>
+ <string name="type">Tipo</string>
+ <string name="now_searching">Buscando ahora</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Buscando escondites</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_downloading">Descargando escondites...\nFaltan: </string>
+ <string name="caches_progress_loading_title">Cargando escondites</string>
+ <string name="caches_progress_loading_text">Escondites almacenados en el dispositivo</string>
+ <string name="caches_eta_ltm">Menos de un minuto</string>
+ <string name="caches_eta_mins"> minutos</string>
+ <string name="caches_eta_min"> minuto</string>
+ <string name="caches_no_caches"> (sin escondites)</string>
+ <string name="caches_store_offline">Usar sin conexión luego</string>
+ <string name="caches_store_selected">Almacenamiento seleccionado</string>
+ <string name="caches_stored">Almacenados</string>
+ <string name="caches_history">Historial</string>
+ <string name="caches_on_map">Ver en mapa</string>
+ <string name="caches_sort">Ordenar</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_title">Ordenar por</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_distance">distancia</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_difficulty">dificultad</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_terrain">terreno</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_size">tamaño</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_favorites">popularidad</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_select">Elegir de la lista</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_drop_selected">Descartar los seleccionados</string>
+ <string name="caches_drop_selected_ask">¿Quieres borrar los escondites seleccionados del dispositivo?</string>
+ <string name="caches_drop_all">Descartar todos</string>
+ <string name="caches_drop_all_ask">¿Quieres borrar todos los escondites guardados en el dispositivo?</string>
+ <string name="caches_drop_stored">Descartar guardados</string>
+ <string name="caches_drop_progress">Borrando escondites</string>
+ <string name="caches_refresh_selected">Actualizar seleccionados</string>
+ <string name="caches_refresh_all">Actualizar todos</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">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_hint">Texto de la imagen</string>
+ <string name="caches_recaptcha_continue">Continuar</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">Lista</string>
+ <string name="list_menu_create">Crear nueva lista</string>
+ <string name="list_menu_drop">Borrar lista actual</string>
+ <string name="list_title">Escoger lista</string>
+ <string name="list_inbox">Guardadas</string>
+ <string name="list_wpt">Puntos de referencia</string>
+ <string name="list_dialog_create_title">Nueva lista</string>
+ <string name="list_dialog_create">Crear</string>
+ <string name="list_dialog_cancel">Cancelar</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">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>
+
+ <!-- about -->
+ <string name="about_changelog">Cambios</string>
+ <string name="about_donate">Donar</string>
+ <string name="about_detail">Detalles</string>
+ <string name="about_donation_less">Donar\nmenos</string>
+ <string name="about_donation_more">Donar\nmas</string>
+ <string name="about_contributors">Colaboradores</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Usuario</string>
+ <string name="init_password">Contraseña</string>
+ <string name="init_passvote">Contraseña</string>
+ <string name="init_login">Acceder</string>
+ <string name="init_login_popup">Acceso</string>
+ <string name="init_login_popup_working">Accediendo a geocaching.com...</string>
+ <string name="init_login_popup_ok">Acceso conseguido.</string>
+ <string name="init_login_popup_failed">Error en el acceso.</string>
+ <string name="init_login_popup_failed_reason">El acceso ha fallado debido a </string>
+ <string name="init_legal">Nota legal</string>
+ <string name="init_go4cache_connect">Conectar a Go 4 Cache</string>
+ <string name="init_twitter_authorize">Autorizar a c:geo</string>
+ <string name="init_twitter_publish">Publicar estado cuando se encuente un escondite</string>
+ <string name="init_signature">Firma</string>
+ <string name="init_signature_help_button">Ayuda</string>
+ <string name="init_signature_help_title">Trucos para la firma</string>
+ <string name="init_signature_help_text">Escribe la firma que quieres usar en los registros.\nLas palabras especiales que puedes usar son: [DATE], [TIME], [USER] y [NUMBER].\nSerán reemplazados por sus valores al insertar la firma.</string>
+ <string name="init_languages">Traducción</string>
+ <string name="init_languages_description">¿Qué lenguajes no necesitas traducir? Indica códigos de idioma de 2 caracteres.</string>
+ <string name="init_languages_hint">en es pt fr</string>
+ <string name="init_translate">Traducir descripción y pista</string>
+ <string name="init_other">Otras opciones</string>
+ <string name="init_skin">Fondo blanco (necesita reiniciar c:geo)</string>
+ <string name="init_transparent">Usar pantalla de inicio transparente</string>
+ <string name="init_address">Mostrar dirección en la pantalla principal</string>
+ <string name="init_captcha">Mostrar CAPTCHA si es necesario</string>
+ <string name="init_useenglish">Usar inglés interno (necesita reiniciar c:geo)</string>
+ <string name="init_exclude">Excluir encontrados y propios</string>
+ <string name="init_disabled">Excluir escondites desactivados</string>
+ <string name="init_offline">Guardar mapas para usar sin conexión</string>
+ <string name="init_units">Usar millas/pies (unidades imperiales)</string>
+ <string name="init_nav">Usar Google Navigation</string>
+ <string name="init_autoload">Autocargar descripción larga</string>
+ <string name="init_livelist">Mostrar dirección a los escondites en su listado</string>
+ <string name="init_browser">Identificar c:geo como navegador por defecto</string>
+ <string name="init_clear">Borrar acceso</string>
+ <string name="init_cleared">c:geo ha borrado la información de acceso.</string>
+ <string name="init_backup">Backup</string>
+ <string name="init_backup_backup">Backup</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_restore">Restaurar</string>
+ <string name="init_backup_success">La base de datos de c:geo se ha copiado satisfactoriamente</string>
+ <string name="init_backup_failed">Ha fallado 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_backup_last">Copia guardada el</string>
+ <string name="init_backup_last_no">No hay ninguna copia de seguridad.</string>
+
+ <!-- auth -->
+ <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_pin_hint">PIN asignado por Twitter</string>
+ <string name="auth_finish">Fin</string>
+ <string name="auth_dialog_wait">Esperando por Twitter...</string>
+ <string name="auth_dialog_pin_title">Código PIN</string>
+ <string name="auth_dialog_pin_message">Debes usar el codigo PIN suministrado por Twitter. Es obligatorio completar la autorización.</string>
+ <string name="auth_dialog_completed">c:geo ahora está autorizado para publicar en Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Sin escondites</string>
+ <string name="cache_count_one">Un escondite</string>
+ <string name="cache_count_more">Escondites</string>
+ <string name="cache_offline">Desconectado</string>
+ <string name="cache_offline_refresh">Actualizar</string>
+ <string name="cache_offline_drop">Tirar</string>
+ <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_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>
+ <string name="cache_offline_time_hours">horas atrás</string>
+ <string name="cache_offline_time_days">días atrás</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Atributos</string>
+ <string name="cache_inventory">Inventario</string>
+ <string name="cache_log_offline">Registro desconectado</string>
+ <string name="cache_description">Descripción</string>
+ <string name="cache_description_long">Descripción larga</string>
+ <string name="cache_waypoints">Puntos de referencia</string>
+ <string name="cache_waypoints_add">Añadir referencia</string>
+ <string name="cache_hint">Pista</string>
+ <string name="cache_logs">Bitácora</string>
+ <string name="cache_dialog_loading_details">Cargando detalles del escondite...</string>
+ <string name="cache_dialog_loading_description">Cargando descripción del escondite...</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_drop_title">Desconectado</string>
+ <string name="cache_dialog_offline_drop_message">Borrando escondite 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_menu_navigate">Navegar</string>
+ <string name="cache_menu_compass">Brújula</string>
+ <string name="cache_menu_tbt">Paso a paso</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Ver en mapa</string>
+ <string name="cache_menu_map_static">Mapas estáticos</string>
+
+
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_short">Mapas</string>
+ <string name="cache_menu_map_ext_short">Mapa ext.</string>
+ <string name="cache_menu_browser">Navegador</string>
+ <string name="cache_menu_visit">Enviar visita</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_details">Detalles</string>
+ <string name="cache_menu_share">Compartir escondite</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_status_archived">Archivado</string>
+ <string name="cache_status_disabled">Desactivado</string>
+ <string name="cache_status_premium">Sólo para miembros Premium</string>
+ <string name="cache_geocode">Código GC</string>
+ <string name="cache_name">Nombre</string>
+ <string name="cache_type">Tipo</string>
+ <string name="cache_distance">Distancia</string>
+ <string name="cache_difficulty">Dificultad</string>
+ <string name="cache_terrain">Terreno</string>
+ <string name="cache_rating">Puntuación</string>
+ <string name="cache_rating_of">de</string>
+ <string name="cache_favourite">Favorito</string>
+ <string name="cache_owner">Propietario</string>
+ <string name="cache_hidden">Oculto</string>
+ <string name="cache_event">Fecha</string>
+ <string name="cache_location">Ubicación</string>
+ <string name="cache_coordinates">Coordenadas</string>
+ <string name="cache_elevation">Elevación</string>
+ <string name="cache_calendars">Elegir calendario</string>
+ <string name="cache_spoiler_images_title">Imágenes reveladoras</string>
+ <string name="cache_spoiler_images_loading">Cargando imágenes reveladoras...</string>
+ <string name="cache_log_types">Tipos de registro</string> <!-- Since: 2.10 RC2 -->
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Buscando archivos .gpx\nen</string>
+ <string name="gpx_import_loading_stored">Cargando escondites del archivo .gpx\nGuardados:</string>
+ <string name="gpx_import_no_files">Lo siento, c:geo no ha encontrado archivos .gpx.</string>
+ <string name="gpx_import_caches_imported">escondites importados</string>
+ <string name="gpx_import_searching">Buscando archivos .gpx</string>
+ <string name="gpx_import_loading">Cargando escondites del archivo .gpx</string>
+ <string name="gpx_import_title">Importar GPX</string>
+ <string name="gpx_import_title_reading_file">Leyendo archivo</string>
+ <string name="gpx_import_title_searching">Buscando</string>
+ <string name="gpx_import_title_caches_imported">Resultados</string>
+
+ <!-- event -->
+ <string name="event_success">Escondite/Evento añadido al calendario</string>
+ <string name="event_fail">Error al añadir escondite/evento al calendario</string>
+
+ <!-- popup -->
+ <string name="popup_more">Más detalles</string>
+ <string name="popup_offline">Desconectado</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Punto de referencia</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_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_note">Nota</string>
+ <string name="waypoint_save">Guardar</string>
+ <string name="waypoint_loading">Cargando punto de referencia...</string>
+ <string name="waypoint_unknown_coordinates">Coordenadas desconocidas</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Publicar en Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Mapa</string>
+ <string name="map_live">Mapa activo</string>
+ <string name="map_view_satellite">Satélite</string>
+ <string name="map_view_map">Ver mapa</string>
+ <string name="map_trail_show">Mostrar rastro</string>
+ <string name="map_trail_hide">Ocultar rastro</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>
+
+ <!-- search -->
+ <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_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_gc">Geocode</string>
+ <string name="search_gc_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_button">Buscar por palabra clave</string>
+ <string name="search_kw_caches">Escondites por palabra clave</string>
+ <string name="search_caches_found_by">Encondites encontrados por</string>
+ <string name="search_caches_hidden_by">Escondites ocultos por</string>
+ <string name="search_fbu">Encontrar 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_hbu">Oculto por usuario</string>
+ <string name="search_hbu_prefill">Propietario</string>
+ <string name="search_hbu_button">Buscar por propietario</string>
+ <string name="search_tb">Rastreable</string>
+ <string name="search_tb_hint">Identificación del rastreable</string>
+ <string name="search_tb_button">Buscar rastreables</string>
+ <string name="search_destination">Destino</string>
+ <string name="search_direction_rel">Desde esta posición</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Buscar escondites</string>
+ <string name="search_caches_near">Escondites cercanos</string>
+ <string name="search_address_started">Buscando lugares</string>
+ <string name="search_address_result">Lugares encontrados</string>
+
+ <!-- trackable -->
+ <string name="trackable">Rastreable</string>
+ <string name="trackable_select_title">Rastreables</string>
+ <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_details">Detalles</string>
+ <string name="trackable_image">Imagen</string>
+ <string name="trackable_code">Código TB</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_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_distance">Recorrido</string>
+ <string name="trackable_touch">Contacto</string>
+
+ <!-- user -->
+ <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_open_browser">Abrir perfil en el navegador</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navegación</string>
+ <string name="compass_title">Brújula</string>
+ <string name="use_gps">Usar GPS</string>
+ <string name="use_compass">Usar brújula</string>
+ <string name="destination_select">Seleccionar destino</string>
+ <string name="destination_set">Elegir destino</string>
+
+ <!-- license -->
+ <string name="license">Licencia</string>
+ <string name="license_show">Mostrar licencia</string>
+ <string name="license_dismiss">Descartar</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">Manual</string>
+ <string name="helper_manual_description">Sencillo manual de c:geo que contiene todas las capacidades de este programa (incluidas las ocultas).</string>
+ <string name="helper_locus_title">Locus</string>
+ <string name="helper_locus_description">Sencilla aplicación que muestra mapas en linea y permite descargarlos para ser usados sin conexión (sólo mapas no vectoriales). Tambien permite registrar el recorrido, gestionar puntos de interés y más funciones interesantes.</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>
+ <string name="helper_bluetoothgps_description">Te permite usar un GPS externo para tener mejor señal, más precisa y ahorrar batería en tu dispositivo.</string>
+
+ <!-- next things -->
+ <string name="legal_note">Para utilizar los servicios de geocaching.com, debes aceptar las <a href="http://www.geocaching.com/about/termsofuse.aspx">condiciones de Groundspeak</a>.</string>
+ <string name="quote">Para hacer el geocaching más sencillo, para hacer a los usuarios más vagos.</string>
+ <string name="powered_by">carnero</string>
+ <string name="author">Autor: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Soporte: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Web: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="nutshellmanual">Manual: <a href="http://itw.bidix.info/cgeo/">c:geo en breve</a></string>
+ <string name="about_go4cache">Servicio <b>Go 4 Cache</b> muestra a otros buscadores en el mapa (en <b>c:geo</b> o en el navegador) en tiempo real. Puede mostrar, por ejemplo, qué escondite estan buscando. Al conectarte a <b>Go 4 Cache</b> <b>c:geo</b> está autorizado a publicar tu ubicación (sólo cuando <b>c:geo</b> está activo).</string>
+ <string name="about_twitter">¿Debe <b>c:geo</b> publicar el nuevo estado en Twitter cuando registras un escondite?</string>
+ <string name="about_auth_1">El siguiente proceso permite a <b>c:geo</b> acceder a Twitter - si estás de acuerdo.</string>
+ <string name="about_auth_2">Hacer clic en el botón \"autorizar c:geo\" iniciará el proceso. Este proceso abrirá un navegador con la web de Twitter. Identifícate y permite a <b>c:geo</b> acceder a tu cuenta. Si aceptas Twitter te mostrará un código PIN. Este PIN debe ser pegado en <b>c:geo</b> y ser confirmado. Eso es todo.</string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
new file mode 100644
index 0000000..f2140c7
--- /dev/null
+++ b/res/values-fr/strings.xml
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo compass</string>
+
+ <!-- basics -->
+ <string name="cache">cache</string>
+ <string name="detail">détails</string>
+ <string name="search">rechercher</string>
+ <string name="settings">paramètres</string>
+ <string name="about">à propos de c:geo</string>
+
+ <!-- caches -->
+ <string name="all">toutes</string>
+ <string name="traditional">traditionnelles</string>
+ <string name="multi">multiples</string>
+ <string name="mystery">inconnues</string>
+ <string name="letterbox">boites-à-lettres hybrides</string>
+ <string name="event">évènements</string>
+ <string name="mega">méga-évènements</string>
+ <string name="earth">earthcache</string>
+ <string name="cito">cache in trash out</string>
+ <string name="webcam">webcams</string>
+ <string name="virtual">virtuelles</string>
+ <string name="wherigo">wherigo</string>
+ <string name="lostfound">perdues &amp; trouvées</string>
+ <string name="ape">project ape cache</string>
+ <string name="gchq">groundspeak hq</string>
+ <string name="gps">gps cache exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">étape finale</string>
+ <string name="wp_stage">étape</string>
+ <string name="wp_puzzle">énigme</string>
+ <string name="wp_pkg">parking</string>
+ <string name="wp_trailhead">départ du sentier</string>
+ <string name="wp_waypoint">point de repère</string>
+
+ <!-- logs -->
+ <string name="log_found">trouvée</string>
+ <string name="log_dnf">pas trouvée</string>
+ <string name="log_note">note</string>
+ <string name="log_published">publiée</string>
+ <string name="log_enabled">activée</string>
+ <string name="log_disabled">désactivée</string>
+ <string name="log_attend">will attend</string>
+ <string name="log_attended">attended</string>
+ <string name="log_retrieved">retrouvé</string>
+ <string name="log_grabbed">pris ailleurs</string>
+ <string name="log_maintained">maintenu</string>
+ <string name="log_maintenance_needed">nécessite une maintenance</string>
+ <string name="log_maintenance_owner">maitenance</string>
+ <string name="log_update">coordonnées mise-à-jours</string>
+ <string name="log_archived">archivée</string>
+ <string name="log_needs_archived">nécessite d\'être archivée</string>
+ <string name="log_discovered">retrouvée</string>
+ <string name="log_reviewed">note du relecteur</string>
+ <string name="log_tb_nothing">ne fait rien</string>
+ <string name="log_tb_visit">visité</string>
+ <string name="log_tb_drop">déposé ici</string>
+ <string name="log_webcam">webcam photo taken</string>
+
+ <!-- errors -->
+ <string name="err_none">ok</string>
+ <string name="err_start">communication not started</string>
+ <string name="err_parse">failed login page parsing</string>
+ <string name="err_server">failed connection to geocaching.com (server or connection down?)</string>
+ <string name="err_login">no login information stored</string>
+ <string name="err_unknown">unknown error</string>
+ <string name="err_comm">unknown communication error</string>
+ <string name="err_wrong">wrong login informations</string>
+ <string name="err_license">user has not agreed to Geocaching.com license agreement</string>
+ <string name="err_store">Sorry, c:geo can\'t store cache.</string>
+ <string name="err_drop">Sorry, c:geo can\'t drop cache.</string>
+ <string name="err_title_problem">problem</string>
+ <string name="err_detail_open">Sorry, c:geo can\'t open geocache details.</string>
+ <string name="err_detail_cache">Sorry, c:geo can\'t display geocache you want. Is it really geocache?</string>
+ <string name="err_detail_cache_find">Sorry, c:geo can\'t find geocache</string>
+ <string name="err_detail_cache_find_some">Sorry, c:geo can\'t find that geocache.</string>
+ <string name="err_detail_cache_forgot">Sorry, c:geo forgot which geocache you want.</string>
+ <string name="err_detail_cache_language">c:geo can\'t read some cache details. Please check if you have geocaching.com website set to English. Unfortunately, c:geo doesn\'t understand other localizations.</string>
+ <string name="err_detail_no_spoiler">c:geo found no spoiler images for this cache.</string>
+ <string name="err_detail_no_map_static">c:geo found no static maps for this cache.</string>
+ <string name="err_detail_still_removing">Still removing this cache.</string>
+ <string name="err_detail_still_saving">Still saving this cache.</string>
+ <string name="err_detail_still_refreshing">Still reloading this cache.</string>
+ <string name="err_radar_title">Radar isn\'t installed.</string>
+ <string name="err_radar_message">This function requires Radar application. Would you install it?</string>
+ <string name="err_radar_market">c:geo can\'t start Android Market to search for Radar application.</string>
+ <string name="err_radar_generic">Sorry, c:geo can\'t start Radar application. Is installed?</string>
+ <string name="err_navigation_no">c:geo can\'t find any supported navigation.</string>
+ <string name="err_application_no">c:geo can\'t find any suitable application.</string>
+ <string name="err_auth_initialize">Sorry, c:geo failed to initialize authorization process.</string>
+ <string name="err_auth_process">Authorization process failed.</string>
+ <string name="err_cannot_log_visit">c:geo has not enough information to log visit. Please, do it from full cache details.</string>
+ <string name="err_init_cleared">Sorry, c:geo can\'t clear your login.</string>
+
+ <!-- location service -->
+ <string name="loc_last">dernière pos. connue</string>
+ <string name="loc_net">réseau</string>
+ <string name="loc_gps">gps</string>
+ <string name="loc_sat">satellites</string>
+ <string name="loc_trying">localisation en cours…</string>
+ <string name="loc_no_addr">adresse inconnue</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">à propos de c:geo</string>
+ <string name="menu_settings">paramètres</string>
+ <string name="menu_filter">filtre</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">carte active</string>
+ <string name="caches_nearby_button">proches</string>
+ <string name="advanced_search_button">recherche</string>
+ <string name="stored_caches_button">enregistrées</string>
+ <string name="any_button">n\'importe où</string>
+ <string name="about_button">à propos</string>
+ <string name="settings_button">paramètres</string>
+ <string name="type">type</string>
+ <string name="now_searching">recherche en cours…</string>
+
+ <!-- caches -->
+ <string name="caches_no_cache">aucune cache</string>
+ <string name="caches_more_caches">plus de caches</string>
+ <string name="caches_more_caches_no">plus de caches</string>
+
+ <!-- about -->
+ <string name="about_changelog">versions</string>
+ <string name="about_donate">dons</string>
+ <string name="about_detail">détails</string>
+ <string name="about_donation_less">don\nmini</string>
+ <string name="about_donation_more">don\ndéveloppement</string>
+
+ <!-- init -->
+ <string name="init_geocaching">geocaching.com</string>
+ <string name="init_gcvote">gcvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">twitter</string>
+ <string name="init_username">identifiant</string>
+ <string name="init_password">mot de passe</string>
+ <string name="init_passvote">mot de passe</string>
+ <string name="init_login">vérification de l\'identifiant</string>
+ <string name="init_legal">note légale</string>
+ <string name="init_go4cache_connect">connection à Go 4 Cache</string>
+ <string name="init_twitter_authorize">autorisation de c:geo</string>
+ <string name="init_twitter_publish">publication d\'une cache trouvée</string>
+ <string name="init_signature">signature</string>
+ <string name="init_other">autres options</string>
+ <string name="init_skin">aspect sobre (nécessite le redémarrage de c:geo)</string>
+ <string name="init_transparent">accueil de c:geo transparent</string>
+ <string name="init_address">afficher l\'adresse sur l\'accueil</string>
+ <string name="init_exclude">exclure les caches trouvée et les miennes</string>
+ <string name="init_disabled">exclure les caches sdésactivées</string>
+ <string name="init_offline">enregistrer les cartes pour utilisation hors ligne</string>
+ <string name="init_units">utiliser des unités de distance impériales</string>
+ <string name="init_nav">utiliser Google Navigation</string>
+ <string name="init_autoload">chargement auto des descriptions longues</string>
+ <string name="init_livelist">afficher la direction des caches dans les listes</string>
+ <string name="init_browser">identifier c:geo comme navigateur standard</string>
+ <string name="init_cleared">c:geo à effacé votre identifiant.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">twitter</string>
+ <string name="auth_authorize">autorisation de c:geo</string>
+ <string name="auth_start">start authorization</string>
+ <string name="auth_again">start again</string>
+ <string name="auth_pin_hint">pin assigned by twitter</string>
+ <string name="auth_finish">finish</string>
+ <string name="auth_dialog_wait">Waiting for Twitter...</string>
+ <string name="auth_dialog_pin_title">pin code</string>
+ <string name="auth_dialog_pin_message">Please write PIN code provided by Twitter website. It\'s mandatory to complete authorization.</string>
+ <string name="auth_dialog_completed">c:geo is now authorized to post on your Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">aucune cache</string>
+ <string name="cache_count_one">une cache</string>
+ <string name="cache_count_more">caches</string>
+ <string name="cache_offline">hors ligne</string>
+ <string name="cache_offline_refresh">recharger</string>
+ <string name="cache_offline_drop">effacer</string>
+ <string name="cache_offline_store">enregistrer</string>
+ <string name="cache_offline_stored">enregistrée</string>
+ <string name="cache_offline_not_ready">hors ligne indisponible</string>
+ <string name="cache_offline_time_about">il y a environ</string>
+ <string name="cache_offline_time_mins">quelques minutes</string>
+ <string name="cache_offline_time_mins_few">moins d\'une heure</string>
+ <string name="cache_offline_time_hour">une heure</string>
+ <string name="cache_offline_time_hours">heures</string>
+ <string name="cache_offline_time_days">jours</string>
+ <string name="cache_attributes">attributs</string>
+ <string name="cache_inventory">inventaire</string>
+ <string name="cache_log_offline">enregistrement hors ligne</string>
+ <string name="cache_description">description</string>
+ <string name="cache_description_long">description longue</string>
+ <string name="cache_waypoints">étapes</string>
+ <string name="cache_waypoints_add">ajouter une étape</string>
+ <string name="cache_hint">indice</string>
+ <string name="cache_logs">carnet de bord</string>
+ <string name="cache_dialog_loading_details">chargement des détails...</string>
+ <string name="cache_dialog_loading_description">Chargement de la description...</string>
+ <string name="cache_dialog_offline_save_title">hors ligne</string>
+ <string name="cache_dialog_offline_save_message">Enregistrement pour une utilisation hors ligne...</string>
+ <string name="cache_dialog_offline_drop_title">hors ligne</string>
+ <string name="cache_dialog_offline_drop_message">Suppression des caches de la mémoire...</string>
+ <string name="cache_dialog_refresh_title">Recharger</string>
+ <string name="cache_dialog_refresh_message">Rechargement des détails...</string>
+ <string name="cache_menu_navigate">navigation</string>
+ <string name="cache_menu_compass">boussole</string>
+ <string name="cache_menu_tbt">itinéraire</string>
+ <string name="cache_menu_radar">radar</string>
+ <string name="cache_menu_map">carte</string>
+ <string name="cache_menu_map_ext">carte externe</string>
+ <string name="cache_menu_map_static">carte statique</string>
+ <string name="cache_menu_browser">navigateur</string>
+ <string name="cache_menu_visit">carnet</string>
+ <string name="cache_menu_spoilers">photos solutions</string>
+ <string name="cache_menu_around">alentours</string>
+ <string name="cache_menu_event">ajouter à l\'agenda</string>
+ <string name="cache_menu_details">détails</string>
+ <string name="cache_status">statut</string>
+ <string name="cache_status_offline_log">saved log</string>
+ <string name="cache_status_found">trouvée</string>
+ <string name="cache_status_archived">archivée</string>
+ <string name="cache_status_disabled">désactivée</string>
+ <string name="cache_status_premium">membres privilégiés seulement</string>
+ <string name="cache_geocode">code gc</string>
+ <string name="cache_type">type</string>
+ <string name="cache_distance">distance</string>
+ <string name="cache_difficulty">difficultée</string>
+ <string name="cache_terrain">terrain</string>
+ <string name="cache_rating">note</string>
+ <string name="cache_owner">propriétaire</string>
+ <string name="cache_hidden">cachée</string>
+ <string name="cache_event">date</string>
+ <string name="cache_location">localisation</string>
+ <string name="cache_coordinates">coordonnées</string>
+ <string name="cache_calendars">choisir un agenda</string>
+
+ <!-- event -->
+ <string name="event_success">Cache évènement ajoutée à l\'agenda</string>
+ <string name="event_fail">Echec d\'ajout de la cache évènement à l\'agenda</string>
+
+ <!-- popup -->
+ <string name="popup_more">plus de détails</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_custom">personnalisé</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">publier votre découverte sur twitter</string>
+
+ <!-- navigation -->
+ <string name="navigation">navigation</string>
+
+ <!-- next things -->
+ <string name="legal_note">Pour utiliser les services de geocaching.com, vous devez accepter les termes et conditions de la <a href="http://www.geocaching.com/about/termsofuse.aspx">mise en garde de Groundspeak</a>.</string>
+ <string name="author">auteur: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">site: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</a></string>
+ <string name="facebook">facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">page c:geo</a></string>
+ <string name="twitter">twitter: <a href="http://twitter.com/android_gc">@android_GC</a></string>
+ <string name="about_go4cache">Le service <b>Go 4 cache</b> vous permet de voir en temps réel d\'autres géocacheurs sur une carte (dans <b>c:geo</b> ou dans le navigateur). Il peut afficher quelles caches ils recherchent. En vous connectant sur <b>Go 4 cache</b> vous permettez à <b>c:geo</b> de publier votre publication pendant (seulement si <b>c:geo</b> fonctionne).</string>
+ <string name="about_twitter">Do you want to publish new status on Twitter everytimes you log find through <b>c:geo</b>?</string>
+ <string name="about_auth_1">The following proccess allows <b>c:geo</b> to access your Twitter account - if you agree.</string>
+ <string name="about_auth_2">Click on \"authorize c:geo\" button will start process. This process will open web browser with Twitter page where you have to login and Accept <b>c:geo</b> to access your account. When you Accept, Twitter will show you numeric PIN code. Please copy this code, paste into <b>c:geo</b> and confirm. That\'s all.</string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
new file mode 100644
index 0000000..bec5311
--- /dev/null
+++ b/res/values-hu/strings.xml
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo iránytű</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Részletek</string>
+ <string name="search">Keresés</string>
+ <string name="settings">Beállítások</string>
+ <string name="about">c:geo-ról</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">A cache linkjének megosztása</string>
+
+ <!-- caches -->
+ <string name="all">Minden caches</string>
+ <string name="traditional">Hagyományos cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Ismeretlen cache</string>
+ <string name="letterbox">Postaláda hybrid</string>
+ <string name="event">Esemény cache</string>
+ <string name="mega">Mega-esemény cache</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">CITO esemény</string>
+ <string name="webcam">Webcam cache</string>
+ <string name="virtual">Virtuális cache</string>
+ <string name="wherigo">Wherigo cache</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Project ape cache</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">GPS cache kiállítás</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Célpont</string>
+ <string name="wp_stage">Multi-cache állomása</string>
+ <string name="wp_puzzle">Kérdésre választ</string>
+ <string name="wp_pkg">Parkoló</string>
+ <string name="wp_trailhead">Ösvény</string>
+ <string name="wp_waypoint">Referencia pont</string>
+
+ <!-- logs -->
+ <string name="log_found">Megtalálva</string>
+ <string name="log_dnf">Nincs megtalálva</string>
+ <string name="log_note">Feljegyzés</string>
+ <string name="log_published">Publikálva</string>
+ <string name="log_enabled">Bekapcsolva</string>
+ <string name="log_disabled">Letiltva</string>
+ <string name="log_attend">Részt vennék</string>
+ <string name="log_attended">Résztvevő</string>
+ <string name="log_retrieved">Fogadva</string>
+ <string name="log_grabbed">Máshonnan megszerezve</string>
+ <string name="log_maintained">Karbantartás</string>
+ <string name="log_maintenance_needed">Karbantartást igényel</string>
+ <string name="log_maintenance_owner">Karbantartás</string>
+ <string name="log_update">Megváltozott koordináták</string>
+ <string name="log_archived">Archiválva</string>
+ <string name="log_needs_archived">Archiválása szükséges</string>
+ <string name="log_discovered">Felfedezve</string>
+ <string name="log_reviewed">Véleményező megjegyzés</string>
+ <string name="log_tb_nothing">Ne csinálj semmit</string>
+ <string name="log_tb_visit">Látogasd meg</string>
+ <string name="log_tb_drop">Rakd ide</string>
+ <string name="log_save">Mentés</string>
+ <string name="log_clear">Törlés</string>
+ <string name="log_webcam">Webkamera fotó rögzítve</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">A kommunikáció nem indult el</string>
+ <string name="err_parse">Belépő oldal értelmezési hiba</string>
+ <string name="err_server">geocaching.com csatlakozási hiba (a szerver vagy a kapcsolat leállt?)</string>
+ <string name="err_login">Nincs bejelentkezési adat tárolva</string>
+ <string name="err_unknown">Ismeretlen hiba</string>
+ <string name="err_comm">Ismeretlen kommunikációs hiba</string>
+ <string name="err_wrong">Hibás bejelentkezési adatok</string>
+ <string name="err_license">A felhasználó nem foggadta el a Geocaching.com licensz szerződését</string>
+ <string name="err_store">Bocs, a c:geo Nem tudja tárolni a cache-t.</string>
+ <string name="err_drop">Bocs, a c:geo nem tudja eldobni a cache-t.</string>
+ <string name="err_title_problem">Probléma</string>
+ <string name="err_detail_open">Bocs, a c:geo nem tudja megnyitni a cache részleteit.</string>
+ <string name="err_detail_cache">Bocs, a c:geo Nem tudja megmutatni a kívánt cache-t. Ez biztosan geocache?</string>
+ <string name="err_detail_cache_find">Bocs, a c:geo nem talált cache-t</string>
+ <string name="err_detail_cache_find_some">Bocs, a c:geo nem találja a cache-t.</string>
+ <string name="err_detail_cache_forgot">Bocs, a c:geo elfelejtette, melyik cache-t szeretnéd.</string>
+ <string name="err_detail_cache_language">A c:geo nem tudja olvasni a cache bizonyos részeit. Ellenőrizd, hogy a geocaching.com oldal angolra van állítva. Sajnos a c:geo nem támogat egyéb nyelvi változatokat.</string>
+ <string name="err_detail_no_spoiler">A c:geo nem talált spoiler képet a cache-hez.</string>
+ <string name="err_detail_no_map_static">A c:geo nem talált statikus térképet a cache-hez.</string>
+ <string name="err_detail_still_removing">Cache eltávolítása.</string>
+ <string name="err_detail_still_saving">Cache mentése.</string>
+ <string name="err_detail_still_refreshing">Cache újratöltése.</string>
+ <string name="err_radar_title">Radar nincs telepítve.</string>
+ <string name="err_radar_message">A funkció Radar alkalmazást igényel. Telepítetted?</string>
+ <string name="err_radar_market">A c:geo can\'t nem tudja elindítani az Android Marketet a Radar alkalmazás kereséséhez.</string>
+ <string name="err_radar_generic">Bocs, a c:geo nem tudja elindítani a Radar alkalmazást. Telepítve van?</string>
+ <string name="err_navigation_no">A c:geo nem talál támogatott navigációt.</string>
+ <string name="err_application_no">A c:geo nem talál megfelelő alkalmazást.</string>
+ <string name="err_auth_initialize">Bocs, a c:geo nem tudja előkészíteni az azonosítási folyamatot.</string>
+ <string name="err_auth_process">Azonosítási folyamat sikertelen.</string>
+ <string name="err_cannot_log_visit">A c:geo nem rendelkezdik elég információval a logoláshoz. A cache részletektől hajtsd végre!</string>
+ <string name="err_init_cleared">Bocs, a c:geo nem tudja törölni a bejelentkezési információkat.</string>
+ <string name="err_no_chaches">Bocs, a c:geo nem tudja betölteni a cache-t vagy cache-eket.</string>
+ <string name="err_download_fail">Bocs, a c:geo nem tudja letölteni a cacheket, mivel </string>
+ <string name="err_update_fail">Hiba a megtett távolság frissítésénél.</string>
+
+ <string name="warn_save_nothing">Nincs semmi elmenthető.</string>
+ <string name="warn_no_cache_coord">Nincs cache a koordinátákkal.</string>
+
+ <string name="info_altitude">Jelenlegi magasság</string>
+ <string name="info_distance">Megtett távolság</string>
+ <string name="info_distance_cleared">Megtett távolság törölve.</string>
+ <string name="info_since">\n(óta </string>
+
+ <!-- location service -->
+ <string name="loc_last">Utolsó ismert</string>
+ <string name="loc_net">Hálózat</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Pozíció keresése</string>
+ <string name="loc_no_addr">Ismeretlen cím</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">c:geo-ról</string>
+ <string name="menu_settings">Beállítások</string>
+ <string name="menu_filter">Szűrő</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Éő térkép</string>
+ <string name="caches_nearby_button">Közeli</string>
+ <string name="advanced_search_button">Keresés</string>
+ <string name="stored_caches_button">Tárolt</string>
+ <string name="any_button">Bárhol</string>
+ <string name="about_button">Rólunk</string>
+ <string name="settings_button">Beállítások</string>
+ <string name="type">Típus</string>
+ <string name="now_searching">Keresés folyamatban</string>
+
+ <!-- caches -->
+ <string name="caches_no_cache">Nincs cache</string>
+ <string name="caches_more_caches">Több cache</string>
+ <string name="caches_more_caches_no">Nincs több cache</string>
+ <string name="caches_downloading">Cache letöltés...\nHátralévő idő: </string>
+ <string name="caches_eta_ltm">Kevesebb, mint egy perc</string>
+ <string name="caches_eta_mins"> perc</string>
+ <string name="caches_no_caches"> (nincs cache)</string>
+ <string name="caches_store_offline">Tárolás</string>
+ <string name="caches_on_map">Megjelenítés térképen</string>
+ <string name="caches_select">Válassz a listából</string>
+
+ <!-- about -->
+ <string name="about_changelog">Változások</string>
+ <string name="about_donate">Támogatás</string>
+ <string name="about_detail">Részletek</string>
+ <string name="about_donation_less">Kisebb\ntámogatás</string>
+ <string name="about_donation_more">Fejlesztői\ntámogatás</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Felhasználónév</string>
+ <string name="init_password">Jelszó</string>
+ <string name="init_passvote">Jelszó</string>
+ <string name="init_login">Bejelentkezés ellenőrzése</string>
+ <string name="init_legal">Jogi megjegyzés</string>
+ <string name="init_go4cache_connect">Go 4 Cache csatlakozás</string>
+ <string name="init_twitter_authorize">c:geo engedélyezés</string>
+ <string name="init_twitter_publish">Állapot közzététel, ha megtalálsz egy cache-t</string>
+ <string name="init_signature">Aláírás</string>
+ <string name="init_other">További beállítások</string>
+ <string name="init_skin">Világos skin (c:geo újraindítás szükséges)</string>
+ <string name="init_transparent">Átlátszó c:geo főképernyő</string>
+ <string name="init_address">Mutasd a címet a főképernyőn</string>
+ <string name="init_exclude">Saját és megtalált cache-k elrejtése</string>
+ <string name="init_disabled">Letiltott cache-k elrejtése</string>
+ <string name="init_offline">Térkép tárolása offline használathoz</string>
+ <string name="init_units">Angolszász mértékegységek használata</string>
+ <string name="init_nav">Google Navigáció használata</string>
+ <string name="init_autoload">Hosszú leírás automatikus betöltése</string>
+ <string name="init_livelist">Cache irányának megjelenítése a listában</string>
+ <string name="init_browser">A c:geo alapértelmezett böngészőként való beállítása</string>
+ <string name="init_cleared">A c:geo törölte a bejelentkezési információkat.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">c:geo engedélyezése</string>
+ <string name="auth_start">Engedélyezés indítása</string>
+ <string name="auth_again">Újrakezdés</string>
+ <string name="auth_pin_hint">Twitter PIN kódja</string>
+ <string name="auth_finish">Kész</string>
+ <string name="auth_dialog_wait">Várakozás a Twitter-re...</string>
+ <string name="auth_dialog_pin_title">PIN kód</string>
+ <string name="auth_dialog_pin_message">Add meg a Twitter oldalán kapott PIN kódot. Ez kötelező az engedélyezés befejezéséhez.</string>
+ <string name="auth_dialog_completed">A c:geo engedélyt kapott Twitter üzenetek létrehozásához.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Nincs cache</string>
+ <string name="cache_count_one">Egy cache</string>
+ <string name="cache_count_more">Cache-ek</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Frissítés</string>
+ <string name="cache_offline_drop">Eldobás</string>
+ <string name="cache_offline_store">Tárolás</string>
+ <string name="cache_offline_stored">Készléken tárolva</string>
+ <string name="cache_offline_not_ready">Nincs beállítva\nofflienh használatra</string>
+ <string name="cache_offline_time_about">Rólunk</string>
+ <string name="cache_offline_time_mins">perce</string>
+ <string name="cache_offline_time_mins_few">néhány perce</string>
+ <string name="cache_offline_time_hour">egy órája</string>
+ <string name="cache_offline_time_hours">órája</string>
+ <string name="cache_offline_time_days">napja</string>
+ <string name="cache_attributes">Jellemzők</string>
+ <string name="cache_inventory">Leltár</string>
+ <string name="cache_log_offline">Offline log</string>
+ <string name="cache_description">Leírás</string>
+ <string name="cache_description_long">Hosszú leírás</string>
+ <string name="cache_waypoints">Útpontok</string>
+ <string name="cache_waypoints_add">Útpont hozzáadása</string>
+ <string name="cache_hint">Segítség</string>
+ <string name="cache_logs">Logbook</string>
+ <string name="cache_dialog_loading_details">Cache részletek betöltése...</string>
+ <string name="cache_dialog_loading_description">Cache leírás betöltése...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Cache mentése offline használathoz...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Cache eltávolítása a memóriából...</string>
+ <string name="cache_dialog_refresh_title">Frissítés</string>
+ <string name="cache_dialog_refresh_message">Cache részleteinek frissítése...</string>
+ <string name="cache_menu_navigate">Navigáció</string>
+ <string name="cache_menu_compass">Iránytű</string>
+ <string name="cache_menu_tbt">Utakon</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Mutasd a térképen</string>
+ <string name="cache_menu_map_ext">Mutasd külső térképen</string>
+ <string name="cache_menu_map_static">Statikus térképek</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_spoilers">Spoiler képek</string>
+ <string name="cache_menu_around">Cache-k a krnyéken</string>
+ <string name="cache_menu_event">Add a naptárhoz</string>
+ <string name="cache_menu_details">Részletek</string>
+ <string name="cache_status">Állapot</string>
+ <string name="cache_status_offline_log">Tárolt log</string>
+ <string name="cache_status_found">Megtalálva</string>
+ <string name="cache_status_archived">Archiválva</string>
+ <string name="cache_status_disabled">Letiltva</string>
+ <string name="cache_status_premium">Csak premium tagoknak</string>
+ <string name="cache_geocode">GC-kód</string>
+ <string name="cache_type">Típus</string>
+ <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">Értékelés</string>
+ <string name="cache_owner">Tulajdonos</string>
+ <string name="cache_hidden">Rejtve</string>
+ <string name="cache_event">Dátum</string>
+ <string name="cache_location">Hely</string>
+ <string name="cache_coordinates">Koordináták</string>
+ <string name="cache_calendars">Naptár kiválasztása</string>
+
+ <!-- event -->
+ <string name="event_success">Esemény cache rögzítve a naptárban</string>
+ <string name="event_fail">Esemény cache naptár-rögzítési hiba</string>
+
+ <!-- popup -->
+ <string name="popup_more">További részletek</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_custom">Egyedi</string>
+ <string name="waypoint_my_coordinates">Saját koordináták</string>
+ <string name="waypoint_bearing">Bearing</string>
+ <string name="waypoint_distance">Távolság</string>
+ <string name="waypoint_name">Név</string>
+ <string name="waypoint_edit">Módosít</string>
+ <string name="waypoint_delete">Töröl</string>
+ <string name="waypoint_edit_title">Útpont módosítás</string>
+ <string name="waypoint_add_title">Útpont hozzáadás</string>
+ <string name="waypoint_note">Jegyzet</string>
+ <string name="waypoint_save">Mentés</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Találat megjelenítése Twitteren</string>
+
+ <!-- map -->
+ <string name="map_map">Térkép</string>
+ <string name="map_live">Élő térkép</string>
+ <string name="map_view_satellite">Műhold nézet</string>
+ <string name="map_view_map">Térkép nézet</string>
+ <string name="map_trail_show">Nyomvonal mutatása</string>
+ <string name="map_trail_hide">Nyomvonal elrejtése</string>
+ <string name="map_live_enable">Élő bekapcsolás</string>
+ <string name="map_live_disable">Élő kikapcsoltás</string>
+
+ <!-- search -->
+ <string name="search_coordinates">Koordináták</string>
+ <string name="search_coordinates_button">Keresés koordinátákkal</string>
+ <string name="search_address">Cím</string>
+ <string name="search_address_button">Keresés cím alapján</string>
+ <string name="search_gc">Geocode</string>
+ <string name="search_gc_button">Keresés geocode alapján</string>
+ <string name="search_kw">Kulcsszavak</string>
+ <string name="search_kw_prefill">Kulcsszó</string>
+ <string name="search_kw_button">Keresés kulcsszó alapján</string>
+ <string name="search_fbu">Felhasználói megtalálás</string>
+ <string name="search_fbu_prefill">Felhasználónév</string>
+ <string name="search_fbu_button">Keresés felhasználónév lapján</string>
+ <string name="search_hbu">Felhasználói rejtés</string>
+ <string name="search_hbu_prefill">Rejtő</string>
+ <string name="search_hbu_button">Keresés rejtő neve alapján</string>
+ <string name="search_tb">TB</string>
+ <string name="search_tb_hint">TB azonosítás</string>
+ <string name="search_tb_button">Keresés TB alapján</string>
+ <string name="search_destination">Cél</string>
+ <string name="search_direction_rel">Ettől a pozíciótól</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigáció</string>
+
+ <!-- next things -->
+ <string name="legal_note">A geocaching.com szolgáltatásainak használatához, a <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeak disclaimer</a> feltételeinek elfogadása szükséges.</string>
+ <string name="author">Szerző: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Támogatás: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Weboldal: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="about_go4cache">A <b>Go 4 Cache</b> más geocacherek valós idejű pozícióját mutatja (<b>c:geo</b>-ban vagy böngészőben). Például megtekinthető, hogy mely rejtést keresik éppen. A <b>Go 4 Cache</b> csatlokzással a <b>c:geo</b> publikája az aktuális pozíciódat játék közben (csak ha fut a <b>c:geo</b>).</string>
+ <string name="about_twitter">Publikája a <b>c:geo</b> Twitter üzenetként a megtalálásaidat?</string>
+ <string name="about_auth_1">A következő folyamattal a <b>c:geo</b> hozzáfér a Twitter fiókodhoz - ha elfogadod.</string>
+ <string name="about_auth_2">Kattints a \"c:geo engedélyezés\" gombra a folyamat indításához. Ekkor megnyílik egy böngészőablak a Twitter oldalával. jelentkezz be és engedélyezd a <b>c:geo</b> számára a hozzáférést. Ha sikeres, a Twitter egy PIN kódot generál neked. Ezt a kódot kell a <b>c:geo</b>-ban megadni. Ennyi az egész.</string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
new file mode 100644
index 0000000..7385691
--- /dev/null
+++ b/res/values-ja/strings.xml
@@ -0,0 +1,742 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo compass</string>
+
+ <!-- basics -->
+ <string name="cache">キャッシュ</string>
+ <string name="detail">詳細</string>
+ <string name="search">検索</string>
+ <string name="settings">設定</string>
+ <string name="helpers">役に立つアプリ</string>
+ <string name="about">c:geoについて</string>
+ <string name="helper"><b>c:geo</b>についてもっと知りたい?\nマニュアル(英語)を読んでね。</string>
+ <string name="database_error_title">データベースエラー</string>
+ <string name="database_error_message">データベースに接続することができませんでした。\n少し後でc:geoを再起動してみてください。もしこのメッセージが何度も表示されるならアンドロイド端末の設定/アプリケーション/アプリケーションの管理/c:geo に進み、「キャッシュを消去」ボタンを押してください。または、c:geoのアンインストールと再インストールをしてください。面倒かけてごめんなさい。</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">キャッシュのリンクを共有</string>
+
+ <!-- caches -->
+ <string name="all">">全てのキャッシュ</string>
+ <string name="all_types">全てのタイプのキャッシュ</string>
+ <string name="traditional">トラディショナルキャッシュ</string>
+ <string name="multi">マルチキャッシュ</string>
+ <string name="mystery">ミステリーキャッシュ</string>
+ <string name="letterbox">レターボックスハイブリッド</string>
+ <string name="event">イベントキャッシュ</string>
+ <string name="mega">メガイベントキャシュ</string>
+ <string name="earth">アースキャッシュ</string>
+ <string name="cito">CITOイベント</string>
+ <string name="webcam">ウェブカムキャッシュ</string>
+ <string name="virtual">バーチャルキャッシュ</string>
+ <string name="wherigo">Wherigoキャッシュ</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Project A.P.E.キャッシュ</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">展覧会キャッシュ</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">最終座標</string>
+ <string name="wp_stage">マルチキャッシュのステージ</string>
+ <string name="wp_puzzle">質問に対する答え</string>
+ <string name="wp_pkg">駐車場</string>
+ <string name="wp_trailhead">出発地点</string>
+ <string name="wp_waypoint">参照地点</string>
+
+ <!-- logs -->
+ <string name="log_found">見つかった</string>
+ <string name="log_dnf">見つからなかった</string>
+ <string name="log_note">メモ</string>
+ <string name="log_published">公開</string>
+ <string name="log_enabled">有効化</string>
+ <string name="log_disabled">無効化</string>
+ <string name="log_attend">参加します</string>
+ <string name="log_attended">参加しました</string>
+ <string name="log_retrieved">回収した</string>
+ <string name="log_placed">Placed</string>
+ <string name="log_grabbed">捕まえた</string>
+ <string name="log_maintained">メンテナンスした</string>
+ <string name="log_maintenance_needed">メンテナンスが必要</string>
+ <string name="log_maintenance_owner">メンテナンス</string>
+ <string name="log_update">座標を更新</string>
+ <string name="log_archived">アーカイブされた</string>
+ <string name="log_needs_archived">アーカイブされるべき</string>
+ <string name="log_discovered">発見した</string>
+ <string name="log_reviewed">レビューノート</string>
+ <string name="log_taken">Visit</string>
+ <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_saving">ログを保存中...</string>
+ <string name="log_clear">消去</string>
+ <string name="log_post">ログを投稿</string>
+ <string name="log_post_rate">ログを投稿し、評価も行う</string>
+ <string name="log_post_no_rate">ログを投稿するが、評価はしない</string>
+ <string name="log_add">挿入</string>
+ <string name="log_date">日付</string>
+ <string name="log_time">時間</string>
+ <string name="log_date_time">日付と時間</string>
+ <string name="log_rating">評価</string>
+ <string name="log_no_rating">評価がまだない</string>
+ <string name="log_stars_1">1つ星</string>
+ <string name="log_stars_2">2つ星</string>
+ <string name="log_stars_3">3つ星</string>
+ <string name="log_stars_4">4つ星</string>
+ <string name="log_stars_5">5つ星</string>
+ <string name="log_webcam">ウェブカムの写真を撮影</string>
+ <string name="log_new_log">ログ</string>
+ <string name="log_new_log_text">ログ本文</string>
+ <string name="log_announcement">アナウンス</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">通信を始めることができませんでした</string>
+ <string name="err_parse">ログインページの解析に失敗しました</string>
+ <string name="err_server">Geocaching.comに接続できません(サーバーまたはネット接続がダウンしてる?)</string>
+ <string name="err_login">ログイン情報が保存されていません</string>
+ <string name="err_login_failed">ログインできません。</string>
+ <string name="err_unknown">未知のエラー</string>
+ <string name="err_comm">未知の通信エラー</string>
+ <string name="err_missing_auth">ユーザ名またはパスワードが入力されていません。</string>
+ <string name="err_wrong">ログイン情報が間違っています</string>
+ <string name="err_license">Geocaching.comのライセンス契約に同意しなかったのでキャッシュの座標を見ることはできません。</string>
+ <string name="err_store">キャッシュ情報を保存することができません。</string>
+ <string name="err_drop">キャッシュ情報を破棄することができません。</string>
+ <string name="err_title_problem">問題</string>
+ <string name="err_detail_open">キャッシュの詳細を開くことができません。</string>
+ <string name="err_detail_cache">キャッシュ情報を表示することができません。これは本当にジオキャッシュですか?</string>
+ <string name="err_detail_cache_find">キャッシュ情報が見つかりません。</string>
+ <string name="err_detail_cache_find_some">キャッシュ情報が見つかりません。</string>
+ <string name="err_detail_cache_find_any">キャッシュ情報が一つも見つかりません。</string>
+ <string name="err_detail_cache_find_next">次のキャッシュ情報が見つかりません。</string>
+ <string name="err_detail_cache_forgot">Sorry, c:geo forgot which geocache you want.</string>
+ <string name="err_detail_cache_forgot_visit">Sorry, c:geo forgot which cache you visited.</string>
+ <string name="err_detail_cache_language">キャッシュの詳細の一部を読み込むことができません。 geocaching.comの言語設定が英語になっていることを確認してください。残念ながらc:geoは他の言語設定には対応しておりません。</string>
+ <string name="err_detail_no_spoiler">このキャッシュのスポイラー画像を見つけることができませんでした。</string>
+ <string name="err_detail_no_map_static">このキャッシュのオフライン地図を見つけることができませんでした。</string>
+ <string name="err_detail_not_load_map_static">オフライン地図のロードに失敗しました。</string>
+ <string name="err_detail_still_removing">このキャッシュはまだ削除中です。</string>
+ <string name="err_detail_still_saving">このキャッシュはまだ保存中です。</string>
+ <string name="err_detail_still_refreshing">このキャッシュはまだ更新中です。</string>
+ <string name="err_radar_title">レーダーがインストールされていません。</string>
+ <string name="err_radar_message">この機能にはレーダーアプリが必要です。インストールしますか?</string>
+ <string name="err_radar_market">レーダーアプリを検索しようとしましたがAndroid Marketを実行することができませんでした。</string>
+ <string name="err_radar_generic">レーダーアプリを実行することができませんでした。インストールされてますか?</string>
+ <string name="err_navigation_no">使用できるナビゲーションが見つかりません。</string>
+ <string name="err_application_no">適切なアプリケーションが見つかりません。</string>
+ <string name="err_auth_initialize">認証プロセスの初期化に失敗しました。</string>
+ <string name="err_auth_process">認証プロセスに失敗しました。</string>
+ <string name="err_cannot_log_visit">ログを保存するのに十分な情報がありません。キャッシュの詳細を全て入力してください。</string>
+ <string name="err_init_cleared">ログイン情報を消去することができません。</string>
+ <string name="err_no_chaches">キャッシュ情報のロードに失敗しました。</string>
+ <string name="err_download_fail">キャッシュ情報のダウンロードに失敗しました。原因: </string>
+ <string name="err_update_fail">移動距離の更新に失敗しました。</string>
+ <string name="err_list_load_fail">キャッシュリストのロードに失敗しました。</string>
+ <string name="err_store_failed">キャッシュ情報を保存することができません。</string>
+ <string name="err_refresh_failed">キャッシュ情報を更新することができません。</string>
+ <string name="err_drop_failed">キャッシュ情報を破棄することができません。</string>
+ <string name="err_dwld_details_failed">キャッシュ情報の詳細をダウンロードすることができません。</string>
+ <string name="err_dwld_details_failed_reason">キャッシュ情報の詳細をダウンロードすることができません。原因: </string>
+ <string name="err_load_descr_failed">キャッシュの説明をロードすることができません。</string>
+ <string name="err_location_unknown">キャッシュの場所が分かりません。</string>
+ <string name="err_manual_title">マニュアルがインストールされていません。</string>
+ <string name="err_manual_message">Manual for c:geo(c:geoマニュアルアプリ,英語)がデバイスに存在しません。インストールされてますか?</string>
+ <string name="err_manual_market">Manual for c:geo(c:geoマニュアルアプリ,英語)を検索しようとしましたがAndroid Marketを実行することができませんでした。</string>
+
+ <string name="err_tb_display">トラッカブルアイテムを表示することができません。本当にトラッカブルアイテムですか?</string>
+ <string name="err_tb_details_open">トラッカブルアイテムの詳細を開くことができません。</string>
+ <string name="err_tb_details_download">トラッカブルアイテムの詳細をダウンロードすることができません。原因: </string>
+ <string name="err_tb_forgot">Sorry, c:geo forgot which trackable you want.</string>
+ <string name="err_tb_forgot_saw">Sorry, 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">Sorry, c:geo doesn\'t know to which cache you want to add waypoint.</string>
+ <string name="err_waypoint_unknown">Sorry, c:geo forgot what waypoint you want to display.</string>
+ <string name="err_waypoint_add_failed">ウェイポイントを追加することができません。</string>
+ <string name="err_waypoint_load_failed">ウェイポイントをロードすることができません。</string>
+ <string name="err_waypoint_delete_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">少なくとも経度、緯度、または距離と方位を入力してください。全てを入力することもできます。</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度で表し単位は付けないでください。距離は単位を付けなければメートルとして扱われ、他にkmなどの単位を付けることができます。</string>
+ <string name="err_point_location_error">ウェイポイントの場所が得られません。</string>
+ <string name="err_navigation_not_found">サポートしているナビゲーションが見つかりません。</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_failed_server">サーバの反応がないのでログを投稿することができませんでした。</string>
+ <string name="err_log_post_failed">ログを投稿することができなかったようです。geocaching.comで確認してください。</string>
+ <string name="err_log_post_failed_because">ログを投稿することができませんでした。原因: </string>
+
+ <string name="err_search_address_no_match">該当する場所が見つかりません。</string>
+ <string name="err_search_address_forgot">Sorry, c:geo forgot address you try to find.</string>
+ <string name="err_search_address">場所を検索中</string>
+ <string name="err_parse_lat">緯度の解析ができません。</string>
+ <string name="err_parse_lon">経度の解析ができません。</string>
+ <string name="err_parse_bear">方位の解析ができません。</string>
+ <string name="err_parse_dist">距離の解析ができません。</string>
+
+ <string name="warn_save_nothing">保存すべきものがありません。</string>
+ <string name="warn_no_cache_coord">座標のあるキャッシュがありません。</string>
+ <string name="warn_no_coordinates">座標が入力されていません。半角英数字にしてください。</string>
+ <string name="warn_no_keyword">キーワードが入力されていません。</string>
+ <string name="warn_no_username">ユーザ名が入力されていません。</string>
+ <string name="warn_search_help_title">ヘルプが必要?</string>
+ <string name="warn_search_help_address">住所、地名や名称を入力してください。例:住所の「Radlicka 100, Prague, Czech Republic」、都市名の「ベルリン」、または「イエローストーン国立公園」のような名称。</string>
+ <string name="warn_search_help_gccode">ジオキャッシュコード(GCコード)を半角英数字で入力してください。例:「GC1VCAZ」。</string>
+ <string name="warn_search_help_keyword">キャッシュ名の一部を入力してください。検索対象はキャッシュ名だけです。キャッシュの詳細は対象ではありません。</string>
+ <string name="warn_search_help_user">Geocaching.comのユーザ名を入力してください。</string>
+ <string name="warn_search_help_tb">トラッカブルアイテムのコード(多くはTBかTCで始まります)を入力してください。例:「TB29QMZ」。</string>
+ <string name="warn_log_text_fill">ログの本文を半角英数字記号で書いてください。(日本語は数値文字参照に変換する必要があります)</string>
+
+ <string name="info_altitude">現在地の標高</string>
+ <string name="info_distance">移動距離</string>
+ <string name="info_distance_cleared">移動距離がリセットされました。</string>
+ <string name="info_since">\n(since </string>
+
+ <string name="info_log_posted">ログを投稿しました。</string>
+ <string name="info_log_saved">ログを保存しました。</string>
+ <string name="info_log_cleared">ログを消去しました。</string>
+ <string name="info_log_type_changed">ログのタイプを変更しました。</string>
+
+ <!-- location service -->
+ <string name="loc_last">Last known</string>
+ <string name="loc_net">ネットワーク</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">衛星</string>
+ <string name="loc_trying">住所確認中</string>
+ <string name="loc_no_addr">住所不明</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">c:geoについて</string>
+ <string name="menu_helpers">ユーティリティアプリ</string>
+ <string name="menu_settings">設定</string>
+ <string name="menu_history">履歴</string>
+ <string name="menu_filter">フィルター</string>
+
+ <!-- main screen -->
+ <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="about_button">About</string>
+ <string name="settings_button">設定</string>
+ <string name="type">タイプ</string>
+ <string name="now_searching">検索中</string>
+
+ <!-- caches -->
+ <string name="caches_searching">キャッシュを検索中</string>
+ <string name="caches_no_cache">キャッシュはありません</string>
+ <string name="caches_more_caches">次のキャッシュ</string>
+ <string name="caches_more_caches_no">キャッシュは以上です</string>
+ <string name="caches_more_caches_loading">キャッシュ情報をロード中...</string>
+ <string name="caches_downloading">キャッシュ情報をダウンロード中...\n残り時間: </string>
+ <string name="caches_progress_loading_title">キャッシュ情報をロード中</string>
+ <string name="caches_progress_loading_text">デバイスに保存されたキャッシュ</string>
+ <string name="caches_eta_ltm">1分以内</string>
+ <string name="caches_eta_mins"> 分</string>
+ <string name="caches_eta_min"> 分</string>
+ <string name="caches_no_caches"> (no caches)</string>
+ <string name="caches_store_offline">オフライン用に保存</string>
+ <string name="caches_store_selected">選択したキャッシュを保存</string>
+ <string name="caches_stored">保存済み</string>
+ <string name="caches_history">履歴</string>
+ <string name="caches_on_map">地図で表示</string>
+ <string name="caches_sort">並び替え</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_title">並び替え</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_distance">距離順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_difficulty">難易度順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_terrain">地形順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_size">サイズ順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_favorites">人気順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_name">名前順</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_gccode">GCコード順(隠した年代順)</string> <!-- since: 2.2 -->
+ <string name="caches_sort_rating">評価順</string>
+ <string name="caches_sort_vote">vote (own rating)</string>
+ <string name="caches_sort_inventory">目録の数順</string>
+ <string name="caches_select">リストから選択</string>
+ <string name="caches_select_mode">選択モード</string>
+ <string name="caches_select_mode_exit">選択モードを終わる</string>
+ <string name="caches_select_invert">選択を反転</string>
+ <string name="caches_nearby">現在地の近く</string>
+ <string name="caches_manage">管理</string>
+ <string name="caches_drop_selected">選択したキャッシュを削除</string>
+ <string name="caches_drop_selected_ask">選択したキャッシュをデバイスから削除しますか?</string>
+ <string name="caches_drop_all">全て削除</string>
+ <string name="caches_drop_all_ask">全てのキャッシュをデバイスから削除しますか?</string>
+ <string name="caches_drop_stored">削除</string>
+ <string name="caches_drop_progress">キャッシュを削除中</string>
+ <string name="caches_refresh_selected">選択したキャッシュを更新</string>
+ <string name="caches_refresh_all">全てのキャッシュを更新</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">画像の文字を半角英数字で入力してください。キャッシュの座標を得るのには重要ですが必須ではありません。設定(メイン画面のメニューボタンから)で、このダイアログを表示しないようにできます。</string>
+ <string name="caches_recaptcha_hint">画像の文字</string>
+ <string name="caches_recaptcha_continue">続ける</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">リスト</string>
+ <string name="list_menu_create">新しいリストを作成</string>
+ <string name="list_menu_drop">このリストを消去</string>
+ <string name="list_menu_change">別のリストにする</string> <!-- since: 2.2 -->
+ <string name="list_title">リストの選択</string>
+ <string name="list_inbox">保存済み</string>
+ <string name="list_wpt">Waypoints</string>
+ <string name="list_dialog_create_title">新しいリスト</string>
+ <string name="list_dialog_create">作成</string>
+ <string name="list_dialog_cancel">キャンセル</string>
+ <string name="list_dialog_create_ok">新しいリストが作成されました</string>
+ <string name="list_dialog_create_err">新しいリストを作成することができませんでした</string>
+ <string name="list_dialog_remove_title">リストの消去</string>
+ <string name="list_dialog_remove_description">このキャッシュリストを消去しますか? このリストにあるキャッシュは\"保存済み\"に移動します。</string>
+ <string name="list_dialog_remove">消去</string>
+ <string name="list_dialog_remove_ok">リストは消去されました</string>
+ <string name="list_dialog_remove_err">リストを消去することができませんでした</string>
+
+ <!-- about -->
+ <string name="about_changelog">更新履歴</string>
+ <string name="about_donate">寄付</string>
+ <string name="about_detail">詳細</string>
+ <string name="about_donation_less">少し\n寄付する</string>
+ <string name="about_donation_more">開発に\n寄付する</string>
+ <string name="about_contributors">貢献者</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">ユーザ名</string>
+ <string name="init_password">パスワード</string>
+ <string name="init_passvote">パスワード</string>
+ <string name="init_login">ログインをチェックする</string>
+ <string name="init_login_popup">ログイン</string>
+ <string name="init_login_popup_working">Geocaching.comにログイン中...</string>
+ <string name="init_login_popup_ok">ログインに成功しました。</string>
+ <string name="init_login_popup_failed">ログインに失敗しました。</string>
+ <string name="init_login_popup_failed_reason">ログインに失敗しました。原因: </string>
+ <string name="init_legal">法律に関する文章</string>
+ <string name="init_go4cache_connect">Go 4 Cacheに接続する</string>
+ <string name="init_twitter_authorize">c:geoを認証する</string>
+ <string name="init_twitter_publish">キャッシュが見つかったら状況をツイートする</string>
+ <string name="init_signature">署名</string>
+ <string name="init_signature_help_button">ヘルプ</string>
+ <string name="init_signature_help_title">署名のヒント</string>
+ <string name="init_signature_help_text">ログ本文で使う署名を半角英数字記号で書いてください。(日本語は数値文字参照に変換する必要があります)\n特別な文字として[DATE]、[TIME]、[USER]や[NUMBER]があります。\nこれらは署名の挿入時に日付、時間、ユーザ名や見つけたキャッシュ数+1に変換されます。</string>
+ <string name="init_languages">Translation</string>
+ <string name="init_languages_description">Which languages you don\'t need to translate? Please provide two-character language codes.</string>
+ <string name="init_languages_hint">en es de cs</string>
+ <string name="init_translate">Translate description &amp; hint</string>
+ <string name="init_other">その他のオプション</string>
+ <string name="init_skin">明るい色のスキン\n(c:geoの再起動が必要)</string>
+ <string name="init_transparent">c:geoのメイン画面を透明化する</string>
+ <string name="init_address">メイン画面での現在地を地名で表示する</string>
+ <string name="init_captcha">必要ならCAPTCHA(画像認識)を表示する</string>
+ <string name="init_useenglish">c:geoを英語表示にする\n(c:geoの再起動が必要)</string>
+ <string name="init_exclude">自分で所有または見つけたキャッシュは除く</string>
+ <string name="init_disabled">無効化キャッシュは除く</string>
+ <string name="init_offline">オフライン用に地図を保存する</string>
+ <string name="init_units">マイル/フィート単位を使う\n(帝国単位)</string>
+ <string name="init_nav">Googleマップナビを使う</string>
+ <string name="init_autoload">キャッシュの説明を自動的に全て表示する</string>
+ <string name="init_livelist">キャッシュの一覧で方向をアイコン表示する</string>
+ <string name="init_browser">c:geoが既定のブラウザかどうか確認する</string>
+ <string name="init_altitude">標高の修正</string>
+ <string name="init_altitude_description">もし現在地の標高が正しくないなら修正できます。正または負のメートル単位で入力してください。</string>
+ <string name="init_clear">ログイン情報を消去</string>
+ <string name="init_cleared">ログイン情報を消去しました。</string>
+ <string name="init_backup">バックアップ</string>
+ <string name="init_backup_backup">バックアップ</string>
+ <string name="init_backup_note">注意: これはキャッシュ情報とウェイポイントのデータベースをバックアップ/リストアします。c:geoの設定はバックアップ/リストアの対象ではありません。また、ログイン情報(パスワードなど)は失われることはありません。</string>
+ <string name="init_backup_restore">リストア</string>
+ <string name="init_backup_success">c:geoのデータベースは正常にバックアップされました。</string>
+ <string name="init_backup_failed">c:geoのデータベースのバックアップに失敗しました。</string>
+ <string name="init_restore_success">c:geoのデータベースは正常にリストアされました。</string>
+ <string name="init_restore_failed">c:geoのデータベースのリストアに失敗しました。</string>
+ <string name="init_backup_last">最終バックアップ日時:</string>
+ <string name="init_backup_last_no">バックアップすべきファイルがありません。</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">c:geoを認証する</string>
+ <string name="auth_start">認証を開始する</string>
+ <string name="auth_again">再度認証を開始する</string>
+ <string name="auth_pin_hint">TwitterのPINコード</string>
+ <string name="auth_finish">完了</string>
+ <string name="auth_dialog_wait">Twitterからの返答を待っています...</string>
+ <string name="auth_dialog_pin_title">PINコード</string>
+ <string name="auth_dialog_pin_message">Twitterのサイトで表示されたPINコードを入力してください。認証を完了するために必要です。</string>
+ <string name="auth_dialog_completed">c:geoはTwitterにポストするための認証を受けました。</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">キャッシュがありません</string>
+ <string name="cache_count_one">1つのキャッシュ</string>
+ <string name="cache_count_more">個のキャッシュ</string>
+ <string name="cache_offline">オフライン</string>
+ <string name="cache_offline_refresh">更新</string>
+ <string name="cache_offline_drop">削除</string>
+ <string name="cache_offline_store">保存</string>
+ <string name="cache_offline_stored">デバイスに保存済み</string>
+ <string name="cache_offline_not_ready">オフライン用に\n保存されていません</string>
+ <string name="cache_offline_time_about">約</string>
+ <string name="cache_offline_time_mins">分前</string>
+ <string name="cache_offline_time_mins_few">数分前</string>
+ <string name="cache_offline_time_hour">1時間前</string>
+ <string name="cache_offline_time_hours">時間前</string>
+ <string name="cache_offline_time_days">日前</string>
+ <string name="cache_premium">プレミア会員</string>
+ <string name="cache_attributes">属性</string>
+ <string name="cache_inventory">目録</string>
+ <string name="cache_log_offline">オフラインログ</string>
+ <string name="cache_description">説明</string>
+ <string name="cache_description_long">全ての説明</string>
+ <string name="cache_waypoints">ウェイポイント</string>
+ <string name="cache_waypoints_add">ウェイポイント追加</string>
+ <string name="cache_hint">ヒント</string>
+ <string name="cache_logs">ログブック</string>
+ <string name="cache_dialog_loading_details">キャッシュの詳細をロード中...</string>
+ <string name="cache_dialog_loading_description">キャッシュの説明をロード中...</string>
+ <string name="cache_dialog_offline_save_title">オフライン</string>
+ <string name="cache_dialog_offline_save_message">オフライン用にキャッシュを保存中...</string>
+ <string name="cache_dialog_offline_drop_title">オフライン</string>
+ <string name="cache_dialog_offline_drop_message">デバイスからキャッシュ情報を削除中...</string>
+ <string name="cache_dialog_refresh_title">更新</string>
+ <string name="cache_dialog_refresh_message">キャッシュの詳細を再ロード中...</string>
+ <string name="cache_menu_navigate">ナビゲーション</string>
+ <string name="cache_menu_compass">コンパス</string>
+ <string name="cache_menu_tbt">道順ナビ</string>
+ <string name="cache_menu_radar">レーダー</string>
+ <string name="cache_menu_map">地図で表示</string>
+ <string name="cache_menu_map_static">オフライン地図</string>
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_ext">外部地図で表示</string>
+ <string name="cache_menu_map_short">Maps</string>
+ <string name="cache_menu_map_ext_short">外部地図</string>
+ <string name="cache_menu_browser">ブラウザで開く</string>
+ <string name="cache_menu_visit">ログを書く</string>
+ <string name="cache_menu_spoilers">スポイラー画像</string>
+ <string name="cache_menu_around">近くのキャッシュ</string>
+ <string name="cache_menu_event">カレンダーに追加</string>
+ <string name="cache_menu_details">詳細</string>
+ <string name="cache_menu_share">キャッシュを共有</string>
+ <string name="cache_status">状態</string>
+ <string name="cache_status_offline_log">保存済みのログ</string>
+ <string name="cache_status_found">見つかった</string>
+ <string name="cache_status_archived">アーカイブ済み</string>
+ <string name="cache_status_disabled">無効化</string>
+ <string name="cache_status_premium">プレミア会員のみ</string>
+ <string name="cache_geocode">GCコード</string>
+ <string name="cache_name">名前</string>
+ <string name="cache_type">タイプ</string>
+ <string name="cache_distance">距離</string>
+ <string name="cache_difficulty">難易度</string>
+ <string name="cache_terrain">地形</string>
+ <string name="cache_rating">評価</string>
+ <string name="cache_rating_of">/</string>
+ <string name="cache_favourite">お気に入り</string>
+ <string name="cache_owner">所有者</string>
+ <string name="cache_hidden">隠した日</string>
+ <string name="cache_event">日時</string>
+ <string name="cache_location">場所</string>
+ <string name="cache_coordinates">座標</string>
+ <string name="cache_elevation">高度</string>
+ <string name="cache_calendars">カレンダーを選択</string>
+ <string name="cache_spoiler_images_title">スポイラー画像</string>
+ <string name="cache_spoiler_images_loading">スポイラー画像をロード中...</string>
+ <string name="cache_log_types">ログタイプ</string> <!-- Since: 2.10 RC2 -->
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">GPXファイルを検索中\nフォルダ:</string>
+ <string name="gpx_import_loading_stored">GPXファイルをロード中\n保存済み:</string>
+ <string name="gpx_import_no_files">GPXファイルが見つかりません。</string>
+ <string name="gpx_import_caches_imported">個のキャッシュを読み込みました</string>
+ <string name="gpx_import_searching">GPXファイルを検索中</string>
+ <string name="gpx_import_loading">GPXファイルをロード中</string>
+ <string name="gpx_import_title">GPXファイルの読み込み</string>
+ <string name="gpx_import_title_reading_file">ファイルを読み込み中</string>
+ <string name="gpx_import_title_searching">検索中</string>
+ <string name="gpx_import_title_caches_imported">結果</string>
+
+ <!-- event -->
+ <string name="event_success">イベントキャッシュがカレンダーに追加されました</string>
+ <string name="event_fail">イベントキャッシュをカレンダーに追加するのに失敗しました</string>
+
+ <!-- popup -->
+ <string name="popup_more">詳細を見る</string>
+ <string name="popup_offline">オフライン</string>
+
+ <!-- waypoint -->
+ <string name="waypoint">ウェイポイント</string>
+ <string name="waypoint_title">ウェイポイント</string>
+ <string name="waypoint_custom">カスタム</string>
+ <string name="waypoint_my_coordinates">現在地</string>
+ <string name="waypoint_bearing">方位</string>
+ <string name="waypoint_distance">距離</string>
+ <string name="waypoint_name">名前</string>
+ <string name="waypoint_edit">編集</string>
+ <string name="waypoint_delete">削除</string>
+ <string name="waypoint_edit_title">ウェイポイントを編集</string>
+ <string name="waypoint_add_title">ウェイポイントを追加</string>
+ <string name="waypoint_note">メモ</string>
+ <string name="waypoint_save">保存</string>
+ <string name="waypoint_loading">ウェイポイントをロード中...</string>
+ <string name="waypoint_unknown_coordinates">Coordinates unknown</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">この発見をTwitterでつぶやく</string>
+
+ <!-- map -->
+ <string name="map_map">地図</string>
+ <string name="map_live">オンライン地図</string>
+ <string name="map_view_satellite">航空写真表示</string>
+ <string name="map_view_map">地図表示</string>
+ <string name="map_trail_show">軌跡表示</string>
+ <string name="map_trail_hide">軌跡非表示</string>
+ <string name="map_circles_show">Show circles</string> <!-- since: 2.23 RC3 -->
+ <string name="map_circles_hide">Hide circles</string> <!-- since: 2.23 RC3 -->
+ <string name="map_live_enable">オンラインで取得</string>
+ <string name="map_live_disable">保存済みキャッシュのみ</string>
+ <string name="map_static_title">オフライン地図</string>
+ <string name="map_static_loading">オフライン地図をロード中...</string>
+
+ <!-- search -->
+ <string name="search_bar_hint">キャッシュ検索</string>
+ <string name="search_bar_desc">キャッシュ(GCコード,キーワード), トラッカブルアイテム(TBコード)</string>
+ <string name="search_coordinates">座標</string>
+ <string name="search_coordinates_button">座標で検索</string>
+ <string name="search_address">住所</string>
+ <string name="search_address_button">住所で検索</string>
+ <string name="search_gc">GCコード</string>
+ <string name="search_gc_button">GCコードで検索</string>
+ <string name="search_kw">キーワード</string>
+ <string name="search_kw_prefill">キーワード</string>
+ <string name="search_kw_button">キーワードで検索</string>
+ <string name="search_kw_caches">キーワード</string>
+ <string name="search_caches_found_by">見つけたユーザ</string>
+ <string name="search_caches_hidden_by">隠したユーザ</string>
+ <string name="search_fbu">ユーザが見つけたキャッシュ</string>
+ <string name="search_fbu_prefill">ユーザ名</string>
+ <string name="search_fbu_button">ユーザ名で検索</string>
+ <string name="search_hbu">ユーザが隠したキャッシュ</string>
+ <string name="search_hbu_prefill">所有者名</string>
+ <string name="search_hbu_button">所有者名で検索</string>
+ <string name="search_tb">トラッカブルアイテム</string>
+ <string name="search_tb_hint">トラッカブルアイテムコード(TBコード)</string>
+ <string name="search_tb_button">トラッカブルアイテムを検索</string>
+ <string name="search_destination">目的地</string>
+ <string name="search_direction_rel">この地点から</string>
+ <string name="search_lat">緯度</string>
+ <string name="search_lon">経度</string>
+ <string name="search_caches">キャッシュの検索</string>
+ <string name="search_caches_near">近くのキャッシュ</string>
+ <string name="search_address_started">場所を検索中</string>
+ <string name="search_address_result">検索結果:場所</string>
+
+ <!-- trackable -->
+ <string name="trackable">トラッカブルアイテム</string>
+ <string name="trackable_select_title">トラッカブルアイテム</string>
+ <string name="trackable_details_loading">トラッカブルアイテムの詳細をロード中...</string>
+ <string name="trackable_log_touch">Log touch</string>
+ <string name="trackable_browser_open">ブラウザで開く</string>
+ <string name="trackable_goal">目的</string>
+ <string name="trackable_details">詳細</string>
+ <string name="trackable_image">画像</string>
+ <string name="trackable_code">TBコード</string>
+ <string name="trackable_name">名前</string>
+ <string name="trackable_type">タイプ</string>
+ <string name="trackable_owner">所有者</string>
+ <string name="trackable_spotted">Spotted</string>
+ <string name="trackable_spotted_in_cache">In</string>
+ <string name="trackable_spotted_at_user">In the hands of</string>
+ <string name="trackable_spotted_unknown_location">Unknown location</string>
+ <string name="trackable_spotted_owner">In the hands of the owner</string>
+ <string name="trackable_origin">出発地</string>
+ <string name="trackable_unknown">不明</string>
+ <string name="trackable_released">リリース</string>
+ <string name="trackable_distance">Travelled</string>
+ <string name="trackable_touch">Touch</string>
+
+ <!-- user -->
+ <string name="user_menu_title">ユーザ名:</string>
+ <string name="user_menu_view_hidden">隠したキャッシュ</string>
+ <string name="user_menu_view_found">見つけたキャッシュ</string>
+ <string name="user_menu_open_browser">ブラウザでプロフィールを開く</string>
+
+ <!-- navigation -->
+ <string name="navigation">ナビゲーション</string>
+ <string name="compass_title">コンパス</string>
+ <string name="use_gps">GPSを使う</string>
+ <string name="use_compass">コンパスを使う</string>
+ <string name="destination_select">目的地を選択</string>
+ <string name="destination_set">目的地を入力</string>
+
+ <!-- license -->
+ <string name="license">ライセンス</string>
+ <string name="license_show">ライセンスを表示</string>
+ <string name="license_dismiss">閉じる</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">マニュアル</string>
+ <string name="helper_manual_description">c:geoのマニュアル(英語)はこのアプリで出来る事(隠れ機能も)の全てについて書いてあります。</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>
+ <string name="helper_bluetoothgps_description">外部GPSデバイスを利用することができます。より良いGPS受信ができ、より正確な位置情報を得られ、アンドロイド端末のバッテリ消費が少なくなるかもしれません。</string>
+
+ <!-- attributes (permissions -> allowed, not allowed) -->
+ <string name="attribute_dogs_yes">犬の同伴可</string>
+ <string name="attribute_dogs_no">犬の同伴不可</string>
+ <string name="attribute_bicycles_yes">自転車侵入可</string>
+ <string name="attribute_bicycles_no">自転車侵入不可</string>
+ <string name="attribute_motorcycles_yes">バイク侵入可</string>
+ <string name="attribute_motorcycles_no">バイク侵入不可</string>
+ <string name="attribute_quads_yes">4輪バギー侵入可</string>
+ <string name="attribute_quads_no">4輪バギー侵入不可</string>
+ <string name="attribute_jeeps_yes">オフロード車侵入可</string>
+ <string name="attribute_jeeps_no">オフロード車侵入不可</string>
+ <string name="attribute_snowmobiles_yes">スノーモービル侵入可</string>
+ <string name="attribute_snowmobiles_no">スノーモービル侵入不可</string>
+ <string name="attribute_horses_yes">馬侵入可</string>
+ <string name="attribute_horses_no">馬侵入不可</string>
+ <string name="attribute_campfires_yes">焚き火可</string>
+ <string name="attribute_campfires_no">焚き火不可</string>
+ <string name="attribute_rv_yes">トラック/RV車侵入可</string>
+ <string name="attribute_rv_no">トラック/RV車侵入不可</string>
+
+ <!-- attributes (conditions -> yes, no) -->
+ <string name="attribute_kids_yes">子供にお薦め</string>
+ <string name="attribute_kids_no">子供にお薦めしない</string>
+ <string name="attribute_onehour_yes">1時間以内</string>
+ <string name="attribute_onehour_no">1時間以上</string>
+ <string name="attribute_scenic_yes">美景</string>
+ <string name="attribute_scenic_no">美景なし</string>
+ <string name="attribute_hiking_yes">長距離の歩行</string>
+ <string name="attribute_hiking_no">長距離の歩行なし</string>
+ <string name="attribute_climbing_yes">難しい登山</string>
+ <string name="attribute_climbing_no">難しい登山なし</string>
+ <string name="attribute_wading_yes">渡渉(水中を歩いて渡る)箇所あり</string>
+ <string name="attribute_wading_no">渡渉水中を歩いて渡る)箇所なし</string>
+ <string name="attribute_swimming_yes">泳いで渡る箇所あり</string>
+ <string name="attribute_swimming_no">泳いで渡る箇所なし</string>
+ <string name="attribute_available_yes">24時間有効</string>
+ <string name="attribute_available_no">24時間有効ではない</string>
+ <string name="attribute_night_yes">夜がお薦め</string>
+ <string name="attribute_night_no">夜はお薦めしない</string>
+ <string name="attribute_winter_yes">冬季に有効</string>
+ <string name="attribute_winter_no">冬季は有効ではない</string>
+ <string name="attribute_stealth_yes">人目を忍ぶ必要あり</string>
+ <string name="attribute_stealth_no">人目を忍ぶ必要なし</string>
+ <string name="attribute_firstaid_yes">メンテナンスが必要</string>
+ <string name="attribute_firstaid_no">メンテナンスが必要ではない</string>
+ <string name="attribute_cow_yes">家畜に注意</string>
+ <string name="attribute_cow_no">家畜はいません</string>
+ <string name="attribute_field_puzzle_yes">Field puzzle</string>
+ <string name="attribute_field_puzzle_no">No field puzzle</string>
+ <string name="attribute_nightcache_yes">ナイトキャッシュ</string>
+ <string name="attribute_nightcache_no">ナイトキャッシュではない</string>
+ <string name="attribute_parkngrab_yes">Park and grab</string>
+ <string name="attribute_parkngrab_no">No park and grab</string>
+ <string name="attribute_abandonedbuilding_yes">廃墟</string>
+ <string name="attribute_abandonedbuilding_no">廃墟ではない</string>
+ <string name="attribute_hike_short_yes">短距離の歩行(1km以下)</string>
+ <string name="attribute_hike_short_no">短距離の歩行ではない</string>
+ <string name="attribute_hike_med_yes">中距離の歩行(1kmから10km)</string>
+ <string name="attribute_hike_med_no">中距離の歩行ではない</string>
+ <string name="attribute_hike_long_yes">長距離の歩行(10km以上)</string>
+ <string name="attribute_hike_long_no">長距離の歩行ではない</string>
+ <string name="attribute_landf_yes">Lost and found tour</string>
+ <string name="attribute_landf_no">No lost and found tour</string>
+ <string name="attribute_sponsored_yes">Sponsored cache</string>
+ <string name="attribute_sponsored_no">Non sponsored cache</string>
+
+ <!-- attributes (equipment -> required, not required) -->
+ <string name="attribute_fee_yes">交通料金や駐車料金が必要</string>
+ <string name="attribute_fee_no">交通料金や駐車料金は不要</string>
+ <string name="attribute_rappelling_yes">登山道具が必要</string>
+ <string name="attribute_rappelling_no">登山道具は不要</string>
+ <string name="attribute_boat_yes">船が必要</string>
+ <string name="attribute_boat_no">船は不要</string>
+ <string name="attribute_scuba_yes">スキューバダイビング用具が必要</string>
+ <string name="attribute_scuba_no">スキューバダイビング用具は不要</string>
+ <string name="attribute_flashlight_yes">懐中電燈が必要</string>
+ <string name="attribute_flashlight_no">懐中電燈は不要</string>
+ <string name="attribute_UV_yes">UVライトが必要</string>
+ <string name="attribute_UV_no">UVライトは不要</string>
+ <string name="attribute_snowshoes_yes">スノーシューが必要</string>
+ <string name="attribute_snowshoes_no">スノーシューは不要</string>
+ <string name="attribute_skiis_yes">クロスカントリースキーが必要</string>
+ <string name="attribute_skiis_no">クロスカントリースキーは不要</string>
+ <string name="attribute_s_tool_yes">特別な道具が必要</string>
+ <string name="attribute_s_tool_no">特別な道具は不要</string>
+ <string name="attribute_wirelessbeacon_yes">無線ビーコンあり</string>
+ <string name="attribute_wirelessbeacon_no">無線ビーコンなし</string>
+
+ <!-- attributes (hazards -> present, not present) -->
+ <string name="attribute_poisonoak_yes">有毒植物あり</string>
+ <string name="attribute_poisonoak_no">有毒植物なし</string>
+ <string name="attribute_dangerousanimals_yes">有害動物がいる</string>
+ <string name="attribute_dangerousanimals_no">有害動物はいない</string>
+ <string name="attribute_ticks_yes">ダニがいる</string>
+ <string name="attribute_ticks_no">ダニはいない</string>
+ <string name="attribute_mine_yes">廃坑あり</string>
+ <string name="attribute_mine_no">廃坑なし</string>
+ <string name="attribute_cliff_yes">崖/落石あり</string>
+ <string name="attribute_cliff_no">崖/落石なし</string>
+ <string name="attribute_hunting_yes">ハンターがいる</string>
+ <string name="attribute_hunting_no">ハンターはいない</string>
+ <string name="attribute_danger_yes">危険区域</string>
+ <string name="attribute_danger_no">危険区域ではない</string>
+ <string name="attribute_thorn_yes">棘のある植物あり</string>
+ <string name="attribute_thorn_no">棘のある植物なし</string>
+
+ <!-- attributes (facilities -> yes, no) -->
+ <string name="attribute_wheelchair_yes">車いす可</string>
+ <string name="attribute_wheelchair_no">車いす不可</string>
+ <string name="attribute_parking_yes">駐車場あり</string>
+ <string name="attribute_parking_no">駐車場なし</string>
+ <string name="attribute_public_yes">公共交通機関あり</string>
+ <string name="attribute_public_no">公共交通機関なし</string>
+ <string name="attribute_water_yes">近くに飲料水あり</string>
+ <string name="attribute_water_no">近くに飲料水なし</string>
+ <string name="attribute_restrooms_yes">近くに公共トイレあり</string>
+ <string name="attribute_restrooms_no">近くに公共トイレなし</string>
+ <string name="attribute_phone_yes">近くに公衆電話あり</string>
+ <string name="attribute_phone_no">近くに公衆電話なし</string>
+ <string name="attribute_picnic_yes">近くにピクニックテーブルあり</string>
+ <string name="attribute_picnic_no">近くにピクニックテーブルなし</string>
+ <string name="attribute_camping_yes">キャンプ可</string>
+ <string name="attribute_camping_no">キャンプ不可</string>
+ <string name="attribute_stroller_yes">ベビーカー可</string>
+ <string name="attribute_stroller_no">ベビーカー不可</string>
+ <string name="attribute_fuel_yes">近くにガソリンスタンドあり</string>
+ <string name="attribute_fuel_no">近くにガソリンスタンドなし</string>
+ <string name="attribute_food_yes">近くに飲食店あり</string>
+ <string name="attribute_food_no">近くに飲食店なし</string>
+
+ <!-- next things -->
+ <string name="legal_note">Geocaching.comを使うには<a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeak 利用規約(英語)</a>に同意している必要があります。</string>
+ <string name="quote">To make geocaching easier, to make users lazier.</string>
+ <string name="powered_by">carnero</string>
+ <string name="author">作者: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">サポート: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">ウェブサイト: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="nutshellmanual">マニュアル: <a href="http://appmanualreader.sourceforge.net/manuals/cgeo/cgeo-help-en.html">c:geo マニュアル(英語)</a></string>
+ <string name="about_go4cache"><b>Go 4 cache</b>サービスにより他のジオキャッシャーを(<b>c:geo</b>またはブラウザで)地図上にリアルタイムで表示できます。例えば、彼らがどのキャッシュを探しているのか表示できます。<b>Go 4 cache</b>に接続すれば<b>c:geo</b>でジオキャッシング中に現在地を(<b>c:geo</b>が起動している間だけ)公開することができます。</string>
+ <string name="about_twitter">キャッシュのログを書いたら<b>c:geo</b>にTwitterでつぶやいてほしい?</string>
+ <string name="about_auth_1"><b>c:geo</b>がTwitterにアクセスする許可を得るには次のようにしてください。</string>
+ <string name="about_auth_2">「認証を開始する」ボタンを押すとブラウザでTwitterのページが開きます。そのページにログインすれば<b>c:geo</b>があなたのアカウントにアクセルする許可が得られます。ログインに成功したら数字のPINコードが表示されるので、この下の入力欄にコピー&amp;ペーストして「完了」ボタンを押してください。</string>
+</resources> \ No newline at end of file
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
new file mode 100644
index 0000000..d78fc3c
--- /dev/null
+++ b/res/values-nb/strings.xml
@@ -0,0 +1,475 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompass</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detalj</string>
+ <string name="search">Søk</string>
+ <string name="settings">Instillinger</string>
+ <string name="about">Om c:geo</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Del link til cachen</string>
+
+ <!-- caches -->
+ <string name="all">Alle cacher</string>
+ <string name="all_types">Alle cache typer</string>
+ <string name="traditional">Tradisjonell cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Ukjent cache</string>
+ <string name="letterbox">Letterbox hybrid</string>
+ <string name="event">Hendelse-cache</string>
+ <string name="mega">Mega-hendelse-cache</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">"Cache in trash out"-hendelse</string>
+ <string name="webcam">Webkamera cache</string>
+ <string name="virtual">Virtuell cache</string>
+ <string name="wherigo">Wherigo cache</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Prosjekt A.P.E. cache</string>
+ <string name="gchq">Groundspeak hovedkvarter</string>
+ <string name="gps">GPS cache</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Sluttpunkt</string>
+ <string name="wp_stage">Multi-cache nivå</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_waypoint">Referanse-punkt</string>
+
+ <!-- logs -->
+ <string name="log_found">Funnet</string>
+ <string name="log_dnf">Ikke funnet</string>
+ <string name="log_note">Notat</string>
+ <string name="log_published">Publisert</string>
+ <string name="log_enabled">Aktivert</string>
+ <string name="log_disabled">Deaktivert</string>
+ <string name="log_attend">Har tenkt å komme</string>
+ <string name="log_attended">Kom</string>
+ <string name="log_retrieved">Tatt fra plassen den skulle være</string>
+ <string name="log_grabbed">Tatt fra en plass den ikke skulle vært</string>
+ <string name="log_maintained">Vedlikehold utført</string>
+ <string name="log_maintenance_needed">Trenger vedlikehold</string>
+ <string name="log_maintenance_owner">Vedlikehold</string>
+ <string name="log_update">Koordinater oppdatert</string>
+ <string name="log_archived">Arkivert</string>
+ <string name="log_needs_archived">Bør arkiveres</string>
+ <string name="log_discovered">Oppdaget</string>
+ <string name="log_reviewed">Andmeldelse</string>
+ <string name="log_tb_nothing">Ikke gjør noe</string>
+ <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_saving">Lagrer logg...</string>
+ <string name="log_clear">Slett</string>
+ <string name="log_post">Last opp loggen</string>
+ <string name="log_post_rate">Last opp loggen og rangér</string>
+ <string name="log_post_no_rate">Last opp loggen uten å rangere</string>
+ <string name="log_add">Legg til</string>
+ <string name="log_date">Dato</string>
+ <string name="log_time">Klokkelsett</string>
+ <string name="log_date_time">Dato og klokkeslett</string>
+ <string name="log_rating">Rangering</string>
+ <string name="log_no_rating">Ingen rangering</string>
+ <string name="log_stars_1">1 stjerne</string>
+ <string name="log_stars_2">2 stjerner</string>
+ <string name="log_stars_3">3 stjerner</string>
+ <string name="log_stars_4">4 stjerner</string>
+ <string name="log_stars_5">5 stjerner</string>
+ <string name="log_webcam">Webkamera-bilde tatt</string>
+ <string name="log_new_log">Logg</string>
+ <string name="log_new_log_text">Logg tekst</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Klarte ikke å koble til</string>
+ <string name="err_parse">Klarte ikke å lese innloggings-siden</string>
+ <string name="err_server">Klarte ikke å koble til geocaching.com (server eller tilkobling nede?)</string>
+ <string name="err_login">Ingen innloggings-opplysninger lagret</string>
+ <string name="err_login_failed">Beklager, c:geo kan ikke logge inn.</string>
+ <string name="err_unknown">Ukjent feil</string>
+ <string name="err_comm">Ukjent tilkoblings-feil</string>
+ <string name="err_missing_auth">Brukernavn eller passord er ikke oppgitt.</string>
+ <string name="err_wrong">Feilaktige innloggings-opplysninger</string>
+ <string name="err_license">Brukeren har ikke akseptert Geocaching.com sin lisens-betingelse, så c:geo kan ikke laste cachens koordinater</string>
+ <string name="err_store">Beklager, c:geo klarte ikke å lagre cachen.</string>
+ <string name="err_drop">Beklager, c:geo klarte ikke å slette cachen.</string>
+ <string name="err_title_problem">problem</string>
+ <string name="err_detail_open">Beklager, c:geo klarte ikke å finne detaljene.</string>
+ <string name="err_detail_cache">Beklager, c:geo klarte ikke å finne den forespurte cachen. Er du sikker på at den eksisterer?</string>
+ <string name="err_detail_cache_find">Beklager, c:geo klarte ikke å finne geocachen</string>
+ <string name="err_detail_cache_find_some">Beklager, c:geo klarte ikke å finne den forespurte cachen.</string>
+ <string name="err_detail_cache_find_any">Beklager, c:geo klarte ikke finne geocacher..</string>
+ <string name="err_detail_cache_find_next">Beklager, c:geo klarte ikke å finne den neste geocachen.</string>
+ <string name="err_detail_cache_forgot">Beklager, c:geo glemte hvilken cache du ønsket.</string>
+ <string name="err_detail_cache_forgot_visit">Beklager, c:geo glemte hvilken cache du fant.</string>
+ <string name="err_detail_cache_language">c:geo klarte ikke å finne cache-detaljene. Vennligst sjekk om geocaching.com sitt språk er satt til engelsk. Desverre, forstår ikke c:geo andre språk.</string>
+ <string name="err_detail_no_spoiler">c:geo fant ingen bilder for denne cachen.</string>
+ <string name="err_detail_no_map_static">c:geo fant ingen statiske kart for denne cachen.</string>
+ <string name="err_detail_still_removing">c:geo holder fortsatt på med å slette denne cachen.</string>
+ <string name="err_detail_still_saving">c:geo holder fortsatt på med å lagre denne cachen.</string>
+ <string name="err_detail_still_refreshing">c:geo holder fortsatt på med å laste inn denne cachen på nytt.</string>
+ <string name="err_radar_title">Radar er ikke installert.</string>
+ <string name="err_radar_message">Denne funksjonen krever applikasjonen "Radar" . Burde det være installert?</string>
+ <string name="err_radar_market">c:geo klarte ikke å åpne Android Marked for å søke etter applikasjonen "Radar".</string>
+ <string name="err_radar_generic">Beklager, c:geo klarte ikke å åpne applikasjonen "Radar". Er det installert?</string>
+ <string name="err_navigation_no">c:geo klarte ikke å finne støttet navigasjon.</string>
+ <string name="err_application_no">c:geo klarte ikke å finne en passende applikasjon.</string>
+ <string name="err_auth_initialize">Beklager, c:geo klarte ikke å igangsette autoriserings-prosessen.</string>
+ <string name="err_auth_process">Autoriserings-prosessen mislyktes.</string>
+ <string name="err_cannot_log_visit">c:geo har ikke nok informasjon til å logge funn. Prøv å laste inn cachens detaljer først.</string>
+ <string name="err_init_cleared">Beklager, c:geo klarte ikke å fjerne innloggings-opplysningene.</string>
+ <string name="err_no_chaches">Beklager, c:geo klarte ikke å laste cachen eller cachenes informasjon..</string>
+ <string name="err_download_fail">Beklager. c:geo klarte ikke å laste ned cachene p.g.a.</string>
+ <string name="err_update_fail">c:geo klarte ikke å oppdatere avstanden reist</string>
+ <string name="err_list_load_fail">Beklager, c:geo klarte ikke å laste cache-listen..</string>
+ <string name="err_store_failed">Beklager, c:geo klarte ikke å lagre cachen.</string>
+ <string name="err_refresh_failed">Beklager, c:geo klarte ikke å oppdatere cachen.</string>
+ <string name="err_drop_failed">Beklager, c:geo klarte ikke å slette cachen.</string>
+ <string name="err_dwld_details_failed">Beklager, c:geo klarte ikke å laste ned cachens detaljer</string>
+ <string name="err_dwld_details_failed_reason">Beklager, c:geo klarte ikke å laste ned cachens detaljer p.g.a.</string>
+ <string name="err_load_descr_failed">Beklager, c:geo klarte ikke å åpne beskrivelsen.</string>
+
+ <string name="err_location_unknown">c:geo vet ikke hvor cachen er.</string>
+ <string name="err_tb_display">"Beklager, c:geo klarte ikke å finne trackable\'en du etterspurte. Er det virkelig en trackable?</string>
+ <string name="err_tb_details_open">Beklager, c:geo klarte ikke å åpne tracable\'ens detaljer.</string>
+ <string name="err_tb_details_download">Beklager, c:geo klarte ikke å laste ned trackable\'ens detaljer p.g.a.</string>
+ <string name="err_tb_forgot">Beklager, c:geo glemte hvilken trackable du etterspurte.</string>
+ <string name="err_tb_forgot_saw">Beklager, c:geo glemte hvilken trackable du oppdaget.</string>
+ <string name="err_tb_find">Beklager, c:geo klarte ikke å finne noen trackable\'er.</string>
+ <string name="err_tb_find_that">Beklager, c:geo kan ikke finne noen trackable\'er</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_failed_server">Beklager, c:geo klarte ikke å logge funnet fordi serveren er nede.</string>
+ <string name="err_log_post_failed">Beklager, c:geo klarte ikke å logge funnet.</string>
+ <string name="err_log_post_failed_because">Beklager, c:geo klarte ikke å logge funnet p.g.a.</string>
+
+ <string name="err_search_address_no_match">Beklager, c:geo klarte ikke å finne den forespurte adressen.</string>
+ <string name="err_search_address_forgot">Beklager, c:geo glemte adressen du prøvde å finne.</string>
+ <string name="err_search_address">Søker etter plasser</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>
+ <string name="err_parse_bear">Beklager, c:geo klarte ikke å lese peilingen..</string>
+ <string name="err_parse_dist">Beklager, c:geo klarte ikke å lese avstanden.</string>
+
+ <string name="warn_save_nothing">Det er ingenting som kan lagres.</string>
+ <string name="warn_no_cache_coord">Det er ingen cacher som oppgir koordinater.</string>
+ <string name="warn_no_coordinates">Ingen koordinater er oppgitt.</string>
+ <string name="warn_no_keyword">Ingen stikkord er oppgitt.</string>
+ <string name="warn_no_username">Brukernavn er ikke oppgitt.</string>
+
+ <string name="warn_log_text_fill">Vennligst skriv en logg-tekst.</string>
+
+ <string name="info_altitude">Nåværende høyde</string>
+ <string name="info_distance">Avstand reist</string>
+ <string name="info_distance_cleared">Avstanden reist ble nullstilt.</string>
+ <string name="info_since">\n(siden </string>
+
+ <string name="info_log_posted">c:geo lyktes i å logge funnet.</string>
+ <string name="info_log_saved">c:geo lyktes i å lagre loggen.</string>
+ <string name="info_log_cleared">Loggen ble slettet.</string>
+ <string name="info_log_type_changed">Logg-typen har blitt forandret!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Sist sett</string>
+ <string name="loc_net">Nettverk</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Satelitt</string>
+ <string name="loc_trying">Prøver å lokalisere</string>
+ <string name="loc_no_addr">Ukjent adresse</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Om c:geo</string>
+ <string name="menu_settings">Instillinger</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live kart</string>
+ <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="about_button">Om c:geo</string>
+ <string name="settings_button">Instillinger</string>
+ <string name="type">Type</string>
+ <string name="now_searching">Søker</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Søker etter cacher</string>
+ <string name="caches_no_cache">ingen cacher</string>
+ <string name="caches_more_caches">flere cacher</string>
+ <string name="caches_more_caches_no">ingen flere cacher</string>
+ <string name="caches_downloading">Laster ned cacher...\nETA: </string>
+ <string name="caches_progress_loading_title">Laster cacher</string>
+ <string name="caches_progress_loading_text">Cachene er lagret på enheten</string>
+ <string name="caches_eta_ltm">Mindre enn ett minutt</string>
+ <string name="caches_eta_mins"> minutter</string>
+ <string name="caches_eta_min"> minutt</string>
+ <string name="caches_no_caches"> (ingen cacher)</string>
+ <string name="caches_store_offline">Lagre for offline-bruk</string>
+ <string name="caches_store_selected">Lagre valgte</string>
+ <string name="caches_stored">Lagret</string>
+ <string name="caches_on_map">Vis på kartet</string>
+ <string name="caches_select">Velg fra listen</string>
+ <string name="caches_select_mode">Velge-modus</string>
+ <string name="caches_select_mode_exit">Avslutt velge-modus</string>
+ <string name="caches_nearby">I nærheten</string>
+ <string name="caches_drop_selected">Slett valgte</string>
+ <string name="caches_drop_selected_ask">Vil du slette de valgte cachene fra enheten?</string>
+ <string name="caches_drop_all">Slett alle</string>
+ <string name="caches_drop_all_ask">Vil du slette alle cacher fra enheten?</string>
+ <string name="caches_drop_stored">Slett lagrede</string>
+ <string name="caches_refresh_selected">Oppdater valgte</string>
+ <string name="caches_refresh_all">Oppdater alle</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+
+
+ <!-- about -->
+ <string name="about_changelog">Oppdateringslogg</string>
+ <string name="about_donate">Donér</string>
+ <string name="about_detail">Detaljer</string>
+ <string name="about_donation_less">Donér\nmindre</string>
+ <string name="about_donation_more">Donér til\nutviklerne</string>
+ <string name="about_contributors">Bidragsytere</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCVote.com</string>
+ <string name="init_go4cache">go 4 cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Brukernavn</string>
+ <string name="init_password">Passord</string>
+ <string name="init_passvote">Passord</string>
+ <string name="init_login">Sjekk innloggings-opplysninger</string>
+ <string name="init_login_popup">Logg inn</string>
+ <string name="init_login_popup_working">Logger inn på geocaching.com...</string>
+ <string name="init_login_popup_ok">Innlogging fullført.</string>
+ <string name="init_login_popup_failed">Innlogging mislyktes.</string>
+ <string name="init_login_popup_failed_reason">Innlogging mislyktes p.g.a.</string>
+ <string name="init_legal">Juridisk informasjon</string>
+ <string name="init_go4cache_connect">Koble til go 4 cache</string>
+ <string name="init_twitter_authorize">Autoriser c:geo</string>
+ <string name="init_twitter_publish">Del på Twitter når du finner cacher</string>
+ <string name="init_signature">Signatur</string>
+ <string name="init_other">Andre instillinger</string>
+ <string name="init_skin">Hvitt tema</string>
+ <string name="init_transparent">Bruk mobilens bakgrunn i menyen</string>
+ <string name="init_address">Vis adressen i menyen</string>
+ <string name="init_exclude">Ekskluder egne og funnede cacher fra kartet</string>
+ <string name="init_disabled">Ekskluder deaktiverte cacher</string>
+ <string name="init_offline">Lagre kartet for offline-bruk (små deler)</string>
+ <string name="init_units">Bruk imperialistiske måleenheter</string>
+ <string name="init_nav">Bruk Google Navigation</string>
+ <string name="init_autoload">Last full beskrivelse automatisk</string>
+ <string name="init_livelist">Vis cachers retning i listen</string>
+ <string name="init_browser">Gjør c:geo til standard cache-leser</string>
+ <string name="init_clear">Ikke husk meg</string>
+ <string name="init_cleared">c:geo fjernet innloggings-opplysningene.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Autoriser c:geo</string>
+ <string name="auth_start">Start autorisasjon</string>
+ <string name="auth_again">Prøv igjen</string>
+ <string name="auth_pin_hint">PIN-kode oppgitt av Twitter</string>
+ <string name="auth_finish">Fullfør</string>
+ <string name="auth_dialog_wait">venter på Twitter...</string>
+ <string name="auth_dialog_pin_title">PIN-kode</string>
+ <string name="auth_dialog_pin_message">Vennligst tast inn PIN-koden oppgitt av Twitter. Det er obligatorisk at du fullfører autorisasjonen.</string>
+ <string name="auth_dialog_completed">c:geo kan nå poste på Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Ingen cacher</string>
+ <string name="cache_count_one">Én cache</string>
+ <string name="cache_count_more">Cacher</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Oppdater</string>
+ <string name="cache_offline_drop">Slett</string>
+ <string name="cache_offline_store">Lagre</string>
+ <string name="cache_offline_stored">Lagret på enheten for</string>
+ <string name="cache_offline_not_ready">Kan ikke brukes\noffline (ikke lagret)</string>
+ <string name="cache_offline_time_about"></string>
+ <string name="cache_offline_time_mins">minutter siden</string>
+ <string name="cache_offline_time_mins_few">en liten stund siden</string>
+ <string name="cache_offline_time_hour">én time siden</string>
+ <string name="cache_offline_time_hours">mange timer siden</string>
+ <string name="cache_offline_time_days">mange dager siden</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Attributer</string>
+ <string name="cache_inventory">Inventar</string>
+ <string name="cache_log_offline">Offline logg</string>
+ <string name="cache_description">Beskrivelse</string>
+ <string name="cache_description_long">Full beskrivelse</string>
+ <string name="cache_waypoints">Veipunkter</string>
+ <string name="cache_waypoints_add">Legg til veipunkter</string>
+ <string name="cache_hint">Hint</string>
+ <string name="cache_logs">Loggbok</string>
+ <string name="cache_dialog_loading_details">Laster cachens detaljer...</string>
+ <string name="cache_dialog_loading_description">Laster cachens fulle beskrivelse...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Lagrer cachen for offline-bruk...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Sletter cachen fra enheten...</string>
+ <string name="cache_dialog_refresh_title">Oppdater</string>
+ <string name="cache_dialog_refresh_message">Laster cachens detaljer på nytt...</string>
+ <string name="cache_menu_navigate">Navigér</string>
+ <string name="cache_menu_compass">Kompass</string>
+ <string name="cache_menu_tbt">Punktvis navigasjon</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Vis på kartet</string>
+ <string name="cache_menu_map_ext">Vis på utvidet kart</string>
+ <string name="cache_menu_map_static">Statisk kart</string>
+ <string name="cache_menu_browser">Åpne med web-leseren</string>
+ <string name="cache_menu_visit">Logg funn</string>
+ <string name="cache_menu_spoilers">Bilder</string>
+ <string name="cache_menu_around">Cacher i nærheten</string>
+ <string name="cache_menu_event">Eksporter til kalender</string>
+ <string name="cache_menu_details">Detaljer</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Logg lagret</string>
+ <string name="cache_status_found">Funnet</string>
+ <string name="cache_status_archived">Arkivert</string>
+ <string name="cache_status_disabled">Deaktivert</string>
+ <string name="cache_status_premium">Kun for premium-medlemmer</string>
+ <string name="cache_geocode">GC-kode</string>
+ <string name="cache_name">Navn</string>
+ <string name="cache_type">Type</string>
+ <string name="cache_distance">Avstand</string>
+ <string name="cache_difficulty">Vanskelighet</string>
+ <string name="cache_terrain">Terreng</string>
+ <string name="cache_rating">Rangering</string>
+ <string name="cache_owner">Eier</string>
+ <string name="cache_hidden">Publisert</string>
+ <string name="cache_event">Dato</string>
+ <string name="cache_location">Lokasjon</string>
+ <string name="cache_coordinates">Koordinater</string>
+ <string name="cache_calendars">Velg kalender</string>
+ <string name="cache_gpx_import">Importer GPX-fil</string>
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Søker etter *.GPX-filer</string>
+ <string name="gpx_import_loading_stored">Laster cacher fra *.GPX-filer\nlagret:</string>
+ <string name="gpx_import_no_files">Beklager, c:geo fant ingen *.GPX-filer.</string>
+ <string name="gpx_import_caches_imported">Cacher importert</string>
+ <string name="gpx_import_searching">Søker etter *.GPX-filer</string>
+ <string name="gpx_import_loading">Laster cacher fra .*.GPX-fil</string>
+ <string name="gpx_import_title">Importer GPX</string>
+ <string name="gpx_import_title_reading_file">Leser fil</string>
+ <string name="gpx_import_title_searching">Søker</string>
+ <string name="gpx_import_title_caches_imported">Resultat</string>
+
+ <!-- event -->
+ <string name="event_success">Hendelse-cache lagt til i kalenderen</string>
+ <string name="event_fail">c:geo klarte ikke å legge hendelse-cachen til i kalenderen</string>
+
+ <!-- popup -->
+ <string name="popup_more">Mer detaljer</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_custom">Eget veipunkt</string>
+ <string name="waypoint_my_coordinates">Mine koordinater</string>
+ <string name="waypoint_bearing">Peiling</string>
+ <string name="waypoint_distance">Distanse</string>
+ <string name="waypoint_name">Navn</string>
+ <string name="waypoint_edit">Rediger</string>
+ <string name="waypoint_delete">Slett</string>
+ <string name="waypoint_edit_title">Rediger veipunkt</string>
+ <string name="waypoint_add_title">Add waypoint</string>
+ <string name="waypoint_note">Note</string>
+ <string name="waypoint_save">Save</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Del dette funnet på Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Kart</string>
+ <string name="map_live">Live kart</string>
+ <string name="map_view_satellite">Satelitt-kart</string>
+ <string name="map_view_map">Vanlig kart</string>
+ <string name="map_trail_show">Vis spor</string>
+ <string name="map_trail_hide">Skjul spor</string>
+ <string name="map_live_enable">Aktiver live</string>
+ <string name="map_live_disable">Deaktiver live</string>
+
+ <!-- search -->
+ <string name="search_coordinates">Koordinater</string>
+ <string name="search_coordinates_button">Søk med koordinater</string>
+ <string name="search_address">Adresse</string>
+ <string name="search_address_button">Søk med adresse</string>
+ <string name="search_gc">Geokode</string>
+ <string name="search_gc_button">Søk med geokode</string>
+ <string name="search_kw">Nøkklord</string>
+ <string name="search_kw_prefill">Nøkkelord</string>
+ <string name="search_kw_button">Søk med nøkkelord</string>
+ <string name="search_kw_caches">Cacher med nøkkelord</string>
+ <string name="search_caches_found_by">Cacher funnet av</string>
+ <string name="search_caches_hidden_by">Cacher gjemt av</string>
+ <string name="search_fbu">Funnet av bruker</string>
+ <string name="search_fbu_prefill">Brukernavn</string>
+ <string name="search_fbu_button">Søk med brukernavn</string>
+ <string name="search_hbu">Gjemt av brukere</string>
+ <string name="search_hbu_prefill">Eier</string>
+ <string name="search_hbu_button">Søk med</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">Trackable-identifisering</string>
+ <string name="search_tb_button">Søk etter trackable</string>
+ <string name="search_destination">Lokaliser ved hjelp av koordinater</string>
+ <string name="search_direction_rel">Fra denne plassen</string>
+ <string name="search_lat">Peiling</string>
+ <string name="search_lon">Lengdegrad</string>
+ <string name="search_caches">Søk etter cacher</string>
+ <string name="search_caches_near">Cacher i nærheten</string>
+ <string name="search_address_started">Søker etter steder</string>
+ <string name="search_address_result">Fant plasser</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_details_loading">Laster trackable\'ens detaljer</string>
+ <string name="trackable_log_touch">Log touch</string>
+ <string name="trackable_browser_open">Åpne i web-leser</string>
+ <string name="trackable_goal">Mål</string>
+ <string name="trackable_details">Detailjer</string>
+ <string name="trackable_image">Bilder</string>
+ <string name="trackable_code">TB-kode</string>
+ <string name="trackable_name">Navn</string>
+ <string name="trackable_type">Type</string>
+ <string name="trackable_owner">Eier</string>
+ <string name="trackable_spotted">Oppdaget</string>
+ <string name="trackable_origin">Start</string>
+ <string name="trackable_unknown">Ukjent</string>
+ <string name="trackable_released">Sluppet</string>
+ <string name="trackable_touch">Touch</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigasjon</string>
+ <string name="compass_title">Kompass</string>
+ <string name="use_gps">Bruk GPS</string>
+ <string name="use_compass">Bruk kompass</string>
+ <string name="destination_select">Velg destinasjon</string>
+ <string name="destination_set">Sett destinasjon</string>
+
+ <!-- license -->
+ <string name="license">Lisens</string>
+ <string name="license_show">Vis lisens</string>
+ <string name="license_dismiss">Dismiss</string>
+
+ <!-- next things -->
+ <string name="legal_note">For å bruke tjenestene til geocaching.com, må brukeren samtykke i vilkårene og betingelsene til <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeak\'s ansvarsfraskrivelse</a></string>
+ <string name="author">utvikler: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">e-post adresse: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">web-side: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</a></string>
+ <string name="facebook">facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo page</a></string>
+ <string name="about_go4cache">Tjenesten <b>Go 4 cache</b> gjør det mulig for deg å se andre geocachere på kartet (i <b>c:geo</b> eller i web-leseren). Det kan for eksempel vise hvilken cache de er ute etter. Ved å koble til <b>Go 4 cache</b> får <b>c:geo</b> din tillatelse til oppgi dine koordinater til andre brukere av <b>Go 4 cache</b>, men bare mens <b>c:geo</b> kjører.</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="about_auth_1">Den følgende prosessen tillater <b>c:geo</b> tilgang til Twitter - hvis bruker samtykker.</string>
+ <string name="about_auth_2">Trykk på \"Start autorisasjon\" knappen for å starte prosessen. Denne prosessen vil åpne Twitter i web-leseren. Logg inn, og tillat <b>c:geo</b> tilgang til kontoen din. Hvis du aksepterer, vil Twitter oppgi en numerisk PIN-kode. Denne PIN-koden må så limes inn i <b>c:geo</b>. Verre er det ikke.</string>
+
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
new file mode 100644
index 0000000..6ae51dd
--- /dev/null
+++ b/res/values-nl/strings.xml
@@ -0,0 +1,502 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo compass</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detail</string>
+ <string name="search">Zoeken</string>
+ <string name="settings">Instellingen</string>
+ <string name="about">Over c:geo</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Deel link naar cache</string>
+
+ <!-- caches -->
+ <string name="all">Alle caches</string>
+ <string name="all_types">Alle cache types</string>
+ <string name="traditional">Traditionele cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Onbekende cache</string>
+ <string name="letterbox">Letterbox hybrid</string>
+ <string name="event">Event cache</string>
+ <string name="mega">Mega-event cache</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">Cache in trash out event</string>
+ <string name="webcam">Webcam cache</string>
+ <string name="virtual">Virtuele cache</string>
+ <string name="wherigo">Wherigo cache</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Project ape cache</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">Gps cache exhibit</string>
+
+ <!-- waypoints -->
+ <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_pkg">Parkeer gelegenheid</string>
+ <string name="wp_trailhead">Trailhead</string>
+ <string name="wp_waypoint">Referentie punt</string>
+
+ <!-- logs -->
+ <string name="log_found">Gevonden</string>
+ <string name="log_dnf">Niet gevonden</string>
+ <string name="log_note">Notitie</string>
+ <string name="log_published">Gepubliceerd</string>
+ <string name="log_enabled">Ingeschakeld</string>
+ <string name="log_disabled">Uitgeschakeld</string>
+ <string name="log_attend">Zal aanwezig zijn</string>
+ <string name="log_attended">Was aanwezig</string>
+ <string name="log_retrieved">Teruggevonden</string>
+ <string name="log_grabbed">Gepakt</string>
+ <string name="log_maintained">Onderhoud uitgevoerd</string>
+ <string name="log_maintenance_needed">Onderhoud nodig</string>
+ <string name="log_maintenance_owner">Onderhoud</string>
+ <string name="log_update">Bijgewerkte coördinaten</string>
+ <string name="log_archived">Gearchiveerd</string>
+ <string name="log_needs_archived">Dient te worden gearchiveerd</string>
+ <string name="log_discovered">Ontdekt</string>
+ <string name="log_reviewed">Recensent notitie</string>
+ <string name="log_tb_nothing">Niets doen</string>
+ <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_saving">Log opslaan...</string>
+ <string name="log_clear">Wissen</string>
+ <string name="log_post">Post log</string>
+ <string name="log_post_rate">Post log &amp; beoordeel</string>
+ <string name="log_post_no_rate">Post log zonder beoordeling</string>
+ <string name="log_add">Toevoegen</string>
+ <string name="log_date">Datum</string>
+ <string name="log_time">Tijd</string>
+ <string name="log_date_time">Datum &amp; tijd</string>
+ <string name="log_rating">Beoordeling</string>
+ <string name="log_no_rating">Geen beoordeling</string>
+ <string name="log_stars_1">1 sterren</string>
+ <string name="log_stars_2">2 sterren</string>
+ <string name="log_stars_3">3 sterren</string>
+ <string name="log_stars_4">4 sterren</string>
+ <string name="log_stars_5">5 sterren</string>
+ <string name="log_webcam">Webcam foto gemaakt</string>
+ <string name="log_new_log">Log</string>
+ <string name="log_new_log_text">Log tekst</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Communicatie niet gestart</string>
+ <string name="err_parse">Login pagina verwerken mislukt</string>
+ <string name="err_server">Verbinding met geocaching.com mislukt (geen verbinding of server niet bereikbaar)</string>
+ <string name="err_login">Geen login informatie opgeslagen</string>
+ <string name="err_login_failed">Sorry, c:geo kan niet inloggen.</string>
+ <string name="err_unknown">Onbekende fout</string>
+ <string name="err_comm">Onbekende communicatie fout</string>
+ <string name="err_missing_auth">Geen gebruikersnaam en/of wachtwoord ingesteld.</string>
+ <string name="err_wrong">Foutieve login informatie</string>
+ <string name="err_license">Gebruiker heeft de gebruikersvoorwaarden van Geocaching.com niet geaccepteerd</string>
+ <string name="err_store">Sorry, c:geo kan de cache niet opslaan.</string>
+ <string name="err_drop">Sorry, c:geo kan de cache niet wissen.</string>
+ <string name="err_title_problem">Probleem</string>
+ <string name="err_detail_open">Sorry, c:geo kan de geocache details niet openen.</string>
+ <string name="err_detail_cache">Sorry, c:geo kan de gezochte geocache niet weergeven.</string>
+ <string name="err_detail_cache_find">Sorry, c:geo kan de geocache niet vinden.</string>
+ <string name="err_detail_cache_find_some">Sorry, c:geo kan die geocache niet vinden.</string>
+ <string name="err_detail_cache_find_any">Sorry, c:geo can\'t find any geocache.</string>
+ <string name="err_detail_cache_find_next">Sorry, c:geo can\'t find next geocaches.</string>
+ <string name="err_detail_cache_forgot">Sorry, c:geo is kwijt welke geocache je wilde openen.</string>
+ <string name="err_detail_cache_forgot_visit">Sorry, c:geo forgot which cache you visited.</string>
+ <string name="err_detail_cache_language">c:geo Kan sommige cache details niet lezen. Controleer of de geocaching.com website is ingesteld op English. Helaas ondersteund c:geo geen localisaties.</string>
+ <string name="err_detail_no_spoiler">c:geo Heeft geen spoiler images gevonden voor deze cache.</string>
+ <string name="err_detail_no_map_static">c:geo Heeft geen statische kaarten gevonden voor deze cache.</string>
+ <string name="err_detail_still_removing">Bezig met wissen van deze cache.</string>
+ <string name="err_detail_still_saving">Bezig met opslaan van deze cache.</string>
+ <string name="err_detail_still_refreshing">Bezig met opnieuw laden van deze cache.</string>
+ <string name="err_radar_title">Radar is niet geinstalleerd.</string>
+ <string name="err_radar_message">Deze functie heeft de Radar applicatie nodig. Deze nu installeren?</string>
+ <string name="err_radar_market">c:geo Kan Android Market niet starten om te zoeken naar de Radar applicatie.</string>
+ <string name="err_radar_generic">Sorry, c:geo kan de Radar applicatie niet starten. Is deze geinstalleerd?</string>
+ <string name="err_navigation_no">c:geo Kan geen ondersteunde navigatie applicatie vinden.</string>
+ <string name="err_application_no">c:geo Kan geen geschikte applicatie vinden.</string>
+ <string name="err_auth_initialize">Sorry, het is c:geo niet gelukt het autorisatie proces te initialiseren.</string>
+ <string name="err_auth_process">Autorisatie proces mislukt.</string>
+ <string name="err_cannot_log_visit">c:geo Heeft onvoldoende informatie om bezoek te loggen. Probeer het vanuit de volledige cache details.</string>
+ <string name="err_init_cleared">Sorry, c:geo kan de login informatie niet wissen.</string>
+ <string name="err_no_chaches">Sorry, c:geo heeft cache(s) niet kunnen laden.</string>
+ <string name="err_download_fail">Sorry, c:geo heeft caches niet kunnen downloaden omdat </string>
+ <string name="err_update_fail">Bijwerken afgelegde afstand mislukt.</string>
+ <string name="err_list_load_fail">Sorry, c:geo heeft cache lijst niet kunnen laden.</string>
+ <string name="err_store_failed">Sorry, c:geo kan de geocache niet opslaan.</string>
+ <string name="err_refresh_failed">Sorry, c:geo kan de geocache niet verversen.</string>
+ <string name="err_drop_failed">Sorry, c:geo kan de geocache niet wissen.</string>
+ <string name="err_dwld_details_failed">Sorry, c:geo kon de cache details niet downloaden.</string>
+ <string name="err_dwld_details_failed_reason">Sorry, c:geo kon de cache details niet downloaden omdat</string>
+ <string name="err_load_descr_failed">Sorry, c:geo kan de omschrijving niet laden.</string>
+ <string name="err_location_unknown">c:geo kent de locatie van de cache niet.</string>
+
+ <string name="err_tb_display">"Sorry, c:geo kan de gezochte trackable niet weergeven. Is het echt een trackable?</string>
+ <string name="err_tb_details_open">Sorry, c:geo kan de trackable details niet laden.</string>
+ <string name="err_tb_details_download">Sorry, c:geo kon de trackable details niet downloaden omdat</string>
+ <string name="err_tb_forgot">Sorry, c:geo is vergeten welke trackable je wilde.</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>
+ <string name="err_waypoint_unknown">Sorry, c:geo is vergeten welke waypoint je wil laten zien.</string>
+ <string name="err_waypoint_add_failed">Sorry, c:geo kon de waypoint niet toevoegen.</string>
+ <string name="err_waypoint_load_failed">Sorry, c:geo kon de waypoint niet laden.</string>
+ <string name="err_waypoint_delete_failed">Sorry, c:geo kan de waypoint niet wissen.</string>
+ <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_point_location_error">Sorry, c:geo kan locatie van de waypoint niet ophalen.</string>
+ <string name="err_navigation_not_found">c:geo kan geen ondersteunde navigatie vinden.</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_failed_server">Sorry, c:geo kon bezoek niet loggen omdat de server niet reageert.</string>
+ <string name="err_log_post_failed">Sorry, het is c:geo niet gelukt het log te posten.</string>
+ <string name="err_log_post_failed_because">Sorry, c:geo kon log niet posten omdat </string>
+
+ <string name="err_search_address_no_match">Sorry, c:geo heeft geen gelijkende plaats gevonden.</string>
+ <string name="err_search_address_forgot">Sorry, c:geo is het adres dat je zoekt vergeten.</string>
+ <string name="err_search_address">Zoeken naar plaatsen</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>
+ <string name="err_parse_bear">Sorry, c:geo kan richting niet verwerken.</string>
+ <string name="err_parse_dist">Sorry, c:geo kan afstand niet verwerken.</string>
+
+ <string name="warn_save_nothing">Er is niets op te slaan.</string>
+ <string name="warn_no_cache_coord">Er is geen cache met deze coördinaten.</string>
+ <string name="warn_no_coordinates">Geen coördinaten opgegeven.</string>
+ <string name="warn_no_keyword">Geen sleutelwoord opgegeven.</string>
+ <string name="warn_no_username">Geem gebruikersnaam opgegeven.</string>
+ <string name="warn_search_help_title">Hulp nodig?</string>
+ <string name="warn_search_help_address">"Vul adres of locatienaam. Gebruik bijvoorbeeld adres \"Hoofdstraat 100, Amsterdam, Nederland\", plaatsnaam \"Utrecht\" of een naam \"Nationaal Park de Hoge Veluwe\".</string>
+ <string name="warn_search_help_gccode">Voer de cachecode in. Bijvoorbeeld \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Voer een woord in dat een deel is van de cache naam die je zoekt.</string>
+ <string name="warn_search_help_user">Voer een gebruikersnaam in van een Geocaching.com gebruiker.</string>
+ <string name="warn_search_help_tb">Voer de trackable code in. Bijvoorbeeld \"TB29QMZ\".</string>
+
+ <string name="warn_log_text_fill">Voer s.v.p. een logtekst in.</string>
+
+ <string name="info_altitude">Huidige hoogte</string>
+ <string name="info_distance">Afgelegde afstand</string>
+ <string name="info_distance_cleared">Afgelegde afstand is gewist.</string>
+ <string name="info_since">\n(sinds </string>
+
+ <string name="info_log_posted">c:geo heeft log succesvol gepost.</string>
+ <string name="info_log_saved">c:geo heeft log succesvol opgeslagen.</string>
+ <string name="info_log_cleared">Log is gewist.</string>
+ <string name="info_log_type_changed">Type log is gewijzigd!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Laatst bekende</string>
+ <string name="loc_net">Netwerk</string>
+ <string name="loc_gps">Gps</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Proberen te lokaliseren</string>
+ <string name="loc_no_addr">Adres onbekend</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Over c:geo</string>
+ <string name="menu_settings">Instellingen</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live map</string>
+ <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="about_button">Over</string>
+ <string name="settings_button">Instellingen</string>
+ <string name="type">Type</string>
+ <string name="now_searching">Bezig met zoeken</string>
+
+ <!-- caches -->
+ <string name="caches_no_cache">Geen cache</string>
+ <string name="caches_more_caches">Meer caches</string>
+ <string name="caches_more_caches_no">Einde cachelijst</string>
+ <string name="caches_downloading">Caches aan het downloaden...\nETE: </string>
+ <string name="caches_progress_loading_title">Caches laden</string>
+ <string name="caches_progress_loading_text">Opgeslagen caches in apparaat</string>
+ <string name="caches_eta_ltm">Minder dan een minuut</string>
+ <string name="caches_eta_mins"> minuten</string>
+ <string name="caches_eta_min"> minuut</string>
+ <string name="caches_no_caches"> (geen caches)</string>
+ <string name="caches_store_offline">Opslaan voor Offline gebruik</string>
+ <string name="caches_store_selected">Geselecteerden opslaan</string>
+ <string name="caches_stored">Opgeslagen</string>
+ <string name="caches_on_map">Toon op kaart</string>
+ <string name="caches_select">Selecteer uit lijst</string>
+ <string name="caches_select_mode">Selectie modus</string>
+ <string name="caches_select_mode_exit">Selectie modus beïndigen</string>
+ <string name="caches_nearby">Nabij</string>
+ <string name="caches_drop_selected">Drop geselecteerde</string>
+ <string name="caches_drop_selected_ask">Wil je de geselecteerde caches verwijderen van het apparaat?</string>
+ <string name="caches_drop_all">Alles droppen</string>
+ <string name="caches_drop_all_ask">Wil je alle caches van het apparaat verwijderen?</string>
+ <string name="caches_drop_stored">Drop opgeslagen</string>
+ <string name="caches_refresh_selected">Ververs geselecteerden</string>
+ <string name="caches_refresh_all">Ververs alles</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+
+ <!-- about -->
+ <string name="about_changelog">Changelog</string>
+ <string name="about_donate">Doneren</string>
+ <string name="about_detail">Details</string>
+ <string name="about_donation_less">Minder doneren</string>
+ <string name="about_donation_more">Doneren aan ontwikkeling</string>
+ <string name="about_contributors">Bijdragers</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Gebruikersnaam</string>
+ <string name="init_password">Wachtwoord</string>
+ <string name="init_passvote">Wachtwoord</string>
+ <string name="init_login">Login controleren</string>
+ <string name="init_login_popup">Inloggen</string>
+ <string name="init_login_popup_working">Inloggen op Geocaching.com...</string>
+ <string name="init_login_popup_ok">Ingelogd.</string>
+ <string name="init_login_popup_failed">Inloggen mislukt.</string>
+ <string name="init_login_popup_failed_reason">Inloggen mislukt omdat </string>
+ <string name="init_legal">Juridische info</string>
+ <string name="init_go4cache_connect">Verbinden met Go 4 Cache</string>
+ <string name="init_twitter_authorize">c:geo Autoriseren</string>
+ <string name="init_twitter_publish">Status publiceren bij gevonden cache</string>
+ <string name="init_signature">Handtekening</string>
+ <string name="init_other">Overige opties</string>
+ <string name="init_skin">Lichte skin (c:geo herstarten)</string>
+ <string name="init_transparent">Transparant c:geo hoofdscherm instellen</string>
+ <string name="init_address">Toon adres op hoofdscherm</string>
+ <string name="init_exclude">Eigen en gevonden caches uitsluiten</string>
+ <string name="init_disabled">Uitgeschakelde caches uitsluiten</string>
+ <string name="init_offline">Kaarten opslaan voor gebruik zonder verbinding</string>
+ <string name="init_units">Gebruik imperiale stelsel voor afstanden</string>
+ <string name="init_nav">Gebruik Google Navigatie</string>
+ <string name="init_autoload">Automatisch lange omschrijving laden</string>
+ <string name="init_livelist">Toon afstand tot cache in lijst</string>
+ <string name="init_browser">c:geo Als standaard browser instellen</string>
+ <string name="init_clear">Login wissen</string>
+ <string name="init_cleared">c:geo Heeft login informatie gewist.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">c:geo Autoriseren</string>
+ <string name="auth_start">Start autorisatie</string>
+ <string name="auth_again">Nogmaals starten</string>
+ <string name="auth_pin_hint">Door Twitter toegekende pin</string>
+ <string name="auth_finish">Afronden</string>
+ <string name="auth_dialog_wait">Wachten op Twitter...</string>
+ <string name="auth_dialog_pin_title">Pin code</string>
+ <string name="auth_dialog_pin_message">Voer de door de Twitter website verstrekte PIN code in. Deze is verplicht om de autorisatie af te ronden.</string>
+ <string name="auth_dialog_completed">c:geo Is nu geauthoriseerd om naar Twitter te posten.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Geen cache</string>
+ <string name="cache_count_one">Een cache</string>
+ <string name="cache_count_more">Caches</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Verversen</string>
+ <string name="cache_offline_drop">Laten vervallen</string>
+ <string name="cache_offline_store">Opslaan</string>
+ <string name="cache_offline_stored">Opgeslagen in apparaat</string>
+ <string name="cache_offline_not_ready">Niet gereed voor\n offline gebruik</string>
+ <string name="cache_offline_time_about">over</string>
+ <string name="cache_offline_time_mins">minuten geleden</string>
+ <string name="cache_offline_time_mins_few">paar minuten geleden</string>
+ <string name="cache_offline_time_hour">een uur geleden</string>
+ <string name="cache_offline_time_hours">uren geleden</string>
+ <string name="cache_offline_time_days">dagen geleden</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Attributen</string>
+ <string name="cache_inventory">Inventaris</string>
+ <string name="cache_log_offline">Offline log</string>
+ <string name="cache_description">Omschrijving</string>
+ <string name="cache_description_long">Lange omschrijving</string>
+ <string name="cache_waypoints">Waypoints</string>
+ <string name="cache_waypoints_add">Waypoint toevoegen</string>
+ <string name="cache_hint">Hint</string>
+ <string name="cache_logs">Logboek</string>
+ <string name="cache_dialog_loading_details">Cache details laden...</string>
+ <string name="cache_dialog_loading_description">Cache omschrijving laden...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Cache opslaan voor offline gebruik...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Cache verwijderen van apparaat geheugen...</string>
+ <string name="cache_dialog_refresh_title">Verversen</string>
+ <string name="cache_dialog_refresh_message">Cache details opnieuw laden...</string>
+ <string name="cache_menu_navigate">Navigeer</string>
+ <string name="cache_menu_compass">Kompas</string>
+ <string name="cache_menu_tbt">Turn-by-turn</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Toon op kaart</string>
+ <string name="cache_menu_map_ext">Toon op ext. kaart</string>
+ <string name="cache_menu_map_static">Statische kaarten</string>
+ <string name="cache_menu_map_short">Kaarten</string>
+ <string name="cache_menu_map_ext_short">Ext. kaart</string>
+ <string name="cache_menu_browser">Open in browser</string>
+ <string name="cache_menu_visit">Log bezoek</string>
+ <string name="cache_menu_spoilers">Spoiler afbeeldingen</string>
+ <string name="cache_menu_around">Caches rondom</string>
+ <string name="cache_menu_event">Toevoegen aan kalender</string>
+ <string name="cache_menu_details">Details</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Log opgeslagen</string>
+ <string name="cache_status_found">Gevonden</string>
+ <string name="cache_status_archived">Gearchiveerd</string>
+ <string name="cache_status_disabled">Uitgeschakeld</string>
+ <string name="cache_status_premium">Alleen voor premium leden</string>
+ <string name="cache_geocode">gc-code</string>
+ <string name="cache_name">Naam</string>
+ <string name="cache_type">Type</string>
+ <string name="cache_distance">Afstand</string>
+ <string name="cache_difficulty">Moeilijkheid</string>
+ <string name="cache_terrain">Terrein</string>
+ <string name="cache_rating">Waardering</string>
+ <string name="cache_owner">Eigenaar</string>
+ <string name="cache_hidden">Verstopt</string>
+ <string name="cache_event">Datum</string>
+ <string name="cache_location">Locatie</string>
+ <string name="cache_coordinates">Coördinaten</string>
+ <string name="cache_calendars">selecteer kalender</string>
+ <string name="cache_spoiler_images_title">Spoiler afbeeldingen</string>
+ <string name="cache_spoiler_images_loading">Spoiler afbeeldingen laden...</string>
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Zoeken naar .gpx bestanden\nin</string>
+ <string name="gpx_import_loading_stored">Caches laden van .gpx bestand\nstored:</string>
+ <string name="gpx_import_no_files">Sorry, c:geo heeft geen .gpx bestanden gevonden.</string>
+ <string name="gpx_import_caches_imported">Caches geïmporteerd</string>
+ <string name="gpx_import_searching">Zoeken naar .gpx bestanden</string>
+ <string name="gpx_import_loading">Caches laden uit .gpx bestand</string>
+ <string name="gpx_import_title">Importeer GPX</string>
+ <string name="gpx_import_title_reading_file">Bestand aan het lezen</string>
+ <string name="gpx_import_title_searching">Bezig met zoeken</string>
+ <string name="gpx_import_title_caches_imported">Resultaat</string>
+
+
+ <!-- event -->
+ <string name="event_success">Event cache toegevoegd aan kalender</string>
+ <string name="event_fail">Niet gelukt om event cache toe te voegen aan kalender</string>
+
+ <!-- popup -->
+ <string name="popup_more">Meer details</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Waypoint</string>
+ <string name="waypoint_custom">Aangepast</string>
+ <string name="waypoint_my_coordinates">Mijn coordinaten</string>
+ <string name="waypoint_bearing">Richting</string>
+ <string name="waypoint_distance">Afstand</string>
+ <string name="waypoint_name">Naam</string>
+ <string name="waypoint_edit">Bewerken</string>
+ <string name="waypoint_delete">Verwijderen</string>
+ <string name="waypoint_edit_title">Waypoint bewerken</string>
+ <string name="waypoint_add_title">Waypoint toevoegen</string>
+ <string name="waypoint_note">Notitie</string>
+ <string name="waypoint_save">Opslaan</string>
+ <string name="waypoint_loading">Waypoint laden...</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Post deze vondst naar Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Kaart</string>
+ <string name="map_live">Live kaart</string>
+ <string name="map_view_satellite">Satelliet weergave</string>
+ <string name="map_view_map">Kaart weergave</string>
+ <string name="map_trail_show">Toon spoor</string>
+ <string name="map_trail_hide">Verberg spoor</string>
+ <string name="map_live_enable">Live aanzetten</string>
+ <string name="map_live_disable">Live uitzetten</string>
+ <string name="map_static_title">Statische kaarten</string>
+ <string name="map_static_loading">Statische kaarten laden...</string>
+
+ <!-- search -->
+ <string name="search_coordinates">Coördinaten</string>
+ <string name="search_coordinates_button">Zoeken op coördinaten</string>
+ <string name="search_address">Adres</string>
+ <string name="search_address_button">Zoeken op adres</string>
+ <string name="search_gc">Geocode</string>
+ <string name="search_gc_button">Zoeken op geocode</string>
+ <string name="search_kw">Trefwoorden</string>
+ <string name="search_kw_prefill">Trefwoord</string>
+ <string name="search_kw_button">Zoeken op trefwoord</string>
+ <string name="search_kw_caches">Caches op trefwoord</string>
+ <string name="search_caches_found_by">Caches gevonden door</string>
+ <string name="search_caches_hidden_by">Caches verstopt door</string>
+ <string name="search_fbu">Gevonden door gebruiker</string>
+ <string name="search_fbu_prefill">Gebruikersnaam</string>
+ <string name="search_fbu_button">Zoeken op gebruikersnaam</string>
+ <string name="search_hbu">Verstopt door gebruikers</string>
+ <string name="search_hbu_prefill">Eigenaar</string>
+ <string name="search_hbu_button">Zoeken op eigenaar</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">Trackable identificatie</string>
+ <string name="search_tb_button">Zoeken naar trackable</string>
+ <string name="search_destination">Bestemming</string>
+ <string name="search_direction_rel">Vanaf deze positie</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Zoeken naar caches</string>
+ <string name="search_caches_near">Caches nabij</string>
+ <string name="search_address_started">Zoeken naar plaatsen</string>
+ <string name="search_address_result">Gevonden plaatsen</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">Bezig met laden van trackable details...</string>
+ <string name="trackable_log_touch">Log aanraking</string>
+ <string name="trackable_browser_open">Openen in Browser</string>
+ <string name="trackable_goal">Doel</string>
+ <string name="trackable_details">Details</string>
+ <string name="trackable_image">Afbeelding</string>
+ <string name="trackable_code">TB-Code</string>
+ <string name="trackable_name">Naam</string>
+ <string name="trackable_type">Type</string>
+ <string name="trackable_owner">Eigenaar</string>
+ <string name="trackable_spotted">Gespot</string>
+ <string name="trackable_origin">Oorsprong</string>
+ <string name="trackable_unknown">Onbekend</string>
+ <string name="trackable_released">Uitgebracht</string>
+ <string name="trackable_touch">Aanraking</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigatie</string>
+ <string name="compass_title">Kompas</string>
+ <string name="use_gps">Gebruik GPS</string>
+ <string name="use_compass">Gebruik kompas</string>
+ <string name="destination_select">Selecteer bestemming</string>
+ <string name="destination_set">Zet bestemming</string>
+
+ <!-- license -->
+ <string name="license">Licentie</string>
+ <string name="license_show">Toon licentie</string>
+ <string name="license_dismiss">Afwijzen</string>
+
+ <!-- next things -->
+ <string name="legal_note">Voor het gebruik van de diensten van geocaching.com, dient akkoord te worden gegaan met de <a href="http://www.geocaching.com/about/disclaimer.aspx">Groundspeak voorwaarden</a>.</string>
+ <string name="author">auteur: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">website: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="about_go4cache">Service <b>Go 4 cache</b> toont andere geocachers op de kaart (in <b>c:geo</b> of in browser) in real time. Het toont bijvoorbeeld welke cache ze zoeken. Door te verbinden met <b>Go 4 cache</b> is <b>c:geo</b> toegestaan om je huidige locatie te publiceren (alleen tijdens het gebruik van <b>c:geo</b>).</string>
+ <string name="about_twitter">Moet <b>c:geo</b> elke cache vondst publiceren naar Twitter?</string>
+ <string name="about_auth_1">Het volgende proces staat <b>c:geo</b> toe om Twitter toegang te verkrijgen bij goedkeuring.</string>
+ <string name="about_auth_2">Klik op de \"autoriseer c:geo\" knop om het proces te starten. Dit proces zal een browser openen met een Twitter pagina. Login op deze pagina en sta <b>c:geo</b> toegang tot je account toe. Bij goedkeuring laat Twitter een numerieke PIN code zien. Deze PIN dien je te plakken en te bevestigen in <b>c:geo</b>.</string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
new file mode 100644
index 0000000..bc7099b
--- /dev/null
+++ b/res/values-pl/strings.xml
@@ -0,0 +1,598 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompas</string>
+
+ <!-- basics -->
+ <string name="cache">Skrzynka</string>
+ <string name="detail">Szczegóły</string>
+ <string name="search">Szukaj</string>
+ <string name="settings">Ustawienia</string>
+ <string name="helpers">Przydatne aplikacje</string>
+ <string name="about">O c:geo</string>
+ <string name="helper">Chcesz dowiedzieć się więcej o <b>c:geo</b>?\nZajrzyj do instrukcji opsługi programu.</string>
+ <string name="database_error_title">Problem z bazą danych</string>
+ <string name="database_error_message">c:geo nie może połączyć się z wewnętrzną bazą danych.\nProszę spróbować uruchomić c:geo nieco później. Jeżeli ten błąd pokazał się wielokrotnie, usuń dane w Ustawienia / Aplikacje / Zarządzaj aplikacjami / c:geo i naciśnij przycisk Wyczyść dane albo zainstaluj c:geo ponownie. Przepraszam za kłopoty.</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Podziel się linkiem do skrzynki</string>
+
+ <!-- caches -->
+ <string name="all">Wszystkie skrzynki</string>
+ <string name="all_types">Wszystkie typy skrzynek</string>
+ <string name="traditional">Skrzynki tradycyjne</string>
+ <string name="multi">Skrzynki wieloetapowe</string>
+ <string name="mystery">Skrzynki zagadkowe</string>
+ <string name="letterbox">Hybrydowe Letterbox</string>
+ <string name="event">Typu wydarzenie</string>
+ <string name="mega">Mega-Wydarzenie</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">CITO</string>
+ <string name="webcam">Skrzynki webcam</string>
+ <string name="virtual">Skrzynki wirtualne</string>
+ <string name="wherigo">Scenariusze Wherigo</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Projekt ape cache</string>
+ <string name="gchq">Groundspeak HQ</string>
+ <string name="gps">GPS cache exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Finał</string>
+ <string name="wp_stage">Etap do skrzynki</string>
+ <string name="wp_puzzle">Pytanie do odpowiedzi</string>
+ <string name="wp_pkg">Parking</string>
+ <string name="wp_trailhead">Punkt wyjścia</string>
+ <string name="wp_waypoint">Punkt nawigacji</string>
+
+ <!-- logs -->
+ <string name="log_found">Znalezione</string>
+ <string name="log_dnf">Nie znalezione</string>
+ <string name="log_note">Notatka</string>
+ <string name="log_published">Opublikowano</string>
+ <string name="log_enabled">Aktywny</string>
+ <string name="log_disabled">Nieaktywny</string>
+ <string name="log_attend">Będę uczestniczyć</string>
+ <string name="log_attended">Uczestniczyłem</string>
+ <string name="log_retrieved">Zabrałem</string>
+ <string name="log_placed">Umieściłem</string>
+ <string name="log_grabbed">Znalazłem gdzieś indziej</string>
+ <string name="log_maintained">Przegląd przeprowadzony</string>
+ <string name="log_maintenance_needed">Przegląd potrzebny</string>
+ <string name="log_maintenance_owner">Przegląd</string>
+ <string name="log_update">Zmienione współrzędne</string>
+ <string name="log_archived">Zarchiwizowane</string>
+ <string name="log_needs_archived">Powinno zostać zarchiwizowane</string>
+ <string name="log_discovered">Odkryty</string>
+ <string name="log_reviewed">Sprawdzony</string>
+ <string name="log_taken">Skrytka odwiedzona</string>
+ <string name="log_tb_nothing">Nie rób nic</string>
+ <string name="log_tb_visit">Odwiedzić</string>
+ <string name="log_tb_drop">Odłożyć</string>
+ <string name="log_tb_changeall">Wszystkie zmienić</string>
+ <string name="log_save">Zapisz</string>
+ <string name="log_saving">Wpis w dzienniku...</string>
+ <string name="log_clear">Oczyść</string>
+ <string name="log_post">Wpisz do dziennika</string>
+ <string name="log_post_rate">Wpisz do dziennika &amp; oceń</string>
+ <string name="log_post_no_rate">Wpisz do dziennika &amp; nie oceniaj</string>
+ <string name="log_add">Dodaj</string>
+ <string name="log_date">Data</string>
+ <string name="log_time">Godzina</string>
+ <string name="log_date_time">Data &amp; godzina</string>
+ <string name="log_rating">Ocena</string>
+ <string name="log_no_rating">Bez oceny</string>
+ <string name="log_stars_1">1 gwiazdka</string>
+ <string name="log_stars_2">2 gwiazdki</string>
+ <string name="log_stars_3">3 gwiazdki</string>
+ <string name="log_stars_4">4 gwiazdki</string>
+ <string name="log_stars_5">5 gwiazdki</string>
+ <string name="log_webcam">Zdjęcie Webcam zrobione</string>
+ <string name="log_new_log">Dodaj wpis</string>
+ <string name="log_new_log_text">Komentarz</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">OK</string>
+ <string name="err_start">Komunikacja nie wystartowana</string>
+ <string name="err_parse">Nieudana analiza strony logowania.</string>
+ <string name="err_server">Nieudane połączenie z geocaching.com (server albo połączenie nieaktywne?)</string>
+ <string name="err_login">Brakuje danych do logowania.</string>
+ <string name="err_login_failed">Przepraszam, c:geo nie może się zalogować.</string>
+ <string name="err_unknown">Nieznany błąd</string>
+ <string name="err_comm">Nieznany błąd w komunikacji</string>
+ <string name="err_missing_auth">Nie wpisana nazwa użytkownika i/lób hasła.</string>
+ <string name="err_wrong">Niepoprawne dane użytkownika</string>
+ <string name="err_license">Użytkownik nie zgodził się jeszcze z regulaminem serwisu Geocaching.com, c:geo nie jest w stanie załadować współrzędnych.</string>
+ <string name="err_store">Przepraszam, c:geo nie mógł zapisać skrzynki.</string>
+ <string name="err_drop">Przepraszam, c:geo nie mógł skasować skrzynki.</string>
+ <string name="err_title_problem">Problem</string>
+ <string name="err_detail_open">Przepraszam, c:geo nie mógł otworzyć szczegółów skrzynki.</string>
+ <string name="err_detail_cache">Przepraszam, c:geo nie mógł pokazać tobie skrzynki. Czy to jest naprawdę skrzynka?</string>
+ <string name="err_detail_cache_find">Przepraszam, c:geo nie mógł znaleść skrzynki.</string>
+ <string name="err_detail_cache_find_some">Przepraszam, c:geo nie mógł znaleść tej skrzynki.</string>
+ <string name="err_detail_cache_find_any">Przepraszam, c:geo nie mógł znaleść żadnej skrzynki.</string>
+ <string name="err_detail_cache_find_next">Przepraszam, c:geo nie mógł znaleść następnej skrzynki.</string>
+ <string name="err_detail_cache_forgot">Przepraszam, c:geo zapomniał którą skrzynkę chciałeś obejrzeć.</string>
+ <string name="err_detail_cache_forgot_visit">Przepraszam, c:geo zapomniał którą skrzynkę chciałeś odwiedzić.</string>
+ <string name="err_detail_cache_language">c:geo nie mógł wczytać niektórych szczegółów. Proszę ustaw stronę geocaching.com na język angielski. Niestety, c:geo nie rozumie innych języków.</string>
+ <string name="err_detail_no_spoiler">c:geo nie znalazł zdjęcia spoilera dla tej skrzynki.</string>
+ <string name="err_detail_no_map_static">c:geo nie znalazł mapki statycznej dla tej skrzynki.</string>
+ <string name="err_detail_not_load_map_static">Przepraszam, c:geo nie mógł załadować statycznej mapki.</string>
+ <string name="err_detail_still_removing">Kasuje nadal skrzynkę.</string>
+ <string name="err_detail_still_saving">Zapisuje nadal skrzynkę.</string>
+ <string name="err_detail_still_refreshing">Nadal ładuje skrzynkę.</string>
+ <string name="err_radar_title">Radar nie jest zainstalowany.</string>
+ <string name="err_radar_message">Ta funkcja potrzebuje aplikacje Radar. Chcesz ją teraz zainstalować?</string>
+ <string name="err_radar_market">c:geo nie mógł wystartować Android Market aby poszukać aplikacje Radar.</string>
+ <string name="err_radar_generic">Przepraszam, c:geo nie mógł wystartować aplikacje Radar. Jest ona zainstalowana?</string>
+ <string name="err_navigation_no">c:geo nie znalazł żadnych wsparć do nawigacji.</string>
+ <string name="err_application_no">c:geo nie znalazł żadnych odpowiednich aplikacji.</string>
+ <string name="err_auth_initialize">Przepraszam, c:geo nie może zainicjować procesu autoryzacji.</string>
+ <string name="err_auth_process">Proces autoryzacji nie udany.</string>
+ <string name="err_cannot_log_visit">c:geo brakuje informacji aby dodać wpis wizyty. Proszę spróbuj przez szczegóły skrzynki.</string>
+ <string name="err_init_cleared">Przepraszam, c:geo nie może skasować danych logowania.</string>
+ <string name="err_no_chaches">Przepraszam, c:geo nie może załadować skrzynki lób skrzynek.</string>
+ <string name="err_download_fail">Przepraszam, c:geo nie może załadować skrzynki, ponieważ </string>
+ <string name="err_update_fail">Nie udało się zaktualizować przebytej odległości.</string>
+ <string name="err_list_load_fail">Przepraszam, c:geo nie może załadować listy skrzynek.</string>
+ <string name="err_store_failed">Przepraszam, c:geo nie może zapisać skrzynki.</string>
+ <string name="err_refresh_failed">Przepraszam, c:geo nie może zaktualizować skrzynki.</string>
+ <string name="err_drop_failed">Przepraszam, c:geo nie może skasować skrzynki.</string>
+ <string name="err_dwld_details_failed">Przepraszam, c:geo nie może załadować szczegółów skrzynki.</string>
+ <string name="err_dwld_details_failed_reason">Przepraszam, c:geo nie może załadować szczegółów skrzynki, ponieważ</string>
+ <string name="err_load_descr_failed">Przepraszam, c:geo nie może załadować opisu.</string>
+ <string name="err_location_unknown">c:geo nie zna lokalizacji skrzynki.</string>
+ <string name="err_manual_title">Instrukcja obsługi nie jest zainstalowana.</string>
+ <string name="err_manual_message">Instrukcja obsługi c:geo nie znajduje się na twojej komórce. Chczesz ją zainstalować?</string>
+ <string name="err_manual_market">c:geo nie może wystartować Android Market aby poszukać instrukcji obsługi.</string>
+
+ <string name="err_tb_display">"Przepraszam, c:geo nie może pokazać przedmiotów podróżnych. Czy to rzeczywiście jest przedmiot podróżny?</string>
+ <string name="err_tb_details_open">Przepraszam, c:geo nie może otworzyć szczegółów przedmiotu podróżnego.</string>
+ <string name="err_tb_details_download">Przepraszam, c:geo nie może otworzyć szczegółów przedmiotu podróżnego, ponieważ</string>
+ <string name="err_tb_forgot">Przepraszam, c:geo zapomiał jaki przedmiot podróżny chciałeś.</string>
+ <string name="err_tb_forgot_saw">Przepraszam, c:geo zapomiał jaki przedmiot podróżny widziałeś.</string>
+ <string name="err_tb_find">Przepraszam, c:geo nie może znaleźć przedmiotu podróżnego.</string>
+ <string name="err_tb_find_that">Przepraszam, c:geo nie może znaleźć tego przedmiotu podróżnego.</string>
+
+ <string name="err_waypoint_cache_unknown">Przepraszam, c:geo nie wie do jakiej skrzynki chcesz dodać punkt nawigacji.</string>
+ <string name="err_waypoint_unknown">Przepraszam, c:geo zapomiał jaki punkt nawigacyjny chciałeś obejrzeć.</string>
+ <string name="err_waypoint_add_failed">Przepraszam, c:geo nie może dodać punktu nawigacyjnego.</string>
+ <string name="err_waypoint_load_failed">Przepraszam, c:geo nie może załadować punktu nawigacyjnego.</string>
+ <string name="err_waypoint_delete_failed">Przepraszam, c:geo nie może skasować punktu nawigacyjnego.</string>
+ <string name="err_point_unknown_position">Przepraszam, 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żna 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_point_location_error">Przepraszam, c:geo nie może rozpoznać lokalizacji punktu nawigacyjnego.</string>
+ <string name="err_navigation_not_found">c:geo nie może znaleźć żadnej nawigacji.</string>
+
+ <string name="err_log_load_data">Przepraszam, c:geo nie może załadować dane wymagane do zalogowania wizyty.</string>
+ <string name="err_log_load_data_again">Przepraszam, c:geo nie może załadować dane wymagane do zalogowania wizyty. Próbuję ponownie.</string>
+ <string name="err_log_load_data_still">Nadal trwa ładowanie danych wymaganych do wpisu w dzienniku. Proszę czekać trochę dłużej.</string>
+ <string name="err_log_failed_server">Przepraszam, c:geo nie może wysłać wpisu ponieważ serwer nie odpowiada.</string>
+ <string name="err_log_post_failed">Przepraszam, c:geo nie mógł dodać wpisu do dziennika.</string>
+ <string name="err_log_post_failed_because">Przepraszam, c:geo nie mógł dodać wpisu do dziennika, ponieważ </string>
+
+ <string name="err_search_address_no_match">Przepraszam, c:geo nie znalazł pasującego miejsca.</string>
+ <string name="err_search_address_forgot">Przepraszam, c:geo zapomiał jaki adres szukałeś.</string>
+ <string name="err_search_address">Wyszukiwanie miejsc</string>
+ <string name="err_parse_lat">Przepraszam, c:geo nie może obliczyć szerokości geograficznej.</string>
+ <string name="err_parse_lon">Przepraszam, c:geo nie może obliczyć długości geograficznej.</string>
+ <string name="err_parse_bear">Przepraszam, c:geo nie może obliczyć namiaru.</string>
+ <string name="err_parse_dist">Przepraszam, c:geo nie może obliczyć odległości.</string>
+
+ <string name="warn_save_nothing">Nie ma nic do zapisania.</string>
+ <string name="warn_no_cache_coord">Nie ma skrzynek z współrzędnymi GPS.</string>
+ <string name="warn_no_coordinates">Nie podane współrzędne.</string>
+ <string name="warn_no_keyword">Nie podane słowo kluczowe.</string>
+ <string name="warn_no_username">Nie podana nazwa użytkownika.</string>
+ <string name="warn_search_help_title">Potrzebujesz pomocy?</string>
+ <string name="warn_search_help_address">Wpisz adres lub nazwę, np. adres ulicy \"ul. Grunwaldzka, Gdańsk, Polska\", nazwę miasta \"Koszalin\" lub po prostu nazwę jak \"Łazienki Królewskie\".</string>
+ <string name="warn_search_help_gccode">Wpisz kod GC. Na przykład \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Wpisz jakieś słowo, które może być gdzieś w nazwie skrytki którą chcesz znaleźć.</string>
+ <string name="warn_search_help_user">Wpisz nazwę użytkownika serwisu Geocaching.com.</string>
+ <string name="warn_search_help_tb">Wpisz kod przedmiotu podróżnego. Na przykład \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">Proszę wypełnić jakimś tekstem.</string>
+
+ <string name="info_altitude">Aktualna wysokość</string>
+ <string name="info_distance">Przebyta odległość</string>
+ <string name="info_distance_cleared">Przebyta odległość została skasowana.</string>
+ <string name="info_since">\n(od </string>
+
+ <string name="info_log_posted">Wpis został dodany.</string>
+ <string name="info_log_saved">Wpis został zapisany.</string>
+ <string name="info_log_cleared">Wpis został skasowany.</string>
+ <string name="info_log_type_changed">Rodzaj wpisu w dzienniku został zmieniony!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Ostatnie stanowisko</string>
+ <string name="loc_net">Sieć</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Próba lokalizacji</string>
+ <string name="loc_no_addr">Nieznany andres</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">O c:geo</string>
+ <string name="menu_helpers">Przydatne Apps</string>
+ <string name="menu_settings">Ustawienia</string>
+ <string name="menu_history">Historia</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Mapka</string>
+ <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">Wszędzie</string>
+ <string name="about_button">O c:geo</string>
+ <string name="settings_button">Ustawienia</string>
+ <string name="type">Filter</string>
+ <string name="now_searching">Szukam...</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Szukam skrzynki</string>
+ <string name="caches_no_cache">Nie ma skrzynki</string>
+ <string name="caches_more_caches">Więcej skrzynek</string>
+ <string name="caches_more_caches_no">Nie ma więcej skrzynek</string>
+ <string name="caches_more_caches_loading">Ładuję skrzynki...</string>
+ <string name="caches_downloading">Ładuję skrzynki...\nSzacowany czas: </string>
+ <string name="caches_progress_loading_title">Ładuję skrzynki</string>
+ <string name="caches_progress_loading_text">Zapisane skrzynki</string>
+ <string name="caches_eta_ltm">Mniej niż minutę</string>
+ <string name="caches_eta_mins"> minut</string>
+ <string name="caches_eta_min"> minuta</string>
+ <string name="caches_no_caches"> (nie ma skrzynek)</string>
+ <string name="caches_store_offline">Zapisz offline</string>
+ <string name="caches_store_selected">Zapisz wybrane</string>
+ <string name="caches_stored">Zapisane</string>
+ <string name="caches_history">Historia</string>
+ <string name="caches_on_map">Pokaż na mapie</string>
+ <string name="caches_sort">Sortuj</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_distance">według odległości</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_difficulty">według trudności</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_terrain">według terenu</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_size">według wielkości</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_favorites">według popularności</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_select">Wybierz z listy</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ądzać</string>
+ <string name="caches_drop_selected">Wybrane skasować</string>
+ <string name="caches_drop_selected_ask">Czy chcesz usunąć wybrane skrzynki z pamięci?</string>
+ <string name="caches_drop_all">Skasuj wszystkie</string>
+ <string name="caches_drop_all_ask">Czy chcesz usunąc wszystkie skrzynki z pamięci?</string>
+ <string name="caches_drop_stored">Skasuj zapisane</string>
+ <string name="caches_drop_progress">Usuwanie skrzynek</string>
+ <string name="caches_refresh_selected">Odśwież wybrane</string>
+ <string name="caches_refresh_all">Odśwież wszystkie</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Proszę, napisz tekst z obrazka. Ważne to jest, aby można było pobrać współrzędne do skrzynek. To jest opcjonalne i może być wyłączone w ustawieniach.</string>
+ <string name="caches_recaptcha_hint">Tekst z obrazka</string>
+ <string name="caches_recaptcha_continue">Kontynuuj</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">Lista</string>
+ <string name="list_menu_create">Utwórz nową listę</string>
+ <string name="list_menu_drop">Usuń aktualną listę</string>
+ <string name="list_title">Wybierz listę</string>
+ <string name="list_inbox">Zapisane</string>
+ <string name="list_wpt">Punkty nawigacyjne</string>
+ <string name="list_dialog_create_title">Nowa lista</string>
+ <string name="list_dialog_create">Utworzyć</string>
+ <string name="list_dialog_cancel">Anulować</string>
+ <string name="list_dialog_create_ok">Nowa lista została utworzona</string>
+ <string name="list_dialog_create_err">c:geo nie udało się utworzyć nowej listy</string>
+ <string name="list_dialog_remove_title">Usuń listę</string>
+ <string name="list_dialog_remove_description">Chcesz usunąć aktualną listę skrzynek? Wszystkie skrzynki na tej liście zostaną przeniesione do listy \"Zapisane\".</string>
+ <string name="list_dialog_remove">Usuń</string>
+ <string name="list_dialog_remove_ok">Lista została usunięta</string>
+ <string name="list_dialog_remove_err">c:geo nie udało się usunąć obecną listę</string>
+
+ <!-- about -->
+ <string name="about_changelog">Zmiany</string>
+ <string name="about_donate">Wspomóc</string>
+ <string name="about_detail">Szczegóły</string>
+ <string name="about_donation_less">Mniejsza\ndarowizna</string>
+ <string name="about_donation_more">Darowizna dla\nprogramisty</string>
+ <string name="about_contributors">Współpracownicy</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Nazwa użytkownika</string>
+ <string name="init_password">Hasło</string>
+ <string name="init_passvote">Hasło</string>
+ <string name="init_login">Sprawdź Logowanie</string>
+ <string name="init_login_popup">Logowanie</string>
+ <string name="init_login_popup_working">Logowanie w geocaching.com...</string>
+ <string name="init_login_popup_ok">Login ok.</string>
+ <string name="init_login_popup_failed">Logowanie nie powiodło się.</string>
+ <string name="init_login_popup_failed_reason">Logowanie nie powiodło się, ponieważ </string>
+ <string name="init_legal">Nota prawna</string>
+ <string name="init_go4cache_connect">Połącz się z Go 4 Cache</string>
+ <string name="init_twitter_authorize">Autoryzacja c:geo</string>
+ <string name="init_twitter_publish">Publikowanie stanu, gdy znaleziono skrzynkę</string>
+ <string name="init_signature">Sygnatura</string>
+ <string name="init_signature_help_button">Pomoc</string>
+ <string name="init_signature_help_title">Sygnatura, porady i wskazówki</string>
+ <string name="init_signature_help_text">Wprowadź swoją sygnaturę która będzie używana przy wpisie do dziennika.\nSpecjalne kody, które mogą być stosowane są: [DATE] , [TIME], [USER] &amp; [NUMBER].</string>
+ <string name="init_languages">Przetłumaczenie</string>
+ <string name="init_languages_description">Jakie języki rozumiesz? Proszę o podanie dwóch znaków kodów.</string>
+ <string name="init_languages_hint">pl en de</string>
+ <string name="init_translate">Przetłumacz opis &amp; wskazówkę</string>
+ <string name="init_other">Inne opcje</string>
+ <string name="init_skin">Light skin\n(wymaga restartu)</string>
+ <string name="init_transparent">Użyj przejrzysty Panel w c:geo</string>
+ <string name="init_address">Pokaż adres na ekranie głównym</string>
+ <string name="init_captcha">Pokaż CAPTCHA w razie potrzeby</string>
+ <string name="init_useenglish">Użyj języka angielskiego wewnątrz c:geo\n(wymaga restartu)</string>
+ <string name="init_exclude">Wyklucz własne lub już znalezione skrzynki</string>
+ <string name="init_disabled">Wyklucz tymczasowo niedostępne skrzynki</string>
+ <string name="init_offline">Zapisuj mampki do użytku offline</string>
+ <string name="init_units">Używaj angielskich jednostek miary\n(mile)</string>
+ <string name="init_nav">Używaj Google Navigation</string>
+ <string name="init_autoload">Długie opisy automatycznie ładować</string>
+ <string name="init_livelist">Pokazuj na liście kierunek do skrzynek</string>
+ <string name="init_browser">Ustaw c:geo jako standardową przeglądarkę</string>
+ <string name="init_clear">Skasuj login</string>
+ <string name="init_cleared">c:geo skasował dane logowania.</string>
+ <string name="init_backup">Kopia zapasowa</string>
+ <string name="init_backup_backup">Kopiuj</string>
+ <string name="init_backup_note">Zwróć uwagę, że ta opcja wykonuje tylko kopie/odzyskiwanie bazy danych, zawierającej skrzynki i punkty nawigacyjne, a nie ustawienia. Twoje dane logowania (hasła) nie opuszczą tej aplikacji.</string>
+ <string name="init_backup_restore">Przywróć</string>
+ <string name="init_backup_success">Baza danych c:geo została pomyślnie skopiowana do pliku</string>
+ <string name="init_backup_failed">Kopia zapasowa bazy danych c:geo nie powiodła się.</string>
+ <string name="init_restore_success">Przywrócenie zakończone.</string>
+ <string name="init_restore_failed">Przywrócenie nie powiodło się.</string>
+ <string name="init_backup_last">Kopia dostępna od</string>
+ <string name="init_backup_last_no">Nie ma plików z kopią zapasową.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Autoryzacja c:geo</string>
+ <string name="auth_start">Startuję autoryzację</string>
+ <string name="auth_again">Startuję ponownie autoryzację</string>
+ <string name="auth_pin_hint">PIN nadany przez Twitter</string>
+ <string name="auth_finish">Gotowe</string>
+ <string name="auth_dialog_wait">Czekam na Twitter...</string>
+ <string name="auth_dialog_pin_title">kod PIN</string>
+ <string name="auth_dialog_pin_message">Proszę wpisać kod PIN dostarczony przez stronę Twitter. To jest obowiązkowe do ukończenia zezwolenia.</string>
+ <string name="auth_dialog_completed">c:geo jest teraz upoważniony do postu na Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Nie ma skrzynek</string>
+ <string name="cache_count_one">Jedna skrzynka</string>
+ <string name="cache_count_more">Skrzynki</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Odśwież</string>
+ <string name="cache_offline_drop">Skasuj</string>
+ <string name="cache_offline_store">Zapisz</string>
+ <string name="cache_offline_stored">Zapisane w pamięci</string>
+ <string name="cache_offline_not_ready">Nie jest gotowy\ndo użytku offline</string>
+ <string name="cache_offline_time_about">około</string>
+ <string name="cache_offline_time_mins">minut</string>
+ <string name="cache_offline_time_mins_few">przed kilkoma minutami</string>
+ <string name="cache_offline_time_hour">przed jedną godziną</string>
+ <string name="cache_offline_time_hours">przed godzinami</string>
+ <string name="cache_offline_time_days">przed kilkoma dniami</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Atrybuty</string>
+ <string name="cache_inventory">Inwentarz</string>
+ <string name="cache_log_offline">Wpis offline</string>
+ <string name="cache_description">Opis</string>
+ <string name="cache_description_long">Długi opis</string>
+ <string name="cache_waypoints">Punkty nawigacji</string>
+ <string name="cache_waypoints_add">Dodaj punkt nawigacji</string>
+ <string name="cache_hint">Wskazówka</string>
+ <string name="cache_logs">Dziennik</string>
+ <string name="cache_dialog_loading_details">Ładuje szczegóły skrzynki...</string>
+ <string name="cache_dialog_loading_description">Ładuje opis skrzynki...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Zapisywanie skrzynek do trybu offline...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Kasuję skrzynkę z pamięci...</string>
+ <string name="cache_dialog_refresh_title">Odśwież</string>
+ <string name="cache_dialog_refresh_message">Aktualizuje szczegóły skrzynki...</string>
+ <string name="cache_menu_navigate">Nawigować</string>
+ <string name="cache_menu_compass">Kompas</string>
+ <string name="cache_menu_tbt">Zakręt po zakręcie</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Pokaż na mapie</string>
+ <string name="cache_menu_map_static">Statyczna mapa</string>
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_ext">Pokaż na zewnętrznej mapie</string>
+ <string name="cache_menu_map_short">Mapa</string>
+ <string name="cache_menu_map_ext_short">Zewn. mapa</string>
+ <string name="cache_menu_browser">Otwórz w przeglądarce</string>
+ <string name="cache_menu_visit">Zaloguj wizytę</string>
+ <string name="cache_menu_spoilers">Zdjęcie spoiler</string>
+ <string name="cache_menu_around">Skrzynek w okręgu</string>
+ <string name="cache_menu_event">Wpisz do kalendarza</string>
+ <string name="cache_menu_details">Szczegóły</string>
+ <string name="cache_menu_share">Podziel się skrzynką</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Zapamiętany wpis</string>
+ <string name="cache_status_found">Znalezione</string>
+ <string name="cache_status_archived">Archiwum</string>
+ <string name="cache_status_disabled">Niedostępny</string>
+ <string name="cache_status_premium">Tylko dla premium użytkowników</string>
+ <string name="cache_geocode">GC-kod</string>
+ <string name="cache_name">Nazwa</string>
+ <string name="cache_type">Typ</string>
+ <string name="cache_distance">Odległość</string>
+ <string name="cache_difficulty">Trudności</string>
+ <string name="cache_terrain">Teren</string>
+ <string name="cache_rating">Ocena</string>
+ <string name="cache_rating_of">od</string>
+ <string name="cache_favourite">Ulubiony</string>
+ <string name="cache_owner">Właściciel</string>
+ <string name="cache_hidden">Schowano</string>
+ <string name="cache_event">Data</string>
+ <string name="cache_location">Lokacja</string>
+ <string name="cache_coordinates">Współrzędne</string>
+ <string name="cache_elevation">Wzniesienie</string>
+ <string name="cache_calendars">Wybierz kalendarz</string>
+ <string name="cache_spoiler_images_title">Zdjęcie spoiler</string>
+ <string name="cache_spoiler_images_loading">Ładuje zdjęcia spoiler...</string>
+ <string name="cache_log_types">Rodzaj logu</string> <!-- Since: 2.10 RC2 -->
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Szukam pliki .gpx\nw</string>
+ <string name="gpx_import_loading_stored">Ładuje skrzynki z pliku .gpx\nZapisane:</string>
+ <string name="gpx_import_no_files">Przepraszam, c:geo nie znalazł plików .gpx</string>
+ <string name="gpx_import_caches_imported">skrzynek importowanych</string>
+ <string name="gpx_import_searching">Szukam za plikami .gpx</string>
+ <string name="gpx_import_loading">Ładuje skrzynki z pliku .gpx</string>
+ <string name="gpx_import_title">Import GPX</string>
+ <string name="gpx_import_title_reading_file">Czytanie pliku</string>
+ <string name="gpx_import_title_searching">Wyszukiwanie</string>
+ <string name="gpx_import_title_caches_imported">Wynik</string>
+
+ <!-- event -->
+ <string name="event_success">Wydarzenie wpisane do kalendarza</string>
+ <string name="event_fail">Nie udało się wpisać wydarzenia do kalendarza</string>
+
+ <!-- popup -->
+ <string name="popup_more">Więcej szczegółów</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Punkt nawigacji</string>
+ <string name="waypoint_custom">Zdefiniowane przez użytkownika</string>
+ <string name="waypoint_my_coordinates">Moje współrzędne</string>
+ <string name="waypoint_bearing">Kierunek</string>
+ <string name="waypoint_distance">Odległość</string>
+ <string name="waypoint_name">Nazwa</string>
+ <string name="waypoint_edit">Edytuj</string>
+ <string name="waypoint_delete">Skasuj</string>
+ <string name="waypoint_edit_title">Edytuj punkt nawigacyjny</string>
+ <string name="waypoint_add_title">Dodaj punkt nawigacyjny</string>
+ <string name="waypoint_note">Notatka</string>
+ <string name="waypoint_save">Zapisz</string>
+ <string name="waypoint_loading">Ładuje punkt nawigacyjny...</string>
+ <string name="waypoint_unknown_coordinates">Współrzędne nieznane</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Wyślij ten wpis też do Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Mapa</string>
+ <string name="map_live">Live mapa</string>
+ <string name="map_view_satellite">Widok z satelity</string>
+ <string name="map_view_map">Widok mapy</string>
+ <string name="map_trail_show">Pokaż szlak</string>
+ <string name="map_trail_hide">Ukryj szlak</string>
+ <string name="map_live_enable">Włącz live</string>
+ <string name="map_live_disable">Wyłącz live</string>
+ <string name="map_static_title">Statyczna mapa</string>
+ <string name="map_static_loading">Ładuje statyczną mapę...</string>
+
+ <!-- search -->
+ <string name="search_bar_hint">Szukaj skrzynki</string>
+ <string name="search_bar_desc">Skrzynki (GC-kod, słowo kluczowe), przedmioty podróżne (TB-kod)</string>
+ <string name="search_coordinates">Współrzędne</string>
+ <string name="search_coordinates_button">Szukaj według współrzędnych</string>
+ <string name="search_address">Adres</string>
+ <string name="search_address_button">Szukaj według adresu</string>
+ <string name="search_gc">GC-kod</string>
+ <string name="search_gc_button">Szukaj według GC-kodu</string>
+ <string name="search_kw">Słowa kluczowe</string>
+ <string name="search_kw_prefill">Słowo kluczowe</string>
+ <string name="search_kw_button">Szukaj z słowem kluczowym</string>
+ <string name="search_kw_caches">Skrzynki z słowem kluczowym</string>
+ <string name="search_caches_found_by">Skrzynki znalezione przez</string>
+ <string name="search_caches_hidden_by">Skrzynki schowane przez</string>
+ <string name="search_fbu">Znalezione przez użytkownika</string>
+ <string name="search_fbu_prefill">Nazwa użytkownika</string>
+ <string name="search_fbu_button">Szukaj według nazwy użytkownika</string>
+ <string name="search_hbu">Schowane przez użytkownika</string>
+ <string name="search_hbu_prefill">Właściciel</string>
+ <string name="search_hbu_button">Szukaj według właściciela</string>
+ <string name="search_tb">Przedmioty podróżne</string>
+ <string name="search_tb_hint">Numer przedmiotu podróżnego</string>
+ <string name="search_tb_button">Szukaj przedmiotów podróżnych</string>
+ <string name="search_destination">Cel</string>
+ <string name="search_direction_rel">Z tej pozycji</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Szukaj skrzynki</string>
+ <string name="search_caches_near">Skrzynki w pobliżu</string>
+ <string name="search_address_started">Wyszukiwanie miejsc</string>
+ <string name="search_address_result">Znalezione miejsca</string>
+
+ <!-- trackable -->
+ <string name="trackable">Przedmiot podróżny</string>
+ <string name="trackable_select_title">Przedmioty podróżne</string>
+ <string name="trackable_details_loading">Ładuje szczegóły przedmiotu podróżnego...</string>
+ <string name="trackable_log_touch">Wpisz odkrycie</string>
+ <string name="trackable_browser_open">Otwórz w przeglądarce</string>
+ <string name="trackable_goal">Cel</string>
+ <string name="trackable_details">Szczegóły</string>
+ <string name="trackable_image">Zdjęcie</string>
+ <string name="trackable_code">TB-kod</string>
+ <string name="trackable_name">Nazwa</string>
+ <string name="trackable_type">Typ</string>
+ <string name="trackable_owner">Właściciel</string>
+ <string name="trackable_spotted">Ostatnio widziany</string>
+ <string name="trackable_spotted_in_cache">W</string>
+ <string name="trackable_spotted_at_user">U</string>
+ <string name="trackable_spotted_unknown_location">W nieznanym miejscu</string>
+ <string name="trackable_spotted_owner">U właściciela</string>
+ <string name="trackable_origin">Pochodzenie</string>
+ <string name="trackable_unknown">Nieznany</string>
+ <string name="trackable_released">Wydany</string>
+ <string name="trackable_distance">W podróży</string>
+ <string name="trackable_touch">TB-Akcja</string>
+
+ <!-- user -->
+ <string name="user_menu_title">O użytkowniku</string>
+ <string name="user_menu_view_hidden">Schowane skrzynki</string>
+ <string name="user_menu_view_found">Znalezione skrzynki</string>
+ <string name="user_menu_open_browser">Otwórz w przeglądarce</string>
+
+ <!-- navigation -->
+ <string name="navigation">Nawigacja</string>
+ <string name="compass_title">Kompas</string>
+ <string name="use_gps">Użyj GPS</string>
+ <string name="use_compass">Użyj kompas</string>
+ <string name="destination_select">Wybierz cel</string>
+ <string name="destination_set">Ustal cel</string>
+
+ <!-- license -->
+ <string name="license">Licencja</string>
+ <string name="license_show">Pokaż licencje</string>
+ <string name="license_dismiss">Odmówić</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">Instrukcja obsługi</string>
+ <string name="helper_manual_description">Obszerny przewodnik do c:geo wraz z opisem wszystkich możliwości tej aplikacji (także ukryte).</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 (map rastrowych tylko). Nagrywanie ścieżek, obsługa POI i wiele innych przydatnych funkcji.</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>
+ <string name="helper_bluetoothgps_description">Umożliwia korzystanie z zewnętrznego odbiornika sygnału GPS, aby uzyskać lepszy odbiór, bardziej precyzyjnej lokalizacji i oszczędzać baterię komórki.</string>
+
+ <!-- next things -->
+ <string name="legal_note">Aby móc korzystać z usług serwisu geocaching.com <a href="http://www.geocaching.com/about/termsofuse.aspx">warunki korzystania Groundspeak</a> muszą być potwierdzone.</string>
+ <string name="about_text"><b>c:geo</b> został opracowany aby był łatwym w obsłudze i wszechstronnym klientem serwisu geocaching.com. Jest i zawsze będzie za darmo. Jeśli chcesz wspierać rozwój aplikacji, donacje są mile widziane (na stronie internetowej). Pytania lub sugestie? Odwiedź mój profil w Facebook albo wyślij mi e-mail.</string>
+ <string name="author">Autor: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Website: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</a></string>
+ <string name="facebook">Facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo strona</a></string>
+ <string name="twitter">Twitter: <a href="http://twitter.com/android_gc">@android_GC</a></string>
+ <string name="nutshellmanual">Manuał: <a href="http://itw.bidix.info/cgeo/">c:geo skrócona instrukcja obsługi</a></string>
+ <string name="about_go4cache">Serwis <b>Go 4 Cache</b> pokazuje innych geocachers na mapie (w <b>c:geo</b> lub w przeglądarce) w czasie rzeczywistym. Pokazuje na przykład co inni w tym czasie szukają. Razem z połączeniem do <b>Go 4 Cache</b> pozwalasz <b>c:geo</b> aby twoje współrzędne zostały na stronie internetowej opublikowane (tylko i wyłącznie wtedy, gdy <b>c:geo</b> jest aktywny).</string>
+ <string name="about_twitter">Czy chczesz aby <b>c:geo</b> publikował wiadomości textowe na stronie Twitter za każdym razem jak znajdziesz skrzynkę?</string>
+ <string name="about_auth_1">Poniższy proces pozwala <b>c:geo</b>, aby uzyskać dostęp do Twitter - po uzgodnieniu.</string>
+ <string name="about_auth_2">Kliknięcie na \"Autoryzacja c:geo\" spowoduje rozpoczęcie procesu. Ten proces spowoduje otwarcie przeglądarki internetowej na stronie Twitter. Zaloguj się na tej stronie i pozwól <b>c:geo</b> aby uzyskać dostęp do konta. Jeśli zostanie zaakceptowany, Twitter pojawi kod numeryczny PIN. Kod PIN musi zostać wklejony do <b>c:geo</b> i zostać potwierdzony. To jest wszystko.</string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
new file mode 100644
index 0000000..d3e1503
--- /dev/null
+++ b/res/values-pt/strings.xml
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo compass</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detalhes</string>
+ <string name="search">Pesquisar</string>
+ <string name="settings">Definições</string>
+ <string name="about">Sobre c:geo</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Partilhar ligação para a cache</string>
+
+ <!-- caches -->
+ <string name="all">Todas as caches</string>
+ <string name="all_types">Caches de todos tipos</string>
+ <string name="traditional">Caches tradicionais</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Cache mistério</string>
+ <string name="letterbox">Letterbox hybrid</string>
+ <string name="event">Cache evento</string>
+ <string name="mega">Cache Mega-evento</string>
+ <string name="earth">Cache Terra</string>
+ <string name="cito">Evento cache in trash out</string>
+ <string name="webcam">Cache webcam</string>
+ <string name="virtual">Cache virtual</string>
+ <string name="wherigo">Cache whereigo</string>
+ <string name="lostfound">Perdidos e achados</string>
+ <string name="ape">Cache projecto ape</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">Cache GPS exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Localização final</string>
+ <string name="wp_stage">Estado da multi-cache</string>
+ <string name="wp_puzzle">Pergunta para a resposta</string>
+ <string name="wp_pkg">Parque de estacionamento</string>
+ <string name="wp_trailhead">Inicio</string>
+ <string name="wp_waypoint">Ponto de referência</string>
+
+ <!-- logs -->
+ <string name="log_found">Encontrei</string>
+ <string name="log_dnf">Não encontrei</string>
+ <string name="log_note">Nota</string>
+ <string name="log_published">Publicado</string>
+ <string name="log_enabled">Activo</string>
+ <string name="log_disabled">Desactivo</string>
+ <string name="log_attend">Vou participar</string>
+ <string name="log_attended">Participei</string>
+ <string name="log_retrieved">Retirado</string>
+ <string name="log_grabbed">Agarrado</string>
+ <string name="log_maintained">Manutenção efectuada</string>
+ <string name="log_maintenance_needed">Precisa manutenção</string>
+ <string name="log_maintenance_owner">Manutenção</string>
+ <string name="log_update">Coordenadas actualizadas</string>
+ <string name="log_archived">Arquivada</string>
+ <string name="log_needs_archived">Precisa arquivos</string>
+ <string name="log_discovered">Descoberta</string>
+ <string name="log_reviewed">Nota de revisor</string>
+ <string name="log_tb_nothing">Não fazer nada</string>
+ <string name="log_tb_visit">Visita</string>
+ <string name="log_tb_drop">Passei aqui</string>
+ <string name="log_tb_changeall">Alterar todos</string>
+ <string name="log_save">Gravar</string>
+ <string name="log_saving">A gravar o log...</string>
+ <string name="log_clear">Limpo</string>
+ <string name="log_post">Publicar log</string>
+ <string name="log_post_rate">Publicar log &amp; votar</string>
+ <string name="log_post_no_rate">Publicar log &amp; não votar</string>
+ <string name="log_add">Adicionar</string>
+ <string name="log_date">Data</string>
+ <string name="log_time">Hora</string>
+ <string name="log_date_time">Data &amp; hora</string>
+ <string name="log_rating">Pontuação</string>
+ <string name="log_no_rating">Não votar</string>
+ <string name="log_stars_1">1 estrela</string>
+ <string name="log_stars_2">2 estrela</string>
+ <string name="log_stars_3">3 estrela</string>
+ <string name="log_stars_4">4 estrela</string>
+ <string name="log_stars_5">5 estrela</string>
+ <string name="log_webcam">Fotografia tirada pela webcam</string>
+ <string name="log_new_log">Log</string>
+ <string name="log_new_log_text">Registar texto</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Comunicação não iniciada</string>
+ <string name="err_parse">Falha na análise da página de login</string>
+ <string name="err_server">Falha na ligação a geocaching.com (servidor ou ligação em baixo?)</string>
+ <string name="err_login">Informação de login não gravada</string>
+ <string name="err_login_failed">Desculpe, c:geo não consegue fazer login.</string>
+ <string name="err_unknown">Erro desconhecido</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>
+ <string name="err_license">O utilizador não concordou com a licença de utilização de Geocaching.com, por isso c:geo não pode carregar as coordenadas da cache.</string>
+ <string name="err_store">Desculpe, c:geo não pode armazenar a cache.</string>
+ <string name="err_drop">Desculpe, c:geo não pode apagar a cache.</string>
+ <string name="err_title_problem">Problema</string>
+ <string name="err_detail_open">Desculpe, c:geo não pode abrir os detalhes da geocache.</string>
+ <string name="err_detail_cache">Desculpe, c:geo não pode mostrar a cache pretendida. É mesmo uma geocache?</string>
+ <string name="err_detail_cache_find">Desculpe, c:geo não encontra a geocache</string>
+ <string name="err_detail_cache_find_some">Desculpe, c:geo não encontra essa geocache.</string>
+ <string name="err_detail_cache_find_any">Desculpe, c:geo não encontra qualquer geocache.</string>
+ <string name="err_detail_cache_find_next">Desculpe, c:geo não encontra as próximas geocaches.</string>
+ <string name="err_detail_cache_forgot">Desculpe, c:geo esqueceu a geocache pretendida.</string>
+ <string name="err_detail_cache_forgot_visit">Desculpe, c:geo esqueceu a cache que visitou.</string>
+ <string name="err_detail_cache_language">c:geo não consegue ler alguns detalhes da cache. Verifique que o site geocaching.com está parameterizado para inglês. Infelizmente c:geo não percebe outros idiomas.</string>
+ <string name="err_detail_no_spoiler">c:geo não encontrou images spoiler para esta cache.</string>
+ <string name="err_detail_no_map_static">c:geo não encontrou mapas estáticos para esta cache.</string>
+ <string name="err_detail_still_removing">A remover a cache.</string>
+ <string name="err_detail_still_saving">A gravar a cache.</string>
+ <string name="err_detail_still_refreshing">A recarregar a cache.</string>
+ <string name="err_radar_title">Radar não está instalado.</string>
+ <string name="err_radar_message">Esta função requer a aplicação Radar. Deve ser instalada?</string>
+ <string name="err_radar_market">c:geo não consegue iniciar o Android Market para pesquisar pela aplicação Radar.</string>
+ <string name="err_radar_generic">Desculpe, c:geo não consegue iniciar a aplicação Radar. Está instalada?</string>
+ <string name="err_navigation_no">c:geo não encontra nenhuma navegação suportada.</string>
+ <string name="err_application_no">c:geo não encontra a aplicação correcta.</string>
+ <string name="err_auth_initialize">Desculpe, c:geo falhou a iniciar o processo de autorização.</string>
+ <string name="err_auth_process">Processo de autorização falhou.</string>
+ <string name="err_cannot_log_visit">c:geo não tem informação suficiente para registar a visita. Por favor, faça-o a partir dos detalhes completos da cache.</string>
+ <string name="err_init_cleared">Desculpe, c:geo não consegue limpar os dados de login.</string>
+ <string name="err_no_chaches">Desculpe, c:geo falhou a carregar a cache ou caches.</string>
+ <string name="err_download_fail">Desculpe, c:geo falhou o download das caches porque </string>
+ <string name="err_update_fail">Falha ao actualizar a distância percorrida.</string>
+ <string name="err_list_load_fail">Desculpe, c:geo falhou a carregar a lista das caches.</string>
+ <string name="err_store_failed">Desculpe, c:geo não pode armazenar a geocache.</string>
+ <string name="err_refresh_failed">Desculpe, c:geo não consegue actualizar a geocache.</string>
+ <string name="err_drop_failed">Desculpe, c:geo não consegue apagar a cache.</string>
+ <string name="err_dwld_details_failed">Desculpe, c:geo falhou o download dos detalhes da cache.</string>
+ <string name="err_dwld_details_failed_reason">Desculpe, c:geo falhou o download dos detalhes da cache porque</string>
+ <string name="err_load_descr_failed">Desculpe, c:geo não consegue carregar a descrição.</string>
+ <string name="err_location_unknown">c:geo não sabe a localização da cache.</string>
+
+ <string name="err_tb_display">"Desculpe, c:geo não consegue mostrar o trackable pretendido. É mesmo um trackable?</string>
+ <string name="err_tb_details_open">Desculpe, c:geo não consegue abrir os detalhes do trackable.</string>
+ <string name="err_tb_details_download">Desculpe, c:geo failed to download trackable details because of</string>
+ <string name="err_tb_forgot">Desculpe, c:geo esqueceu o trackable pretendido.</string>
+ <string name="err_tb_forgot_saw">Desculpe, c:geo esqueceo o trackable que viu.</string>
+ <string name="err_tb_find">Desculpe, c:geo não encontra trackable</string>
+ <string name="err_tb_find_that">Desculpe, c:geo não encontra esse trackable.</string>
+
+ <string name="err_log_load_data">Desculpe, c:geo não consegue carregar os dados necessários para registar a sua visita.</string>
+ <string name="err_log_load_data_again">Desculpe, 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">c:geo ainda está a carregar dados necessários para publicar o registo. Por favor espere mais um pouco.</string>
+ <string name="err_log_failed_server">Desculpe, c:geo falhou a publicação do registo porque o servidor não responde.</string>
+ <string name="err_log_post_failed">Desculpe, c:geo falhou a publicação do registo.</string>
+ <string name="err_log_post_failed_because">Desculpe, c:geo falhou a publicação do registo porque </string>
+
+ <string name="err_search_address_no_match">Desculpe, c:geo não encontrou um local que corresponda.</string>
+ <string name="err_search_address_forgot">Desculpe, c:geo esqueceu o endereço que procura.</string>
+ <string name="err_search_address">À procura de locais</string>
+ <string name="err_parse_lat">Desculpe, c:geo não pode analisar a latitue.</string>
+ <string name="err_parse_lon">Desculpe, c:geo não pode analisar a logitude.</string>
+ <string name="err_parse_bear">Desculpe, c:geo não pode analisar a direcção.</string>
+ <string name="err_parse_dist">Desculpe, c:geo não pode analisar a distância.</string>
+
+ <string name="warn_save_nothing">Não há nada para guardar.</string>
+ <string name="warn_no_cache_coord">Não há cache com coordenadas.</string>
+ <string name="warn_no_coordinates">Nenhumas coordenadas fornecidas.</string>
+ <string name="warn_no_keyword">Nenhuma palavra-chave fornecida.</string>
+ <string name="warn_no_username">Nenhum nome de utilizador fornecido.</string>
+ <string name="warn_search_help_title">Precisa de ajuda?</string>
+ <string name="warn_search_help_address">"Preencha o endereço ou o nome da localização. Por exemplo o nome da rua \"Radlicka 100, Prague, Czech Republic\", nome da cidade \"Berlin\" ou simplesmente o nome de algo como \"Yellowstone Park\".</string>
+ <string name="warn_search_help_gccode">Preencha o código da geocache. Por exemplo \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Preencha acom uma palavra que é suposto estar algures no nome da cache que está a tentar encontrar.</string>
+ <string name="warn_search_help_user">Preencha o nome de utilizador em Geocaching.com.</string>
+ <string name="warn_search_help_tb">Fill code of trackable. For example \"TB29QMZ\".</string>
+
+ <string name="warn_log_text_fill">Por favor, preencha algum texto para o registo.</string>
+
+ <string name="info_altitude">Altitude corrente</string>
+ <string name="info_distance">Distância percorrida</string>
+ <string name="info_distance_cleared">A disntância percorrida foi limpa.</string>
+ <string name="info_since">\n(desde </string>
+
+ <string name="info_log_posted">c:geo publicou o registo com sucesso.</string>
+ <string name="info_log_saved">c:geo gravou o registo com sucesso.</string>
+ <string name="info_log_cleared">O registo foi limpo.</string>
+ <string name="info_log_type_changed">O tipo de registo foi alterado!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Último conhecido</string>
+ <string name="loc_net">Rede</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">A tentar localizar</string>
+ <string name="loc_no_addr">Endereço desconhecido</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Sobre c:geo</string>
+ <string name="menu_settings">Definições</string>
+ <string name="menu_filter">Filtro</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Mapa ao vivo</string>
+ <string name="caches_nearby_button">Por perto</string>
+ <string name="advanced_search_button">Pesquisar</string>
+ <string name="stored_caches_button">Armazenadas</string>
+ <string name="any_button">Qualquer destino</string>
+ <string name="about_button">Sobre</string>
+ <string name="settings_button">Definições</string>
+ <string name="type">Tipo</string>
+ <string name="now_searching">A pesquisar agora</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Pesquisar por caches</string>
+ <string name="caches_no_cache">Nenhuma cache</string>
+ <string name="caches_more_caches">Mais caches</string>
+ <string name="caches_more_caches_no">Mais nenhuma cache</string>
+ <string name="caches_downloading">Downloading caches...\nETE: </string>
+ <string name="caches_progress_loading_title">A carregar caches</string>
+ <string name="caches_progress_loading_text">Caches armazenadas no dispositivo</string>
+ <string name="caches_eta_ltm">Menos de um minuto</string>
+ <string name="caches_eta_mins"> minutos</string>
+ <string name="caches_eta_min"> minuto</string>
+ <string name="caches_no_caches"> (nenhuma cache)</string>
+ <string name="caches_store_offline">Armazenar para offline</string>
+ <string name="caches_store_selected">Armazenar selecionada</string>
+ <string name="caches_stored">Armazenada</string>
+ <string name="caches_on_map">Mostrar no mapa</string>
+ <string name="caches_select">Selecionar da lista</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_nearby">Por perto</string>
+ <string name="caches_drop_selected">Apagar selecionada</string>
+ <string name="caches_drop_selected_ask">Quer apagar as caches selecionados do dispositivo?</string>
+ <string name="caches_drop_all">Apagar todas</string>
+ <string name="caches_drop_all_ask">Quer remover todas as caches do dispositivo?</string>
+ <string name="caches_drop_stored">Apagar armazenada</string>
+ <string name="caches_refresh_selected">Actualizar selecionada</string>
+ <string name="caches_refresh_all">Actualizar todas</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+
+ <!-- about -->
+ <string name="about_changelog">Changelog</string>
+ <string name="about_donate">Doar</string>
+ <string name="about_detail">Detalhes</string>
+ <string name="about_donation_less">Doar\nmenos</string>
+ <string name="about_donation_more">Doar\ndesenvolvimento</string>
+ <string name="about_contributors">Contribuidores</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Nome de utilizador</string>
+ <string name="init_password">Password</string>
+ <string name="init_passvote">Password</string>
+ <string name="init_login">Verificar login</string>
+ <string name="init_login_popup">Login</string>
+ <string name="init_login_popup_working">Logging to geocaching.com...</string>
+ <string name="init_login_popup_ok">Login ok.</string>
+ <string name="init_login_popup_failed">Login falhado.</string>
+ <string name="init_login_popup_failed_reason">Login falhado porque </string>
+ <string name="init_legal">Nota legal</string>
+ <string name="init_go4cache_connect">Ligar a Go 4 Cache</string>
+ <string name="init_twitter_authorize">Autorize c:geo</string>
+ <string name="init_twitter_publish">Publicar estado quando encontrar cache</string>
+ <string name="init_signature">Assinatura</string>
+ <string name="init_other">Outras opções</string>
+ <string name="init_skin">Tema leve (precisa reiniciar c:geo)</string>
+ <string name="init_transparent">Utilizar ecrã principal do c:geo transparente</string>
+ <string name="init_address">Mostrar endereços no ecrãn principal</string>
+ <string name="init_exclude">Excluir caches encontradas e minhas</string>
+ <string name="init_disabled">Excluir caches desactivadas</string>
+ <string name="init_offline">Armazenar mapas para uso offline</string>
+ <string name="init_units">Utilizar distância nas unidades inglesas</string>
+ <string name="init_nav">Utilizar Google Navigation</string>
+ <string name="init_autoload">Carregar automaticamente a descrição longa</string>
+ <string name="init_livelist">Mostrar a direcção para a cache na lista</string>
+ <string name="init_browser">Utilizar c:geo como browser principal</string>
+ <string name="init_clear">Limpar login</string>
+ <string name="init_cleared">c:geo limpou a informação de login.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Autorizar c:geo</string>
+ <string name="auth_start">Autorização iniciada</string>
+ <string name="auth_again">Iniciar de novo</string>
+ <string name="auth_pin_hint">PIN atribuido pelo Twitter</string>
+ <string name="auth_finish">Fim</string>
+ <string name="auth_dialog_wait">A esperar por Twitter...</string>
+ <string name="auth_dialog_pin_title">Código PIN</string>
+ <string name="auth_dialog_pin_message">Por favor insira o código PIN fornecido pelo site do Twitter. É imperativo para que se complete a autorização.</string>
+ <string name="auth_dialog_completed">c:geo está agora autorizado a publicar no Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Nenhuma cache</string>
+ <string name="cache_count_one">Uma cache</string>
+ <string name="cache_count_more">Caches</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Actualizar</string>
+ <string name="cache_offline_drop">Apagar</string>
+ <string name="cache_offline_store">Armazenar</string>
+ <string name="cache_offline_stored">Armazenada no dispositivo</string>
+ <string name="cache_offline_not_ready">Não está pronto\npara utilização offline</string>
+ <string name="cache_offline_time_about">sobre</string>
+ <string name="cache_offline_time_mins">minutos atrás</string>
+ <string name="cache_offline_time_mins_few">alguns minutos atrás</string>
+ <string name="cache_offline_time_hour">uma hora atrás</string>
+ <string name="cache_offline_time_hours">horas atrás</string>
+ <string name="cache_offline_time_days">dias atrás</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Atributos</string>
+ <string name="cache_inventory">Inventório</string>
+ <string name="cache_log_offline">Registo Offline</string>
+ <string name="cache_description">Descrição</string>
+ <string name="cache_description_long">Descrição longa</string>
+ <string name="cache_waypoints">Waypoints</string>
+ <string name="cache_waypoints_add">Adicionar waypoint</string>
+ <string name="cache_hint">Pista</string>
+ <string name="cache_logs">Livro de resgisto</string>
+ <string name="cache_dialog_loading_details">A carregar os detalhes da cache...</string>
+ <string name="cache_dialog_loading_description">A carregar a descrição da cache...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">A gravar cache para utilizar offline ...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">A remover a cache da memória do dispositivo...</string>
+ <string name="cache_dialog_refresh_title">Actualizar</string>
+ <string name="cache_dialog_refresh_message">A recarregar os detalhes da cache...</string>
+ <string name="cache_menu_navigate">Navegar</string>
+ <string name="cache_menu_compass">Bússola</string>
+ <string name="cache_menu_tbt">Turn-by-turn</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Mostrar no mapa</string>
+ <string name="cache_menu_map_ext">Mostrar no mapa ext.</string>
+ <string name="cache_menu_map_static">Mapa estático</string>
+ <string name="cache_menu_map_short">Mapas</string>
+ <string name="cache_menu_map_ext_short">Mapa ext.</string>
+ <string name="cache_menu_browser">Abrir no browser</string>
+ <string name="cache_menu_visit">Registar visita</string>
+ <string name="cache_menu_spoilers">Imagens spoiler</string>
+ <string name="cache_menu_around">caches próximas</string>
+ <string name="cache_menu_event">Adicionar ao calendário</string>
+ <string name="cache_menu_details">Detalhes</string>
+ <string name="cache_status">Estado</string>
+ <string name="cache_status_offline_log">Registo gravado</string>
+ <string name="cache_status_found">Encontrada</string>
+ <string name="cache_status_archived">Arquivada</string>
+ <string name="cache_status_disabled">Desactivada</string>
+ <string name="cache_status_premium">Apenas membros premium</string>
+ <string name="cache_geocode">GC-code</string>
+ <string name="cache_name">Nome</string>
+ <string name="cache_type">Tipo</string>
+ <string name="cache_distance">Distância</string>
+ <string name="cache_difficulty">Dificuldade</string>
+ <string name="cache_terrain">Terreno</string>
+ <string name="cache_rating">Pontuação</string>
+ <string name="cache_owner">Dono</string>
+ <string name="cache_hidden">Escondida</string>
+ <string name="cache_event">Data</string>
+ <string name="cache_location">Localização</string>
+ <string name="cache_coordinates">Coordenadas</string>
+ <string name="cache_calendars">Selecionar calendário</string>
+ <string name="cache_gpx_import">Importar ficheiro GPX</string>
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">A procurar por ficheiros .gpx\nem</string>
+ <string name="gpx_import_loading_stored">a carregar caches do ficheiro .gpx\narmazenado:</string>
+ <string name="gpx_import_no_files">Desculpe, c:geo não encontrou ficheiros .gpx.</string>
+ <string name="gpx_import_caches_imported">caches importadas</string>
+ <string name="gpx_import_searching">A procurar ficheiros .gpx</string>
+ <string name="gpx_import_loading">A carregar caches do ficheiro .gpx</string>
+ <string name="gpx_import_title">Importar GPX</string>
+ <string name="gpx_import_title_reading_file">A ler o ficheiro</string>
+ <string name="gpx_import_title_searching">Procurar</string>
+ <string name="gpx_import_title_caches_imported">Resultado</string>
+
+ <!-- event -->
+ <string name="event_success">Cache evento adiconada ao calendário</string>
+ <string name="event_fail">Falha ao adicionar a cache evento ao calendário</string>
+
+ <!-- popup -->
+ <string name="popup_more">Mais detalhes</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Waypoint</string>
+ <string name="waypoint_custom">Custom</string>
+ <string name="waypoint_my_coordinates">Minhas coordenadas</string>
+ <string name="waypoint_bearing">Direcção</string>
+ <string name="waypoint_distance">Distância</string>
+ <string name="waypoint_name">Nome</string>
+ <string name="waypoint_edit">Editar</string>
+ <string name="waypoint_delete">Apagar</string>
+ <string name="waypoint_edit_title">Editar waypoint</string>
+ <string name="waypoint_add_title">Adicionar waypoint</string>
+ <string name="waypoint_note">Nota</string>
+ <string name="waypoint_save">Gravar</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Publicar esta descoberta no Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Mapa</string>
+ <string name="map_live">Mapa ao vivo</string>
+ <string name="map_view_satellite">Vista de satélite</string>
+ <string name="map_view_map">Vista de mapa</string>
+ <string name="map_trail_show">Mostrar caminho</string>
+ <string name="map_trail_hide">Esconder caminho</string>
+ <string name="map_live_enable">Activar ao vivo</string>
+ <string name="map_live_disable">Desactivar ao vivo</string>
+
+ <!-- search -->
+ <string name="search_coordinates">Coordenadas</string>
+ <string name="search_coordinates_button">Pesquisar por coordenadas</string>
+ <string name="search_address">Endereço</string>
+ <string name="search_address_button">Pesquisar por endereço</string>
+ <string name="search_gc">Geo-código</string>
+ <string name="search_gc_button">Pesquisar por geo-código</string>
+ <string name="search_kw">Palavras-chave</string>
+ <string name="search_kw_prefill">Palavra-chave</string>
+ <string name="search_kw_button">Pesquisar por palavra-chave</string>
+ <string name="search_kw_caches">Caches por palavra-chave</string>
+ <string name="search_caches_found_by">Caches encontradas por</string>
+ <string name="search_caches_hidden_by">Caches escondidas por</string>
+ <string name="search_fbu">Encontradas pelo utilizador</string>
+ <string name="search_fbu_prefill">Nome de utilizador</string>
+ <string name="search_fbu_button">Pesquisar por nome de utilizador</string>
+ <string name="search_hbu">Escondida pelos utilizadores</string>
+ <string name="search_hbu_prefill">Dono</string>
+ <string name="search_hbu_button">Pesquisar pelo dono</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">identificação trackable</string>
+ <string name="search_tb_button">Pesquisar por trackable</string>
+ <string name="search_destination">Destino</string>
+ <string name="search_direction_rel">A partir desta posição</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Pesquisar por caches</string>
+ <string name="search_caches_near">Caches perto</string>
+ <string name="search_address_started">Pesquisar por lugares</string>
+ <string name="search_address_result">Encontrar lugares</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_details_loading">A carregar os detalhes trackable...</string>
+ <string name="trackable_log_touch">Registar toque</string>
+ <string name="trackable_browser_open">Abrir no browser</string>
+ <string name="trackable_goal">Objectivo</string>
+ <string name="trackable_details">Detalhes</string>
+ <string name="trackable_image">Imagem</string>
+ <string name="trackable_code">TB-Code</string>
+ <string name="trackable_name">Nome</string>
+ <string name="trackable_type">Tipo</string>
+ <string name="trackable_owner">Dono</string>
+ <string name="trackable_spotted">Visto</string>
+ <string name="trackable_origin">Origem</string>
+ <string name="trackable_unknown">Desconhecido</string>
+ <string name="trackable_released">lançado</string>
+ <string name="trackable_touch">Toque</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navegação</string>
+ <string name="compass_title">Bússola</string>
+ <string name="use_gps">Utilizar GPS</string>
+ <string name="use_compass">Utilizar Bússola</string>
+ <string name="destination_select">Selecionar destino</string>
+ <string name="destination_set">Defenir destino</string>
+
+ <!-- license -->
+ <string name="license">Licença</string>
+ <string name="license_show">Mostrar licença</string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
new file mode 100644
index 0000000..94d948e
--- /dev/null
+++ b/res/values-sk/strings.xml
@@ -0,0 +1,502 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompas</string>
+
+ <!-- basics -->
+ <string name="cache">Skrýša</string>
+ <string name="detail">Detail</string>
+ <string name="search">Vyhľadávanie</string>
+ <string name="settings">Nastavenie</string>
+ <string name="helpers">Pomocné aplikácie</string>
+ <string name="about">O aplikácii</string>
+ <string name="helper">Chcete sa dozvedieť viac o <b>c:geo</b>?\nPozrite si manuál.</string>
+ <string name="database_error_title">Problém with databázou.</string>
+ <string name="database_error_message">c:geo sa nedokázalo spojiť s internou databázou.\nProsím, skúste spustiť c:geo trochu neskôr. Ak sa táto správa zobrazovala viac krát, otvorte Settings / Applications / c:geo a stlačte tlačidlo Clear Data. Alebo odinštalujte a nainštalujte c:geo znovu. Ospravedlňujeme sa za nepríjemnosti.</string>
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Zdieľať odkaz ku skrýši</string>
+
+ <!-- caches -->
+ <string name="all">Všetky skrýše</string>
+ <string name="all_types">Všetky typy skrýš</string>
+ <string name="traditional">Tradičná skrýša</string>
+ <string name="multi">Multi-skrýša</string>
+ <string name="mystery">Neznáma skrýša</string>
+ <string name="letterbox">Dopisná schránka</string>
+ <string name="event">Udalosť</string>
+ <string name="mega">Mega-udalosť</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">Udalosť cache in trash out</string>
+ <string name="webcam">Webcam skrýša</string>
+ <string name="virtual">Virtuálna skrýša</string>
+ <string name="wherigo">Wherigo skrýša</string>
+ <string name="lostfound">Stratené a nájdené</string>
+ <string name="ape">Skrýša projektu ape</string>
+ <string name="gchq">Ústredie groundspeaku</string>
+ <string name="gps">GPS cache exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Cieľ</string>
+ <string name="wp_stage">Časť multi-skrýše</string>
+ <string name="wp_puzzle">Otázka</string>
+ <string name="wp_pkg">Parkovisko</string>
+ <string name="wp_trailhead">Rázcestie</string>
+ <string name="wp_waypoint">Referenčný bod</string>
+
+ <!-- logs -->
+ <string name="log_found">Nález</string>
+ <string name="log_dnf">Nenájdené</string>
+ <string name="log_note">Poznámka</string>
+ <string name="log_published">Zverejnené</string>
+ <string name="log_enabled">Aktivované</string>
+ <string name="log_disabled">Deaktivované</string>
+ <string name="log_attend">Zúčastní sa</string>
+ <string name="log_attended">Zúčastnil sa</string>
+ <string name="log_retrieved">Vybratý zo skrýše</string>
+ <string name="log_grabbed">Prevzatý</string>
+ <string name="log_maintained">Udržiavaná</string>
+ <string name="log_maintenance_needed">Vyžaduje údržbu</string>
+ <string name="log_maintenance_owner">Údržba</string>
+ <string name="log_update">Zmena súradníc</string>
+ <string name="log_archived">Archivácia</string>
+ <string name="log_needs_archived">Vyžaduje archiváciu</string>
+ <string name="log_discovered">Nájdený</string>
+ <string name="log_reviewed">Poznámka kontroly</string>
+ <string name="log_tb_nothing">Bezo zmeny</string>
+ <string name="log_tb_visit">Návšteva</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_saving">Ukladanie logu</string>
+ <string name="log_clear">Vyčistiť</string>
+ <string name="log_post">Odoslať log</string>
+ <string name="log_post_rate">Odoslať log a hlasovať</string>
+ <string name="log_post_no_rate">Odoslať log a nehlasovať</string>
+ <string name="log_add">Pridať</string>
+ <string name="log_date">Dátum</string>
+ <string name="log_time">Čas</string>
+ <string name="log_date_time">Dátum a čas</string>
+ <string name="log_rating">Hlasovať</string>
+ <string name="log_no_rating">Nehlasovať</string>
+ <string name="log_stars_1">1 hviezdička</string>
+ <string name="log_stars_2">2 hviezdičky</string>
+ <string name="log_stars_3">3 hviezdičky</string>
+ <string name="log_stars_4">4 hviezdičky</string>
+ <string name="log_stars_5">5 hviezdičiek</string>
+ <string name="log_webcam">Odfotený webkamerou</string>
+ <string name="log_new_log">Log</string>
+ <string name="log_new_log_text">Text logu</string>
+ <string name="log_announcement">Oznámenie</string>
+
+ <!-- errors -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Komunikácia nezačala.</string>
+ <string name="err_parse">Zlyhalo čítanie prihlasovacej stránky.</string>
+ <string name="err_server">Zlyhalo pripojenie k serveru geocaching.com (pripojenie alebo server nefunkčný?)</string>
+ <string name="err_login">Nie sú uložené žiadne prihlasovacie údaje.</string>
+ <string name="err_login_failed">prepáčte, ale c:geo sa nemôže prihlásiť.</string>
+ <string name="err_unknown">Neznámá chyba</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>
+ <string name="err_license">Používateľ nepotvrdil súhlas s licenčnou dohodou serveru Geocaching.com, takže c:geo nemôže načítať koordináty skrýše.</string>
+ <string name="err_store">Prepáčte, c:geo nemôže uložiť skrýšu.</string>
+ <string name="err_drop">Prepáčte, c:geo nemôže zmazať skrýšu.</string>
+ <string name="err_title_problem">Problém</string>
+ <string name="err_detail_open">Prepáčte, c:geo nedokáže načítať detaily skrýše.</string>
+ <string name="err_detail_cache">Prepáčte, c:geo nedokáže načítať detaily skrýše. Je to naozaj skrýša?</string>
+ <string name="err_detail_cache_find">Prepáčte, c:geo nemôže nájsť skrýšu</string>
+ <string name="err_detail_cache_find_some">Prepáčte, c:geo nemôže nájsť požadovanú skrýšu.</string>
+ <string name="err_detail_cache_find_any">Prepáčte, c:geo nemôže nájsť žiadnu skrýšu.</string>
+ <string name="err_detail_cache_find_next">Prepáčte, c:geo nemôže nájsť ďalšiu skrýšu.</string>
+ <string name="err_detail_cache_forgot">Prepáčte, c:geo zabudlo, akú skrýšu chcete zobraziť.</string>
+ <string name="err_detail_cache_forgot_visit">Prepáčte, c:geo zabudlo, akú skrýšu ste prezerali.</string>
+ <string name="err_detail_cache_language">c:geo nemôže prečítať niektoré detaily. Prosím skontrolujte, či máte web Geocaching.com nastavený na anglický jazyk. c:geo zatiaľ bohužiaľ nedokáže prečítať iné jazyky.</string>
+ <string name="err_detail_no_spoiler">c:geo nenašlo žiadny obrázok pre túto skrýšu.</string>
+ <string name="err_detail_no_map_static">c:geo nenašlo žiadnu statickú mapu pre túto skrýšu.</string>
+ <string name="err_detail_still_removing">Ešte odstraňujem skrýšu.</string>
+ <string name="err_detail_still_saving">Ešte ukladám skrýšu.</string>
+ <string name="err_detail_still_refreshing">Ešte aktualizujem skrýšu.</string>
+ <string name="err_radar_title">Radar nie je nainštalovaný.</string>
+ <string name="err_radar_message">Táto funkcia vyžaduje aplikáciu Radar. Chcete ju nainštalovať?</string>
+ <string name="err_radar_market">Prepáčte, c:geo nedokáže spustiť Android Market a vyhľadať aplikáciu Radar.</string>
+ <string name="err_radar_generic">Prepáčte, c:geo nedokáže spustit aplikáciu Radar. Je nainštalovaná?</string>
+ <string name="err_navigation_no">Prepáčte, c:geo nemôže nájsť žiadnu podporovanú navigáciu.</string>
+ <string name="err_application_no">Prepáčte, c:geo nemôže násjť žiadnu použiteľnú aplikáciu.</string>
+ <string name="err_auth_initialize">Prepáčte, c:geo nedokázalo zahájiť autorizáciu.</string>
+ <string name="err_auth_process">Autorizácia zlyhala.</string>
+ <string name="err_cannot_log_visit">c:geo nemá dostatok informácií pre zapísanie návštevy. Prosím urobte to z kompletného detailu skrýše.</string>
+ <string name="err_init_cleared">Prepáčte, c:geo nedokázalo zmazať prihlasovacie údaje.</string>
+ <string name="err_no_chaches">Prepáčte, c:geo nedokázalo načítať skrýšu alebo skrýše.</string>
+ <string name="err_download_fail">Prepáčte, c:geo nemôže načítať skrýšu, pretože</string>
+ <string name="err_update_fail">Nepodarilo sa aktualizovať urazenú vzdialenosť.</string>
+ <string name="err_list_load_fail">c:geo nemôže načítať zoznam skrýš.</string>
+ <string name="err_store_failed">c:geo nemôže uložiť skrýšu.</string>
+ <string name="err_refresh_failed">c:geo nemôže obnoviť skrýšu.</string>
+ <string name="err_drop_failed">c:geo nemôže zmazat skrýšu.</string>
+ <string name="err_dwld_details_failed">c:geo nemôže stiahnuť detaily skrýše.</string>
+ <string name="err_dwld_details_failed_reason">c:geo nemôže načítať podrobnosti o skrýši, pretože</string>
+ <string name="err_load_descr_failed">c:geo nemôže stiahnuť popis skrýše.</string>
+ <string name="err_location_unknown">c:geo nepozná súradnice skrýše</string>
+ <string name="err_tb_display">"Prepáčte, c:geo nemôže zobraziť trackable. Je to naozaj trackable?</string>
+ <string name="err_tb_details_open">Prepáčte, c:geo nemôže otvoriť podrobnosti k trackable.</string>
+ <string name="err_tb_details_download">Prepáčte, c:geo nemôže stiahnuť podrobnosti k trackable, pretože</string>
+ <string name="err_tb_forgot">c:geo zabudlo, ktorý trackable ste chceli.</string>
+ <string name="err_tb_forgot_saw">c:geo zabudlo, ktorý trackable ste prrehliadali.</string>
+ <string name="err_tb_find">c:geo nemôže nájsť trackable.</string>
+ <string name="err_tb_find_that">c:geo nemôže nájsť toto trackable.</string>
+ <string name="err_waypoint_cache_unknown">c:geo nevie, ku ktorej skrýši chcete pridať bod trasy.</string>
+ <string name="err_waypoint_unknown">c:geo zabudlo, ktorý bod trasy chcete zobraziť.</string>
+ <string name="err_waypoint_add_failed">c:geo nemôže pridať bod trasy.</string>
+ <string name="err_waypoint_load_failed">c:geo nemôže načítať bod trasy.</string>
+ <string name="err_waypoint_delete_failed">c:geo nemôže zmazať bod trasy.</string>
+ <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ň šírku alebo dĺžku alebo vzdialenosť a smer. Môžete tiež vyplniť všetky štyri polia.</string>
+ <string name="err_point_curr_position_unavailable">c:geo stále nemá 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 smer a vzdialenosť. Uhol je uhol 0 - 360 stupňov vzhľadem k severu. Vzdialenosť s alebo bez jednotiek.</string>
+ <string name="err_point_location_error">c:geo nemôže získať polohu bodov cesty.</string>
+ <string name="err_navigation_not_found">c:geo nemôže nájsť žiadnu podporovanú navigáciu.</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_failed_server">c:geo nemohlo odeslať log, pretože server neodpovedá.</string>
+ <string name="err_log_post_failed">c:geo nemohlo odeslať log.</string>
+ <string name="err_log_post_failed_because">c:geo nemohlo odoslať log z dôvodu</string>
+ <string name="err_search_address_no_match">c:geo nenašlo žiadne zodpovedajúce miesto</string>
+ <string name="err_search_address_forgot">c:geo zabudlo adresu, kterú sa pokúšate nájsť.</string>
+ <string name="err_search_address">vyhľadávánie miest</string>
+ <string name="err_parse_lat">c:geo nemôže dopočítať šírku.</string>
+ <string name="err_parse_lon">c:geo nemôže dopočítať dĺžku.</string>
+ <string name="err_parse_bear">c:geo nemôže dopočítať smer.</string>
+ <string name="err_parse_dist">c:geo nemôže dopočítať vzdialenosť.</string>
+ <string name="warn_save_nothing">nie je nič na uloženie.</string>
+ <string name="warn_no_cache_coord">Nie je žiadna skrýša so súradnicami.</string>
+ <string name="warn_no_coordinates">Nezískané súradnice</string>
+ <string name="warn_no_keyword">žiadne kľúčové slová nenájdené</string>
+ <string name="warn_no_username">Používateľské meno nezadané.</string>
+ <string name="warn_search_help_title">Potrebujete pomoc?</string>
+ <string name="warn_search_help_address">&quot;Zadejte adresu alebo meno oblasti. Napríklad použite názov ulice \&quot;Radlicka 100, Praha, Ceska republika\&quot;, názov mesta \&quot;Berlín\&quot; alebo použite názov miesta \&quot;Yellowstone Park\&quot;.</string>
+ <string name="warn_search_help_gccode">Zadajte kód skrýše. Napríklad \&quot;GC1VCAZ\&quot;.</string>
+ <string name="warn_search_help_keyword">Zadejte slovo, ktoré je použité v názve skrýše, ktorú sa pokúšate nájsť.</string>
+ <string name="warn_search_help_user">Zadejte meno používateľa z Geocaching.com.</string>
+ <string name="warn_search_help_tb">Zadajte kód trackable. Napríklad \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">prosím, vyplňte nejaký text do logu.</string>
+ <string name="info_altitude">Súčasná nadmorská výška</string>
+ <string name="info_distance">urazená vzdialenosť</string>
+ <string name="info_distance_cleared">urazená vzdialenosť bola zmazaná</string>
+ <string name="info_since">\n(od</string>
+ <string name="info_log_posted">c:geo úspešne zaslalo log.</string>
+ <string name="info_log_saved">c:geo úspešne uložilo log.</string>
+ <string name="info_log_cleared">Log bol vyprázdnený.</string>
+ <string name="info_log_type_changed">Typ logu bol zmenený!</string>
+
+ <!-- location service -->
+ <string name="loc_last">posledná známa</string>
+ <string name="loc_net">sieť</string>
+ <string name="loc_gps">gps</string>
+ <string name="loc_sat">sat</string>
+ <string name="loc_trying">zisťujem pozíciu</string>
+ <string name="loc_no_addr">neznáma adresa</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">o aplikácii</string>
+ <string name="menu_settings">nastavenie</string>
+ <string name="menu_filter">filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">aktívna mapa</string>
+ <string name="caches_nearby_button">najbližší</string>
+ <string name="advanced_search_button">hľadanie</string>
+ <string name="stored_caches_button">uložené</string>
+ <string name="any_button">cieľ</string>
+ <string name="about_button">o aplikácii</string>
+ <string name="settings_button">nastavenie</string>
+ <string name="type">typ</string>
+ <string name="now_searching">vyhľadávam</string>
+
+ <!-- caches -->
+ <string name="caches_searching">vyhľadávanie skrýš</string>
+ <string name="caches_no_cache">žiadna skrýša</string>
+ <string name="caches_more_caches">dalšie skrýše</string>
+ <string name="caches_more_caches_no">žádne dalšie skrýše</string>
+ <string name="caches_downloading">sťahujem skrýše...\nETA:</string>
+ <string name="caches_progress_loading_title">načítavam skrýše</string>
+ <string name="caches_progress_loading_text">Skrýš uložená v prístroji</string>
+ <string name="caches_eta_ltm">menej než minútu</string>
+ <string name="caches_eta_mins">minúty</string>
+ <string name="caches_eta_min">minúta</string>
+ <string name="caches_no_caches">(žiadne skrýše)</string>
+ <string name="caches_store_offline">uložiť offline</string>
+ <string name="caches_store_selected">uložiť vybraté</string>
+ <string name="caches_stored">uložené</string>
+ <string name="caches_on_map">zobraziť na mape</string>
+ <string name="caches_select">vybrať zo zoznamu</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_nearby">blízke</string>
+ <string name="caches_drop_selected">odebrať vybraté</string>
+ <string name="caches_drop_selected_ask">Naozaj chcete zmazať vybraté skrýše z prístroja?</string>
+ <string name="caches_drop_all">odobrať všetko</string>
+ <string name="caches_drop_all_ask">Naozaj chcete zmazať všetky skrýše z prístroja?</string>
+ <string name="caches_drop_stored">odebrať uložené</string>
+ <string name="caches_refresh_selected">aktualizovať vybraté</string>
+ <string name="caches_refresh_all">aktualizovať všetko</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Opíšte text z obrázkov. Je to dôležité pre stiahnutie súradníc skrýš.</string>
+ <string name="caches_recaptcha_hint">Text z obrázku</string>
+ <string name="caches_recaptcha_continue">pokračovať</string>
+
+ <!-- about -->
+ <string name="about_changelog">zmeny</string>
+ <string name="about_donate">podpora vývoja</string>
+ <string name="about_detail">detaily</string>
+ <string name="about_donation_less">darujte\nmenej</string>
+ <string name="about_donation_more">podporte\nvývoj</string>
+ <string name="about_contributors">prispievatelia</string>
+
+ <!-- init -->
+ <string name="init_geocaching">geocaching.com</string>
+ <string name="init_gcvote">gcvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">twitter</string>
+ <string name="init_username">používateľské heslo</string>
+ <string name="init_password">heslo</string>
+ <string name="init_passvote">heslo</string>
+ <string name="init_login">skontrolovať</string>
+ <string name="init_login_popup">prihlásenie</string>
+ <string name="init_login_popup_working">prihlasovanie na geocaching.com...</string>
+ <string name="init_login_popup_ok">prihlásenie prebehlo</string>
+ <string name="init_login_popup_failed">prihlásenie neprebehlo</string>
+ <string name="init_login_popup_failed_reason">prihlásenie neprebehlo, pretože</string>
+ <string name="init_legal">poznámka</string>
+ <string name="init_go4cache_connect">pripojit k Go 4 Cache</string>
+ <string name="init_twitter_authorize">autorizovať c:geo</string>
+ <string name="init_twitter_publish">nový status pri náleze skrýše</string>
+ <string name="init_signature">podpis</string>
+ <string name="init_other">dalšie možnosti</string>
+ <string name="init_skin">svetlý skin (vyžaduje reštart)</string>
+ <string name="init_transparent">priehľadná úvodná obrazovka</string>
+ <string name="init_address">adresa na úvodnej obrazovke</string>
+ <string name="init_exclude">nezobrazovať vlastné a nájdené skrýše</string>
+ <string name="init_disabled">nezobrazovať zrušené skrýše</string>
+ <string name="init_offline">ukladať mapy pre offline použitie</string>
+ <string name="init_units">používať imperiálne jednotky vzdialenosti</string>
+ <string name="init_nav">používať Google Navigation</string>
+ <string name="init_autoload">automaticky sťahovať dlhé popisy</string>
+ <string name="init_livelist">zobrazovať smer v zozname skrýš</string>
+ <string name="init_browser">tváriť sa ako běžný webový prehliadač</string>
+ <string name="init_clear">zmazať prihlasovacie údaje</string>
+ <string name="init_cleared">c:geo zmazalo prihlasovacie údaje.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">twitter</string>
+ <string name="auth_authorize">autorizovať c:geo</string>
+ <string name="auth_start">zahájiť autorizáciu</string>
+ <string name="auth_again">znovu autorizovať</string>
+ <string name="auth_pin_hint">pin pridelený twitterom</string>
+ <string name="auth_finish">dokončiť</string>
+ <string name="auth_dialog_wait">Čakám na Twitter...</string>
+ <string name="auth_dialog_pin_title">pin kód</string>
+ <string name="auth_dialog_pin_message">Prosím, napíšte PIN kód, ktorý Vám bol pridelený Twitterom. Je potrebné pre dokončenie autorizácie.</string>
+ <string name="auth_dialog_completed">c:geo teray môže posielať správy na Váš Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">žiadna skrýša</string>
+ <string name="cache_count_one">jedna skrýša</string>
+ <string name="cache_count_more">skrýš</string>
+ <string name="cache_offline">offline</string>
+ <string name="cache_offline_refresh">obnoviť</string>
+ <string name="cache_offline_drop">zmazať</string>
+ <string name="cache_offline_store">uložiť</string>
+ <string name="cache_offline_stored">uložená v zariadení</string>
+ <string name="cache_offline_not_ready">nie je pripravená\nna použitie offline</string>
+ <string name="cache_offline_time_about">približne pred</string>
+ <string name="cache_offline_time_mins">minútami</string>
+ <string name="cache_offline_time_mins_few">niekoľkými minútami</string>
+ <string name="cache_offline_time_hour">jednou hodinou</string>
+ <string name="cache_offline_time_hours">hodinami</string>
+ <string name="cache_offline_time_days">dňnami</string>
+ <string name="cache_premium">platený účet</string>
+ <string name="cache_attributes">atribúty</string>
+ <string name="cache_inventory">inventár</string>
+ <string name="cache_log_offline">offline log</string>
+ <string name="cache_description">popis</string>
+ <string name="cache_description_long">dlhý popis</string>
+ <string name="cache_waypoints">body trasy</string>
+ <string name="cache_waypoints_add">pridat bod</string>
+ <string name="cache_hint">nápoveda</string>
+ <string name="cache_logs">logbook</string>
+ <string name="cache_dialog_loading_details">načítavam detaily skrýše...</string>
+ <string name="cache_dialog_loading_description">načítavam popis skrýše...</string>
+ <string name="cache_dialog_offline_save_title">offline</string>
+ <string name="cache_dialog_offline_save_message">Ukladám skrýšu na použitie offline...</string>
+ <string name="cache_dialog_offline_drop_title">offline</string>
+ <string name="cache_dialog_offline_drop_message">Odstraňujem skrýšu z pamäte zaríadenia...</string>
+ <string name="cache_dialog_refresh_title">aktualizáce</string>
+ <string name="cache_dialog_refresh_message">Aktualizujem detaily skrýše...</string>
+ <string name="cache_menu_navigate">navigovať</string>
+ <string name="cache_menu_compass">kompas</string>
+ <string name="cache_menu_tbt">turn-by-turn</string>
+ <string name="cache_menu_radar">radar</string>
+ <string name="cache_menu_map">zobraziť na mape</string>
+ <string name="cache_menu_map_ext">zobraziť na inej mape</string>
+ <string name="cache_menu_map_static">statické mapy</string>
+ <string name="cache_menu_map_short">mapy</string>
+ <string name="cache_menu_map_ext_short">Ext. mapy</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_spoilers">obrázky</string>
+ <string name="cache_menu_around">skrýša v okolí</string>
+ <string name="cache_menu_event">pridat do kalendára</string>
+ <string name="cache_menu_details">detaily</string>
+ <string name="cache_status">status</string>
+ <string name="cache_status_offline_log">pripravený log</string>
+ <string name="cache_status_found">nájdená</string>
+ <string name="cache_status_archived">archivovaná</string>
+ <string name="cache_status_disabled">zrušená</string>
+ <string name="cache_status_premium">iba pre platiacich použávateľov</string>
+ <string name="cache_geocode">gc kód</string>
+ <string name="cache_name">názov</string>
+ <string name="cache_type">typ</string>
+ <string name="cache_distance">vzdialenosť</string>
+ <string name="cache_difficulty">obtiažnosť</string>
+ <string name="cache_terrain">terén</string>
+ <string name="cache_rating">hodnotenie</string>
+ <string name="cache_owner">zakladateľ</string>
+ <string name="cache_hidden">skrytá</string>
+ <string name="cache_event">dátum</string>
+ <string name="cache_location">miesto</string>
+ <string name="cache_coordinates">súradnice</string>
+ <string name="cache_calendars">vyberte kalendár</string>
+ <string name="cache_spoiler_images_title">Spoiler images</string>
+ <string name="cache_spoiler_images_loading">Loading spoiler images...</string>
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">hľadanie .gpx súborov\nv</string>
+ <string name="gpx_import_loading_stored">nahrávanie skrýš z .gpx súboru\nuložených:</string>
+ <string name="gpx_import_no_files">c:geo nenašlo žiadny .gpx soubor</string>
+ <string name="gpx_import_caches_imported">skrýše importované</string>
+ <string name="gpx_import_searching">vyhľadávanie .gpx súborov</string>
+ <string name="gpx_import_loading">nahrávanie skrýš z .gpx súboru</string>
+ <string name="gpx_import_title">Import GPX</string>
+ <string name="gpx_import_title_reading_file">čítanie souboru</string>
+ <string name="gpx_import_title_searching">hľadanie</string>
+ <string name="gpx_import_title_caches_imported">výsledok</string>
+
+ <!-- event -->
+ <string name="event_success">Udalosť bola pridaná do kalendára</string>
+ <string name="event_fail">Nepodarilo sa vložiť udalosť do kalendára</string>
+
+ <!-- popup -->
+ <string name="popup_more">viac detailov</string>
+ <string name="popup_offline">offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint_title">Bod trasy</string>
+ <string name="waypoint_custom">vlastný</string>
+ <string name="waypoint_my_coordinates">aktuálna poloha</string>
+ <string name="waypoint_bearing">smer</string>
+ <string name="waypoint_distance">vzdialenosť</string>
+ <string name="waypoint_name">názov</string>
+ <string name="waypoint_edit">upraviť</string>
+ <string name="waypoint_delete">zmazať</string>
+ <string name="waypoint_edit_title">úprava bodu trasy</string>
+ <string name="waypoint_add_title">nový bod trasy</string>
+ <string name="waypoint_note">poznámka</string>
+ <string name="waypoint_save">uložiť</string>
+ <string name="waypoint_loading">načítavanie bodu trasy...</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">informovať o náleze na twitteri</string>
+
+ <!-- map -->
+ <string name="map_map">Mapa</string>
+ <string name="map_live">aktívna mapa</string>
+ <string name="map_view_satellite">satelitný pohľad</string>
+ <string name="map_view_map">pohľad do mapy</string>
+ <string name="map_trail_show">zobraziť záznam trasy</string>
+ <string name="map_trail_hide">skryť záznam trasy</string>
+ <string name="map_live_enable">povoliť aktuálnu polohu</string>
+ <string name="map_live_disable">zakázať aktuálnu polohu</string>
+ <string name="map_static_title">statické mapy</string>
+ <string name="map_static_loading">načítavanie statických máp...</string>
+
+ <!-- search -->
+ <string name="search_coordinates">súradnice</string>
+ <string name="search_coordinates_button">hľadať podľa súradníc</string>
+ <string name="search_address">adresa</string>
+ <string name="search_address_button">hľadať podľa adresy</string>
+ <string name="search_gc">geokód</string>
+ <string name="search_gc_button">hľadať podľa geokódu</string>
+ <string name="search_kw">kľúčové slová</string>
+ <string name="search_kw_prefill">kľúčové slová</string>
+ <string name="search_kw_button">hľadať podľa kľúčového slova</string>
+ <string name="search_kw_caches">skrýše podľa kľúčového slova</string>
+ <string name="search_caches_found_by">skrýše nájdené</string>
+ <string name="search_caches_hidden_by">skrýše skryté</string>
+ <string name="search_fbu">nájdené používateľom</string>
+ <string name="search_fbu_prefill">používateľské meno</string>
+ <string name="search_fbu_button">hľadať podľa nálezcu</string>
+ <string name="search_hbu">skryté používateľom</string>
+ <string name="search_hbu_prefill">vlastník</string>
+ <string name="search_hbu_button">hľadať podľa vlastníka</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">identifikácia trackable</string>
+ <string name="search_tb_button">vyhľadávanie trackable</string>
+ <string name="search_destination">cieľ</string>
+ <string name="search_direction_rel">od tejto polohy</string>
+ <string name="search_lat">šírka</string>
+ <string name="search_lon">dĺžka</string>
+ <string name="search_caches">hľadať skrýše</string>
+ <string name="search_caches_near">skrýše v okolí</string>
+ <string name="search_address_started">vyhľadávanie miest</string>
+ <string name="search_address_result">miesta nájdené</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">Načítavanie detailov trackable...</string>
+ <string name="trackable_log_touch">Hlásenie zhliadnutia</string>
+ <string name="trackable_browser_open">Otvoriť v prehliadači</string>
+ <string name="trackable_goal">Cieľ</string>
+ <string name="trackable_details">Detaily</string>
+ <string name="trackable_image">Obrázok</string>
+ <string name="trackable_code">TB-kód</string>
+ <string name="trackable_name">Názov</string>
+ <string name="trackable_type">Typ</string>
+ <string name="trackable_owner">Vlastník</string>
+ <string name="trackable_spotted">Spotted</string>
+ <string name="trackable_origin">Pôvod</string>
+ <string name="trackable_unknown">Neznámy</string>
+ <string name="trackable_released">Vypustenie</string>
+ <string name="trackable_touch">Dotyk</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigácia</string>
+ <string name="compass_title">Kompas</string>
+ <string name="use_gps">Použiť GPS</string>
+ <string name="use_compass">Použiť kompas</string>
+ <string name="destination_select">Vyberte cieľ</string>
+ <string name="destination_set">Cieľ nastavený</string>
+
+ <!-- license -->
+ <string name="license">Licencia</string>
+ <string name="license_show">Zobraziť licenciu</string>
+ <string name="license_dismiss">Zamietnutie</string>
+
+ <!-- next things -->
+ <string name="legal_note">Pred používaním služieb serveru geocaching.com je potrebné súhlasiť s <a href="http://www.geocaching.com/about/disclaimer.aspx">licenčnou dohodou Groundspeaku</a>.</string>
+ <string name="author">autor: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">podpora: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">web: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</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="about_go4cache">Služba<b>Go 4 cache</b>umožňuje sledovať v reálnom čase ostatných cacherov na mape (v <b>c:geo</b>alebo v prehliadači). Môžete se tak pozrieť napríklad na to, akú skrýšu práve hľedajú. Pripojením ku službe <b>Go 4 cache</b>umožníte aplikácii <b>c:geo</b>zveřejňovať Vašu aktuálnu polohu (iba pokiaľ <b>c:geo</b>beží).</string>
+ <string name="about_twitter">Chcete, aby <b>c:geo</b>napísalo na Váš Twitter zakaždým, keď zapíšete nález skrýše? </string>
+ <string name="about_auth_1">Pomocou nasledujúceho procesu môžete aplikácii <b>c:geo</b>umožniť odesielanie príspevkov na Váš Twitter. </string>
+ <string name="about_auth_2">Tapnutím na tlačidlo "zahájiť autorizáciu" celý proces začne. Tento proces otvorí webovú stránku Twitteru, kde sa budete musieť prihlásiť a tlačidlom Accept potom umožniť aplikácii <b>c:geo</b>prístup k Vášmu Twitteru. Twitter Vám pridelí PIN kód pokiaľ tapnete na Accept. Tento kód skopírujte a vložte do aplikácie <b>c:geo</b>. A potvrďte. To je všetko.</string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
new file mode 100644
index 0000000..c32b9c9
--- /dev/null
+++ b/res/values-sv/strings.xml
@@ -0,0 +1,612 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo kompass</string>
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detaljer</string>
+ <string name="search">Sök</string>
+ <string name="settings">Inställningar</string>
+ <string name="helpers">Program att installera</string>
+ <string name="about">Om c:geo</string>
+ <string name="helper">Vill du lära dig mer om <b>c:geo</b>?\nLäs manualen (på engelska).</string>
+ <string name="database_error_title">Problem med databasen</string>
+ <string name="database_error_message">c:geo misslyckades att ansluta till den interna databasen.\nVänligen försök att starta c:geo igen om en liten stund. Om detta meddelande fortsätter att visas bör du gå till Telefoninställningar / Program / c:geo och välja att Rensa data. Om inte detta hjälper får du tyvärr avinstallera och installera c:geo igen. Vi ber om ursäkt för detta!</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Skicka cachens länk via</string>
+
+ <!-- caches -->
+ <string name="all">Alla cacher</string>
+ <string name="all_types">Alla typer av cacher</string>
+ <string name="traditional">Traditionell cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Mysterie cache</string>
+ <string name="letterbox">Letterbox hybrid</string>
+ <string name="event">Event cache</string>
+ <string name="mega">Mega-event cache</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">Cache in trash out event</string>
+ <string name="webcam">Webcam cache</string>
+ <string name="virtual">Virtuell cache</string>
+ <string name="wherigo">Wherigo cache</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Projekt APE cache</string>
+ <string name="gchq">Groundspeak HQ</string>
+ <string name="gps">GPS cache utställning</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Slutlig plats</string>
+ <string name="wp_stage">Delsteg för multi-cache</string>
+ <string name="wp_puzzle">Fråga att besvara</string>
+ <string name="wp_pkg">Parkeringsplats</string>
+ <string name="wp_trailhead">Stigstart</string>
+ <string name="wp_waypoint">Referensplats</string>
+
+ <!-- logs -->
+ <string name="log_found">Hittad</string>
+ <string name="log_dnf">Hittade inte</string>
+ <string name="log_note">Kommentar</string>
+ <string name="log_published">Publicerad</string>
+ <string name="log_enabled">Aktiverad</string>
+ <string name="log_disabled">Inaktiverad</string>
+ <string name="log_attend">Kommer att deltaga</string>
+ <string name="log_attended">Deltog</string>
+ <string name="log_retrieved">Hämtade från</string>
+ <string name="log_placed">Lämnade i</string>
+ <string name="log_grabbed">Tagen från annan</string>
+ <string name="log_maintained">Underhåll utfört</string>
+ <string name="log_maintenance_needed">Behöver underhåll</string>
+ <string name="log_maintenance_owner">Underhåll</string>
+ <string name="log_update">Uppdaterade koordinaterna</string>
+ <string name="log_archived">Arkiverad</string>
+ <string name="log_needs_archived">Behöver arkiveras</string>
+ <string name="log_discovered">Såg den</string>
+ <string name="log_reviewed">Meddelande till reviewern</string>
+ <string name="log_taken">Besökte</string>
+ <string name="log_tb_nothing">Gör inget</string>
+ <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_saving">Sparar logg...</string>
+ <string name="log_clear">Rensa</string>
+ <string name="log_post">Posta logg</string>
+ <string name="log_post_rate">Posta logg &amp; ge betyget</string>
+ <string name="log_post_no_rate">Posta logg utan betyg</string>
+ <string name="log_add">Lägg till</string>
+ <string name="log_date">Datum</string>
+ <string name="log_time">Tid</string>
+ <string name="log_date_time">Datum &amp; tid</string>
+ <string name="log_rating">Betyg</string>
+ <string name="log_no_rating">Inget betyg</string>
+ <string name="log_stars_1">1 stjärna</string>
+ <string name="log_stars_2">2 stjärnor</string>
+ <string name="log_stars_3">3 stjärnor</string>
+ <string name="log_stars_4">4 stjärnor</string>
+ <string name="log_stars_5">5 stjärnor</string>
+ <string name="log_webcam">Foto taget med Webcam</string>
+ <string name="log_new_log">Logga</string>
+ <string name="log_new_log_text">Loggtext</string>
+ <string name="log_announcement">Kungörelse</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Kommunikationen har inte påbörjats</string>
+ <string name="err_parse">misslyckades analysera inloggningssidan</string>
+ <string name="err_server">misslyckades att ansluta till geocaching.com (servern eller anslutningen nere?)</string>
+ <string name="err_login">Inloggningsinformationen ej sparad</string>
+ <string name="err_login_failed">Tyvärr, c:geo kan inte logga in.</string>
+ <string name="err_unknown">okänt fel</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>
+ <string name="err_license">användaren inte har bekräftat licensavtalet med geocaching.com</string>
+ <string name="err_store">Tyvärr, c:geo kan inte spara cachen.</string>
+ <string name="err_drop">Tyvärr, c:geo kan inte ta bort cachen.</string>
+ <string name="err_title_problem">Problem</string>
+ <string name="err_detail_open">Tyvärr, c:geo kan inte visa detaljer om geocachen.</string>
+ <string name="err_detail_cache">Tyvärr, c:geo kan inte visa den geocache du önskar. Är det verkligen en geocache?</string>
+ <string name="err_detail_cache_find">Tyvärr, c:geo kan inte hitta geocache</string>
+ <string name="err_detail_cache_find_some">Tyvärr, c:geo kan inte hitta geocachen.</string>
+ <string name="err_detail_cache_find_any">Tyvärr, c:geo kan inte hitta någon geocache.</string>
+ <string name="err_detail_cache_find_next">Tyvärr, c:geo kan inte hitta nästa geocache.</string>
+ <string name="err_detail_cache_forgot">Tyvärr, c:geo glömde vilken geocache du ville se.</string>
+ <string name="err_detail_cache_forgot_visit">Tyvärr, c:geo glömde vilken cache tittade på.</string>
+ <string name="err_detail_cache_language">c:geo kan inte läsa vissa detaljer om cachen. Vänligen kontrollera att geocaching.com hemsidan är inställd för att visas på Engelska. Tyvärr kan inte c:geo förstå andra språk.</string>
+ <string name="err_detail_no_spoiler">c:geo hittade inga spoiler bilder för den här cachen.</string>
+ <string name="err_detail_no_map_static">c:geo hittade inga sparade kartor för denna cache.</string>
+ <string name="err_detail_not_load_map_static">Tyvärr, c:geo misslyckades att ladda sparade kartor.</string>
+ <string name="err_detail_still_removing">Fortsätter att ta bort denna cache.</string>
+ <string name="err_detail_still_saving">Fortsätter att spara denna cache.</string>
+ <string name="err_detail_still_refreshing">Fortsätter att ladda om denna cache.</string>
+ <string name="err_radar_title">Radar är inte installerat.</string>
+ <string name="err_radar_message">Den här funktionen kräver programmet Radar. Vill du installera det?</string>
+ <string name="err_radar_market">c:geo kan inte öppna Android Market för att leta efter programmet Radar.</string>
+ <string name="err_radar_generic">Tyvärr, c:geo kan inte starta programmet Radar. Är det verkligen installerat?</string>
+ <string name="err_navigation_no">c:geo kan inte hitta något stöd för navigering.</string>
+ <string name="err_application_no">c:geo kan inte hitta något lämpligt program.</string>
+ <string name="err_auth_initialize">Tyvärr, c:geo misslyckades att starta inloggningsproceduren.</string>
+ <string name="err_auth_process">Inloggningsproceduren misslyckades.</string>
+ <string name="err_cannot_log_visit">c:geo har inte tillräckligt med information för att logga ditt besök. Vänligen försök igen från vyn men all information om cachen.</string>
+ <string name="err_init_cleared">Tyvärr, c:geo kan inte rensa inloggningsinställningarna.</string>
+ <string name="err_no_chaches">Tyvärr, c:geo misslyckades att ladda cachen eller cacherna.</string>
+ <string name="err_download_fail">Tyvärr, c:geo misslyckades att ladda ner cacher pga</string>
+ <string name="err_update_fail">Misslyckades att uppdatera rest sträcka.</string>
+ <string name="err_list_load_fail">Tyvärr, c:geo misslyckades att ladda listan med cacher.</string>
+ <string name="err_store_failed">Tyvärr, c:geo kan inte spara geocachen.</string>
+ <string name="err_refresh_failed">Tyvärr, c:geo kan inte uppdatera geocachen.</string>
+ <string name="err_drop_failed">Tyvärr, c:geo kan inte radera geocachen.</string>
+ <string name="err_dwld_details_failed">Tyvärr, c:geo misslyckades att ladda detaljer.</string>
+ <string name="err_dwld_details_failed_reason">Tyvärr, c:geo misslyckades att ladda detaljer pga</string>
+ <string name="err_load_descr_failed">Tyvärr, c:geo kan inte ladda beskrivningen.</string>
+ <string name="err_location_unknown">c:geo har inte koordinaterna för cachen.</string>
+ <string name="err_manual_title">Manualen är inte installerad.</string>
+ <string name="err_manual_message">Manualen för c:geo finns inte i din enhet. Vill du installera den?</string>
+ <string name="err_manual_market">c:geo kan inte öppna Android Market för att söka efter Manualen till c:geo.</string>
+
+ <string name="err_tb_display">"Tyvärr, c:geo kan inte visa den trackable du önskar. Är den verkligen trackable?</string>
+ <string name="err_tb_details_open">Tyvärr, c:geo kan inte öppna detaljer för trackable.</string>
+ <string name="err_tb_details_download">Tyvärr, c:geo misslyckades att ladda ner detaljer för trackable pga</string>
+ <string name="err_tb_forgot">Tyvärr, c:geo glömde vilken trackable önskade.</string>
+ <string name="err_tb_forgot_saw">Tyvärr, c:geo glömde vilken trackable du såg.</string>
+ <string name="err_tb_find">Tyvärr, c:geo kunde inte hitta trackable</string>
+ <string name="err_tb_find_that">Tyvärr, c:geo kan inte hitta önskad trackable.</string>
+
+ <string name="err_waypoint_cache_unknown">Tyvärr, c:geo vet inte till vilken cache du vill lägga till en punkt.</string>
+ <string name="err_waypoint_unknown">Tyvärr, c:geo glömde vilken punkt du ville visa.</string>
+ <string name="err_waypoint_add_failed">Tyvärr, c:geo misslyckades att lägga till din punkt.</string>
+ <string name="err_waypoint_load_failed">Tyvärr, c:geo misslyckades att ladda punkten.</string>
+ <string name="err_waypoint_delete_failed">Tyvärr, c:geo kan inte ta bort punkten.</string>
+ <string name="err_point_unknown_position">Tyvärr, c:geo kan 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_point_location_error">Tyvärr, c:geo kan inte få fram platsen för din punkt.</string>
+ <string name="err_navigation_not_found">c:geo kan inte hitta något sätt att navigera.</string>
+
+ <string name="err_log_load_data">Tyvärr, c:geo kan inte ladda information som krävs för att logga ditt besök.</string>
+ <string name="err_log_load_data_again">Tyvärr, c:geo kan inte ladda information som krävs för att logga ditt besök. Försöker igen.</string>
+ <string name="err_log_load_data_still">c:geo laddar fortfarande data för att kunna posta loggen. Vänligen vänta en stund till.</string>
+ <string name="err_log_failed_server">Tyvärr, c:geo misslyckades att posta loggen eftersom servern inte svarade.</string>
+ <string name="err_log_post_failed">Tyvärr, c:geo misslyckades att posta loggen.</string>
+ <string name="err_log_post_failed_because">Tyvärr, c:geo misslyckades att posta loggen pga </string>
+
+ <string name="err_search_address_no_match">Tyvärr, c:geo hittade ingen plats som stämde.</string>
+ <string name="err_search_address_forgot">Tyvärr, c:geo glömde adressen du sökte efter.</string>
+ <string name="err_search_address">Söker efter platser</string>
+ <string name="err_parse_lat">Tyvärr, c:geo kan inte tolka latitud.</string>
+ <string name="err_parse_lon">Tyvärr, c:geo kan inte tolka longitud.</string>
+ <string name="err_parse_bear">Tyvärr, c:geo kan inte tolka riktning.</string>
+ <string name="err_parse_dist">Tyvärr, c:geo kan inte tolka avstånd.</string>
+
+ <string name="warn_save_nothing">Det finns inget att spara.</string>
+ <string name="warn_no_cache_coord">Det finns inga koordinater för cachen.</string>
+ <string name="warn_no_coordinates">Inga koordinater angivna.</string>
+ <string name="warn_no_keyword">Inget nyckelord angett.</string>
+ <string name="warn_no_username">Inget användarnamn angett.</string>
+ <string name="warn_search_help_title">Tips!</string>
+ <string name="warn_search_help_address">"Ange adress eller namn på en plats. Använd tex gatunamn \"Kungsgatan 10, Stockholm\", namn på ort \"Malmö\" eller annat sorts namn \"Avenyn\".</string>
+ <string name="warn_search_help_gccode">Ange geocachens kod. Tex \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Ange ett ord som du tror finns i titeln på cachen du söker.</string>
+ <string name="warn_search_help_user">Ange en användare på Geocaching.com.</string>
+ <string name="warn_search_help_tb">Ange koden för en trackable. Tex \"TB29QMZ\".</string>
+
+ <string name="warn_log_text_fill">Vänligen skriv någon text i loggen.</string>
+
+ <string name="info_altitude">Nuvarande höjd</string>
+ <string name="info_distance">Rest sträcka</string>
+ <string name="info_distance_cleared">Rest sträcka har rensats.</string>
+ <string name="info_since">\n(sedan </string>
+
+ <string name="info_log_posted">c:geo har postat din logg.</string>
+ <string name="info_log_saved">c:geo har sparat din logg.</string>
+ <string name="info_log_cleared">Loggen har rensats.</string>
+ <string name="info_log_type_changed">Typen av logg har ändrats!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Senast kända</string>
+ <string name="loc_net">Nätverk</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Försöker hitta plats</string>
+ <string name="loc_no_addr">Okänd adress</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">Om c:geo</string>
+ <string name="menu_helpers">Tilläggsprogram</string>
+ <string name="menu_settings">Inställningar</string>
+ <string name="menu_history">Loggade cacher</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live karta</string>
+ <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="about_button">Om</string>
+ <string name="settings_button">Inställningar</string>
+ <string name="type">Typ</string>
+ <string name="now_searching">Söker</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Söker efter cacher</string>
+ <string name="caches_no_cache">Det finns ingen cache</string>
+ <string name="caches_more_caches">Ladda fler cacher</string>
+ <string name="caches_more_caches_no">Inga fler cacher att ladda</string>
+ <string name="caches_more_caches_loading">Laddar fler cacher...</string>
+ <string name="caches_downloading">Laddar ner cacher...\nTid kvar: </string>
+ <string name="caches_progress_loading_title">Laddar cacher</string>
+ <string name="caches_progress_loading_text">Cacher sparade i enheten</string>
+ <string name="caches_eta_ltm">mindre än en minut</string>
+ <string name="caches_eta_mins"> minuter</string>
+ <string name="caches_eta_min"> minut</string>
+ <string name="caches_no_caches"> (inga cacher)</string>
+ <string name="caches_store_offline">Spara för Offline</string>
+ <string name="caches_store_selected">Spara valda</string>
+ <string name="caches_stored">Sparade cacher</string>
+ <string name="caches_history">Senast loggade cacher</string>
+ <string name="caches_on_map">Visa på karta</string>
+ <string name="caches_sort">Sortering</string>
+ <string name="caches_sort_title">Sortera efter</string>
+ <string name="caches_sort_distance">avstånd</string>
+ <string name="caches_sort_difficulty">svårighet</string>
+ <string name="caches_sort_terrain">terräng</string>
+ <string name="caches_sort_size">storlek</string>
+ <string name="caches_sort_favorites">favoriter</string>
+ <string name="caches_sort_name">namn</string>
+ <string name="caches_sort_gccode">GC-kod (ålder)</string>
+ <string name="caches_sort_rating">betyg (GC-vote)</string>
+ <string name="caches_sort_vote">betyg (eget)</string>
+ <string name="caches_sort_inventory">antal trackable</string>
+ <string name="caches_select">Välj från lista</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_drop_selected">Ta bort valda</string>
+ <string name="caches_drop_selected_ask">Vill du ta bort valda cacher från enheten?</string>
+ <string name="caches_drop_all">Ta bort alla</string>
+ <string name="caches_drop_all_ask">Vill du ta bort alla cacher från enheten?</string>
+ <string name="caches_drop_stored">Ta bort sparade</string>
+ <string name="caches_drop_progress">Tar bort cacher</string>
+ <string name="caches_refresh_selected">Uppdatera valda</string>
+ <string name="caches_refresh_all">Uppdatera alla</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Skriv texten som syns i bilden. Det krävs för att hämta koordinaterna för cacherna i listan. Det går att fortsätta ändå (men med sämre funktionalitet).</string>
+ <string name="caches_recaptcha_hint">Text från bilden</string>
+ <string name="caches_recaptcha_continue">Fortsätt</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">Listor</string>
+ <string name="list_menu_create">Skapa en ny lista</string>
+ <string name="list_menu_drop">Ta bort den här listan</string>
+ <string name="list_menu_change">Byt lista</string>
+ <string name="list_title">Välj en lista</string>
+ <string name="list_inbox">Sparade</string>
+ <string name="list_wpt">Punkter</string>
+ <string name="list_dialog_create_title">Ny lista</string>
+ <string name="list_dialog_create">Skapa</string>
+ <string name="list_dialog_cancel">Avbryt</string>
+ <string name="list_dialog_create_ok">Den nya listan har skapats</string>
+ <string name="list_dialog_create_err">c:geo misslyckades med att skapa den nya listan</string>
+ <string name="list_dialog_remove_title">Ta bort lista</string>
+ <string name="list_dialog_remove_description">Vill du ta bort den här listan? Alla cacher som finns i listan kommer att flyttas till \"Sparade\".</string>
+ <string name="list_dialog_remove">Ta bort</string>
+ <string name="list_dialog_remove_ok">Listan har tagits bort</string>
+ <string name="list_dialog_remove_err">c:geo misslyckades med att ta bort listan</string>
+
+ <!-- about -->
+ <string name="about_changelog">Historik</string>
+ <string name="about_donate">Donera</string>
+ <string name="about_detail">Detaljer</string>
+ <string name="about_donation_less">Donera\nlite</string>
+ <string name="about_donation_more">Donera\nutveckling</string>
+ <string name="about_contributors">Medarbetare</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Användare</string>
+ <string name="init_password">Lösenord</string>
+ <string name="init_passvote">Lösenord</string>
+ <string name="init_login">Testa inloggning</string>
+ <string name="init_login_popup">Inloggning</string>
+ <string name="init_login_popup_working">Testar inloggning mot geocaching.com...</string>
+ <string name="init_login_popup_ok">Inloggning ok.</string>
+ <string name="init_login_popup_failed">Inloggning misslyckades.</string>
+ <string name="init_login_popup_failed_reason">Inloggning misslyckades pga </string>
+ <string name="init_legal">Legal kommentar</string>
+ <string name="init_go4cache_connect">Anslut till Go 4 Cache</string>
+ <string name="init_twitter_authorize">Inställningar för Twitter</string>
+ <string name="init_twitter_publish">Publicera status när en cache hittats</string>
+ <string name="init_signature">Signatur</string>
+ <string name="init_signature_help_button">Hjälp</string>
+ <string name="init_signature_help_title">Tips och tricks</string>
+ <string name="init_signature_help_text">Skriv den signatur som du vill använda i dina loggtexter.\nDet finns några speciella texter som kan användas och som expanderas när signaturen läggs in: [DATE] , [TIME], [USER] &amp; [NUMBER].</string>
+ <string name="init_languages">Översättning</string>
+ <string name="init_languages_description">Vilka språk förstår du (och som därmed inte behöver översättas)? Ange språkkoder i form av två tecken.</string>
+ <string name="init_languages_hint">en sv de fr es no da fi</string>
+ <string name="init_translate">Översätt beskrivning &amp; tips/hint</string>
+ <string name="init_other">Övriga inställningar</string>
+ <string name="init_skin">Vitt skal (kräver omstart av c:geo)</string>
+ <string name="init_transparent">Transparent huvudmeny</string>
+ <string name="init_address">Visa adress på huvudskärmen</string>
+ <string name="init_captcha">Visa CAPTCHA (robotfällor) vid behov</string>
+ <string name="init_useenglish">Använd engelska i c:geo (kräver omstart)</string>
+ <string name="init_exclude">Dölj egna och hittade cacher</string>
+ <string name="init_disabled">Dölj inaktiva cacher</string>
+ <string name="init_offline">Spara kartor för användning offline</string>
+ <string name="init_units">Använd amerikanska enheter för avstånd</string>
+ <string name="init_nav">Använd Google Navigering</string>
+ <string name="init_autoload">Ladda full beskrivning automatiskt</string>
+ <string name="init_livelist">Visa riktning till cacher i listan</string>
+ <string name="init_browser">Identifiera c:geo som normal webbläsare</string>
+ <string name="init_altitude">Höjd justering</string>
+ <string name="init_altitude_description">Det är möjligt att justera höjden över havet om din GPS visar fel. Detta görs med ett positivt eller negativt tal, angivet i meter.</string>
+ <string name="init_clear">Rensa inloggningsinfo</string>
+ <string name="init_cleared">c:geo har rensat inloggningsinformationen</string>
+ <string name="init_backup">Säkerhetskopiering</string>
+ <string name="init_backup_backup">Kopiera</string>
+ <string name="init_backup_note">Med knapparna ovan kan du säkerhetskopiera eller återställa databasen som innehåller cacher och punkter (waypoints). Inställningar (såsom användarnamn och lösenord) kopieras inte.</string>
+ <string name="init_backup_restore">Återställ</string>
+ <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_restore_success">Återställning klar.</string>
+ <string name="init_restore_failed">Återställningen misslyckades.</string>
+ <string name="init_backup_last">Tillgänglig kopia från</string>
+ <string name="init_backup_last_no">Det finns ingen säkerhetskopia.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Koppla c:geo mot Twitter</string>
+ <string name="auth_start">Påbörja koppling mot Twitter</string>
+ <string name="auth_again">Påbörja koppling mot Twitter igen</string>
+ <string name="auth_pin_hint">PIN erhållen från Twitter</string>
+ <string name="auth_finish">Bekräfta PIN</string>
+ <string name="auth_dialog_wait">Väntar på Twitter...</string>
+ <string name="auth_dialog_pin_title">PIN kod</string>
+ <string name="auth_dialog_pin_message">Vänligen skriv in PIN koden du fick på Twitters hemsida. Den krävs för att slutföra kopplingen.</string>
+ <string name="auth_dialog_completed">c:geo är nu godkänd att posta på Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">Ingen cache</string>
+ <string name="cache_count_one">En cache</string>
+ <string name="cache_count_more">cacher</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Uppdatera</string>
+ <string name="cache_offline_drop">Radera</string>
+ <string name="cache_offline_store">Spara</string>
+ <string name="cache_offline_stored">Sparad i enheten</string>
+ <string name="cache_offline_not_ready">Inte redo\nför användning offline</string>
+ <string name="cache_offline_time_about">för</string>
+ <string name="cache_offline_time_mins">minuter sedan</string>
+ <string name="cache_offline_time_mins_few">för några minuter sedan</string>
+ <string name="cache_offline_time_hour">en timme sedan</string>
+ <string name="cache_offline_time_hours">timmar sedan</string>
+ <string name="cache_offline_time_days">dagar sedan</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Attribut</string>
+ <string name="cache_inventory">Innehåll</string>
+ <string name="cache_log_offline">Offline logg</string>
+ <string name="cache_description">Beskrivning</string>
+ <string name="cache_description_long">Lång beskrivning</string>
+ <string name="cache_waypoints">Punkter</string>
+ <string name="cache_waypoints_add">Lägg till punkt</string>
+ <string name="cache_hint">Tips</string>
+ <string name="cache_logs">Loggbok</string>
+ <string name="cache_dialog_loading_details">Laddar detaljer om cachen...</string>
+ <string name="cache_dialog_loading_description">Laddar beskrivning om cachen...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Sparar cachen för användning offline...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Tar bort cachen från enhetens minne...</string>
+ <string name="cache_dialog_refresh_title">Uppdatera</string>
+ <string name="cache_dialog_refresh_message">Uppdaterar detaljer om cachen...</string>
+ <string name="cache_menu_navigate">Navigera</string>
+ <string name="cache_menu_compass">Kompass</string>
+ <string name="cache_menu_tbt">Sväng-för-sväng</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Visa på karta</string>
+ <string name="cache_menu_map_static">Sparade kartor</string>
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_ext">Visa på extern karta</string>
+ <string name="cache_menu_map_short">Kartor</string>
+ <string name="cache_menu_map_ext_short">Ext. karta</string>
+ <string name="cache_menu_browser">Öppna i webbläsare</string>
+ <string name="cache_menu_visit">Logga besök</string>
+ <string name="cache_menu_spoilers">Spoiler bilder</string>
+ <string name="cache_menu_around">Cacher i närheten</string>
+ <string name="cache_menu_event">Lägg till i kalender</string>
+ <string name="cache_menu_details">Detaljer</string>
+ <string name="cache_menu_share">Skicka länk</string>
+ <string name="cache_menu_move_list">Flytta till annan lista</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Sparad logg</string>
+ <string name="cache_status_found">Hittad</string>
+ <string name="cache_status_archived">Arkiverad</string>
+ <string name="cache_status_disabled">Inaktiverad</string>
+ <string name="cache_status_premium">Enbart för Premium medlemmar</string>
+ <string name="cache_geocode">GC-kod</string>
+ <string name="cache_name">Namn</string>
+ <string name="cache_type">Typ</string>
+ <string name="cache_distance">Avstånd</string>
+ <string name="cache_difficulty">Svårighet</string>
+ <string name="cache_terrain">Terräng</string>
+ <string name="cache_rating">Betyg</string>
+ <string name="cache_rating_of">av</string>
+ <string name="cache_favourite">Favorit</string>
+ <string name="cache_owner">Ägare</string>
+ <string name="cache_hidden">Gömd</string>
+ <string name="cache_event">Datum</string>
+ <string name="cache_location">Plats</string>
+ <string name="cache_coordinates">Koordinater</string>
+ <string name="cache_coordinates_no">Cachen saknar koordinater.</string>
+ <string name="cache_elevation">Höjd</string>
+ <string name="cache_calendars">Välj kalender</string>
+ <string name="cache_spoiler_images_title">Spoiler bilder</string>
+ <string name="cache_spoiler_images_loading">Laddar spoiler bilder...</string>
+ <string name="cache_log_types">Loggtyper</string> <!-- Since: 2.10 RC2 -->
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Söker efter .gpx filer\ni</string>
+ <string name="gpx_import_loading_stored">Laddar cacher från .gpx fil\nSparat:</string>
+ <string name="gpx_import_no_files">Tyvärr, c:geo hittade ingen .gpx fil.</string>
+ <string name="gpx_import_caches_imported">cacher importerade</string>
+ <string name="gpx_import_searching">Söker efter .gpx filer</string>
+ <string name="gpx_import_loading">Laddar cacher från .gpx fil</string>
+ <string name="gpx_import_title">Importera GPX</string>
+ <string name="gpx_import_title_reading_file">Läser fil</string>
+ <string name="gpx_import_title_searching">Söker</string>
+ <string name="gpx_import_title_caches_imported">Resultat</string>
+
+ <!-- event -->
+ <string name="event_success">Event tillagt i kalender</string>
+ <string name="event_fail">Misslyckades att lägga till event i kalender</string>
+
+ <!-- popup -->
+ <string name="popup_more">Mer information</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint">Punkt</string>
+ <string name="waypoint_title">Punkt</string>
+ <string name="waypoint_custom">Egen</string>
+ <string name="waypoint_my_coordinates">Mina koordinater</string>
+ <string name="waypoint_bearing">Riktning</string>
+ <string name="waypoint_distance">Avstånd</string>
+ <string name="waypoint_name">Namn</string>
+ <string name="waypoint_edit">Redigera</string>
+ <string name="waypoint_delete">Ta bort</string>
+ <string name="waypoint_edit_title">Redigera punkt</string>
+ <string name="waypoint_add_title">Lägg till punkt</string>
+ <string name="waypoint_note">Kommentar</string>
+ <string name="waypoint_save">Spara</string>
+ <string name="waypoint_loading">Laddar punkt...</string>
+ <string name="waypoint_unknown_coordinates">Koordinaterna ogiltiga</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Skicka att du hittat till Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Karta</string>
+ <string name="map_live">Live karta</string>
+ <string name="map_view_satellite">Satellitvy</string>
+ <string name="map_view_map">Kartvy</string>
+ <string name="map_trail_show">Visa spår</string>
+ <string name="map_trail_hide">Dölj spår</string>
+ <string name="map_circles_show">Visa cirklar</string>
+ <string name="map_circles_hide">Dölj cirklar</string>
+ <string name="map_live_enable">Aktivera live</string>
+ <string name="map_live_disable">Inaktivera live</string>
+ <string name="map_static_title">Sparade kartor</string>
+ <string name="map_static_loading">Laddar sparade kartor...</string>
+
+ <!-- search -->
+ <string name="search_bar_hint">Sök cache/TB</string>
+ <string name="search_bar_desc">Cache (GC-kod, nyckelord), Trackable (TB-kod)</string>
+ <string name="search_coordinates">Koordinater</string>
+ <string name="search_coordinates_button">Sök med koordinater</string>
+ <string name="search_address">Adress</string>
+ <string name="search_address_button">Sök med adress</string>
+ <string name="search_gc">GC-kod</string>
+ <string name="search_gc_button">Sök med GC-kod</string>
+ <string name="search_kw">Nyckelord</string>
+ <string name="search_kw_prefill">Nyckelord</string>
+ <string name="search_kw_button">Sök med nyckelord</string>
+ <string name="search_kw_caches">Cacher med nyckelord</string>
+ <string name="search_caches_found_by">Cacher hittade av</string>
+ <string name="search_caches_hidden_by">Cacher gömda av</string>
+ <string name="search_fbu">Hittad av användare</string>
+ <string name="search_fbu_prefill">Användare</string>
+ <string name="search_fbu_button">Sök baserat på hittare</string>
+ <string name="search_hbu">Gömd av användare</string>
+ <string name="search_hbu_prefill">Ägare</string>
+ <string name="search_hbu_button">Sök baserat på ägare</string>
+ <string name="search_tb">Trackables</string>
+ <string name="search_tb_hint">Identifiering av trackable</string>
+ <string name="search_tb_button">Sök efter trackable</string>
+ <string name="search_destination">Mål</string>
+ <string name="search_direction_rel">Från min plats</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Sök efter cacher</string>
+ <string name="search_caches_near">Cacher nära</string>
+ <string name="search_address_started">Söker efter platser</string>
+ <string name="search_address_result">Hittade platser</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">Laddar detaljer om trackable...</string>
+ <string name="trackable_log_touch">Logga</string>
+ <string name="trackable_browser_open">Öppna i webbläsare</string>
+ <string name="trackable_goal">Uppdrag</string>
+ <string name="trackable_details">Detaljer</string>
+ <string name="trackable_image">Bild</string>
+ <string name="trackable_code">TB-kod</string>
+ <string name="trackable_name">Namn</string>
+ <string name="trackable_type">Typ</string>
+ <string name="trackable_owner">Ägare</string>
+ <string name="trackable_spotted">Plats</string>
+ <string name="trackable_spotted_in_cache">I</string>
+ <string name="trackable_spotted_at_user">I händerna på</string>
+ <string name="trackable_spotted_unknown_location">Okänd</string>
+ <string name="trackable_spotted_owner">Hos ägaren</string>
+ <string name="trackable_origin">Ursprung</string>
+ <string name="trackable_unknown">Okänd</string>
+ <string name="trackable_released">Släppt</string>
+ <string name="trackable_distance">Rest sträcka</string>
+ <string name="trackable_touch">Logga</string>
+
+ <!-- user -->
+ <string name="user_menu_title">Om</string>
+ <string name="user_menu_view_hidden">Gömda cacher</string>
+ <string name="user_menu_view_found">Hittade cacher</string>
+ <string name="user_menu_open_browser">Öppna profil i webbläsaren</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigering</string>
+ <string name="compass_title">Kompass</string>
+ <string name="use_gps">Använd GPS</string>
+ <string name="use_compass">Använd kompass</string>
+ <string name="destination_select">Välj målpunkt</string>
+ <string name="destination_set">Sätt målpunkt</string>
+
+ <!-- license -->
+ <string name="license">Licens</string>
+ <string name="license_show">Visa licens</string>
+ <string name="license_dismiss">Avbryt</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">Manual</string>
+ <string name="helper_manual_description">En utförlig manual för c:geo som beskriver alla möjligheter och ger en hel del tips. Manualen finns enbart på engelska.</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_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>
+ <string name="helper_bluetoothgps_description">Gör det möjligt att använda en extern GPS enhet för att få bättre mottagning, mer exakt position och kan även spara på batteriet i telefonen.</string>
+
+ <!-- next things -->
+ <string name="legal_note">För att använda tjänster hos geocaching.com, måste regler och villkor i <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeaks avtal</a> godkännas.</string>
+ <string name="author">Upphovsman: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Support: <a href="mailto:carnero@carnero.cc">carnero@carnero.cc</a></string>
+ <string name="website">Hemsida: <a href="http://cgeo.carnero.cc/">cgeo.carnero.cc</a></string>
+ <string name="facebook">Facebook: <a href="http://www.facebook.com/pages/cgeo/297269860090">c:geo</a></string>
+ <string name="twitter">Twitter: <a href="http://twitter.com/android_gc">@android_GC</a></string>
+ <string name="about_go4cache">Tjänsten <b>Go 4 Cache</b> visar andra geocachare på kartan i realtid (i <b>c:geo</b> eller webbläsaren). Du kan till exempel se vilken cache de letar efter. Genom att ansluta till <b>Go 4 Cache</b> tillåter du <b>c:geo</b> att publicera din nuvarande plats när du geocachar (bara när <b>c:geo</b> är igång).</string>
+ <string name="about_twitter">Ska <b>c:geo</b> publicera ny status på Twitter varje gång en cache loggas?</string>
+ <string name="about_auth_1">Nedan tillåter du <b>c:geo</b> att ansluta till Twitter.</string>
+ <string name="about_auth_2">Klicka på \"Påbörja koppling mot Twitter\" om du vill koppla ihop <b>c:geo</b> med Twitter. Twitters hemsida kommer att öppnas i en webbläsare. Logga in på den sidan och tillåt <b>c:geo</b> att ansluta till ditt konto. När du godkänt så kommer Twitter att visa en PIN kod. Kom ihåg denna PIN kod, stäng webbläsaren och skriv in PIN koden i <b>c:geo</b> och bekräfta.</string>
+</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
new file mode 100644
index 0000000..48d911c
--- /dev/null
+++ b/res/values/attrs.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <declare-styleable name="cgCompassMini">
+ <attr name="skin" format="integer" />
+ </declare-styleable>
+
+ <!-- colors -->
+ <attr name="just_color" format="color" />
+ <attr name="text_color" format="color" />
+ <attr name="text_color_headline" format="color" />
+ <attr name="text_color_grey" format="color" />
+ <attr name="text_color_hint" format="color" />
+ <attr name="text_color_link" format="color" />
+ <attr name="button_color_enabled" format="color" />
+ <attr name="button_color_disabled" format="color" />
+ <attr name="background_color" format="color" />
+ <attr name="background_color_notice" format="color" />
+ <attr name="background_color_transparent" format="color" />
+ <attr name="separator_color" format="color" />
+
+ <!-- drawables -->
+ <attr name="button" format="integer" />
+ <attr name="input" format="integer" />
+ <attr name="inventory" format="integer" />
+ <attr name="favourite" format="integer" />
+ <attr name="favourite_r" format="integer" />
+ <attr name="favourite_o" format="integer" />
+ <attr name="favourite_g" format="integer" />
+ <attr name="close" format="integer" />
+
+ <!-- others -->
+ <attr name="compass" format="integer" />
+</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
new file mode 100644
index 0000000..c8df1fa
--- /dev/null
+++ b/res/values/colors.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <color name="just_white">#FFFFFFFF</color>
+ <color name="just_black">#FF000000</color>
+ <color name="background_dark">#FF000000</color>
+ <color name="background_light">#FFFFFFFF</color>
+ <color name="background_dark_notice">#FF191919</color>
+ <color name="background_light_notice">#FFDFDFDF</color>
+ <color name="background_dark_transparent">#44000000</color>
+ <color name="background_light_transparent">#44FFFFFF</color>
+ <color name="owncache_background_dark">#FF222222</color>
+ <color name="owncache_background_light">#FFDDDDDD</color>
+ <color name="separator_dark">#44FFFFFF</color>
+ <color name="separator_light">#44000000</color>
+ <color name="text_icon">#FFFFFFFF</color>
+ <color name="text_dark">#FFFFFFFF</color>
+ <color name="text_light">#FF000000</color>
+ <color name="text_headline_dark">#66FFFFFF</color>
+ <color name="text_headline_light">#66000000</color>
+ <color name="text_grey_dark">#99FFFFFF</color>
+ <color name="text_grey_light">#99000000</color>
+ <color name="text_hint_dark">#44FFFFFF</color>
+ <color name="text_hint_light">#44000000</color>
+ <color name="link">#FF00C0FF</color>
+ <color name="button_enabled">#FF000000</color>
+ <color name="button_disabled">#66000000</color>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 0000000..051f73f
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <dimen name="actionbar_height">45dip</dimen>
+ <dimen name="actionbar_separator_height">37dip</dimen>
+ <dimen name="actionbar_separator_width">2dip</dimen>
+</resources>
diff --git a/res/values/ids.xml b/res/values/ids.xml
new file mode 100644
index 0000000..cfb09cd
--- /dev/null
+++ b/res/values/ids.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <item type="id" name="actionbar_title" />
+ <item type="id" name="actionbar_progress" />
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644
index 0000000..c31ac80
--- /dev/null
+++ b/res/values/strings.xml
@@ -0,0 +1,957 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources>
+ <string name="app_name">c:geo</string>
+ <string name="app_name_compass">c:geo compass</string>
+
+ <!-- keys -->
+ <string name="maps_api_keyx">0_xEJVmqy36u8h1HaFz1YeOknLa7fozNSKI4lHg</string> <!-- dev -->
+ <string name="maps_api_key">0_xEJVmqy36vnWDcOuXUXTpS6JMk-OuN3w1BfJw</string> <!-- market -->
+
+ <!-- basics -->
+ <string name="cache">Cache</string>
+ <string name="detail">Detail</string>
+ <string name="search">Search</string>
+ <string name="settings">Settings</string>
+ <string name="helpers">What to install</string>
+ <string name="about">About c:geo</string>
+ <string name="helper">Do you want to learn about <b>c:geo</b>?\nCheck our easy to read manual.</string>
+ <string name="database_error_title">Problem with database</string>
+ <string name="database_error_message">c:geo failed to connect to internal database.\nPlease try to start c:geo a bit later. If this message has been showed for many times, proceed to phone Settings / Applications / c:geo and hit the Clear Data button. Or uninstall and install c:geo again. Sorry for inconvenience.</string>
+
+ <!-- actionbar -->
+ <string name="action_bar_share_title">Share link to cache</string>
+
+ <!-- caches -->
+ <string name="all">All caches</string>
+ <string name="all_types">All cache types</string>
+ <string name="traditional">Traditional cache</string>
+ <string name="multi">Multi-cache</string>
+ <string name="mystery">Unknown cache</string>
+ <string name="letterbox">Letterbox hybrid</string>
+ <string name="event">Event cache</string>
+ <string name="mega">Mega-event cache</string>
+ <string name="earth">Earthcache</string>
+ <string name="cito">Cache in trash out event</string>
+ <string name="webcam">Webcam cache</string>
+ <string name="virtual">Virtual cache</string>
+ <string name="wherigo">Wherigo cache</string>
+ <string name="lostfound">Lost &amp; found</string>
+ <string name="ape">Project ape cache</string>
+ <string name="gchq">Groundspeak hq</string>
+ <string name="gps">GPS cache exhibit</string>
+
+ <!-- waypoints -->
+ <string name="wp_final">Final location</string>
+ <string name="wp_stage">Stage of multi-cache</string>
+ <string name="wp_puzzle">Question for answer</string>
+ <string name="wp_pkg">Parking area</string>
+ <string name="wp_trailhead">Trailhead</string>
+ <string name="wp_waypoint">Reference point</string>
+
+ <!-- logs -->
+ <string name="log_found">Found</string>
+ <string name="log_dnf">Did not find</string>
+ <string name="log_note">Note</string>
+ <string name="log_published">Published</string>
+ <string name="log_enabled">Enabled</string>
+ <string name="log_disabled">Disabled</string>
+ <string name="log_attend">Will attend</string>
+ <string name="log_attended">Attended</string>
+ <string name="log_retrieved">Retrieved</string>
+ <string name="log_placed">Placed</string>
+ <string name="log_grabbed">Grabbed somewhere</string>
+ <string name="log_maintained">Maintenance performed</string>
+ <string name="log_maintenance_needed">Needs maintenance</string>
+ <string name="log_maintenance_owner">Maintenance</string>
+ <string name="log_update">Updated coordinates</string>
+ <string name="log_archived">Archived</string>
+ <string name="log_needs_archived">Needs archived</string>
+ <string name="log_discovered">Discovered</string>
+ <string name="log_reviewed">Reviewer note</string>
+ <string name="log_taken">Visit</string>
+ <string name="log_tb_nothing">Do nothing</string>
+ <string name="log_tb_visit">Visit</string>
+ <string name="log_tb_drop">Drop here</string>
+ <string name="log_tb_changeall">Change all</string>
+ <string name="log_save">Save</string>
+ <string name="log_saving">Saving log...</string>
+ <string name="log_clear">Clear</string>
+ <string name="log_post">Post log</string>
+ <string name="log_post_rate">Post log &amp; rate</string>
+ <string name="log_post_no_rate">Post log &amp; do not rate</string>
+ <string name="log_add">Add</string>
+ <string name="log_date">Date</string>
+ <string name="log_time">Time</string>
+ <string name="log_date_time">Date &amp; time</string>
+ <string name="log_rating">Rating</string>
+ <string name="log_no_rating">No rating</string>
+ <string name="log_stars_1">1 star</string>
+ <string name="log_stars_2">2 stars</string>
+ <string name="log_stars_3">3 stars</string>
+ <string name="log_stars_4">4 stars</string>
+ <string name="log_stars_5">5 stars</string>
+ <string name="log_webcam">Webcam photo taken</string>
+ <string name="log_new_log">Log</string>
+ <string name="log_new_log_text">Log text</string>
+ <string name="log_announcement">Announcement</string>
+
+ <!-- errors, warnings, info toasts -->
+ <string name="err_none">Ok</string>
+ <string name="err_start">Communication not started</string>
+ <string name="err_parse">Failed login page parsing</string>
+ <string name="err_server">Failed connection to geocaching.com (server or connection down?)</string>
+ <string name="err_login">No login information stored</string>
+ <string name="err_login_failed">Sorry, c:geo can\'t login.</string>
+ <string name="err_unknown">Unknown error</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">Wrong login informations</string>
+ <string name="err_license">User has not agreed to Geocaching.com license agreement, so c:geo can\'t load caches coordinates.</string>
+ <string name="err_store">Sorry, c:geo can\'t store cache.</string>
+ <string name="err_drop">Sorry, c:geo can\'t drop cache.</string>
+ <string name="err_title_problem">Problem</string>
+ <string name="err_detail_open">Sorry, c:geo can\'t open geocache details.</string>
+ <string name="err_detail_cache">Sorry, c:geo can\'t display geocache you want. Is it really geocache?</string>
+ <string name="err_detail_cache_find">Sorry, c:geo can\'t find geocache</string>
+ <string name="err_detail_cache_find_some">Sorry, c:geo can\'t find that geocache.</string>
+ <string name="err_detail_cache_find_any">Sorry, c:geo can\'t find any geocache.</string>
+ <string name="err_detail_cache_find_next">Sorry, c:geo can\'t find next geocaches.</string>
+ <string name="err_detail_cache_forgot">Sorry, c:geo forgot which geocache you want.</string>
+ <string name="err_detail_cache_forgot_visit">Sorry, c:geo forgot which cache you visited.</string>
+ <string name="err_detail_cache_language">c:geo can\'t read some cache details. Please check if the geocaching.com website is set to English. Unfortunately, c:geo doesn\'t understand other localisations.</string>
+ <string name="err_detail_no_spoiler">c:geo found no spoiler images for this cache.</string>
+ <string name="err_detail_no_map_static">c:geo found no static maps for this cache.</string>
+ <string name="err_detail_not_load_map_static">Sorry, c:geo failed to load static maps.</string>
+ <string name="err_detail_still_removing">Still removing this cache.</string>
+ <string name="err_detail_still_saving">Still saving this cache.</string>
+ <string name="err_detail_still_refreshing">Still reloading this cache.</string>
+ <string name="err_radar_title">Radar isn\'t installed.</string>
+ <string name="err_radar_message">This function requires Radar application. Should it be installed?</string>
+ <string name="err_radar_market">c:geo can\'t start Android Market to search for Radar application.</string>
+ <string name="err_radar_generic">Sorry, c:geo can\'t start Radar application. Is it installed?</string>
+ <string name="err_navigation_no">c:geo can\'t find any supported navigation.</string>
+ <string name="err_application_no">c:geo can\'t find any suitable application.</string>
+ <string name="err_auth_initialize">Sorry, c:geo failed to initialize authorization process.</string>
+ <string name="err_auth_process">Authorization process failed.</string>
+ <string name="err_cannot_log_visit">c:geo has not enough information to log visit. Please, do it from full cache details.</string>
+ <string name="err_init_cleared">Sorry, c:geo can\'t clear login information.</string>
+ <string name="err_no_chaches">Sorry, c:geo failed to load cache or caches.</string>
+ <string name="err_download_fail">Sorry, c:geo failed to download caches because of </string>
+ <string name="err_update_fail">Failed to update traveled distance.</string>
+ <string name="err_list_load_fail">Sorry, c:geo failed to load cache list.</string>
+ <string name="err_store_failed">Sorry, c:geo can\'t store geocache.</string>
+ <string name="err_refresh_failed">Sorry, c:geo can\'t refresh geocache.</string>
+ <string name="err_drop_failed">Sorry, c:geo can\'t drop geocache.</string>
+ <string name="err_dwld_details_failed">Sorry, c:geo failed to download cache details.</string>
+ <string name="err_dwld_details_failed_reason">Sorry, c:geo failed to download cache details because of</string>
+ <string name="err_load_descr_failed">Sorry, c:geo can\'t load description.</string>
+ <string name="err_location_unknown">c:geo doesn\'t know location of cache.</string>
+ <string name="err_manual_title">Manual isn\'t installed.</string>
+ <string name="err_manual_message">Manual for c:geo is not present in your device. Should it be installed?</string>
+ <string name="err_manual_market">c:geo can\'t start Android Market to search for Manual of c:geo.</string>
+ <string name="err_missing_device_name">Please enter a device name before registering.</string>
+
+ <string name="err_tb_display">"Sorry, c:geo can\'t display trackable you want. Is it really trackable?</string>
+ <string name="err_tb_details_open">Sorry, c:geo can\'t open trackable details.</string>
+ <string name="err_tb_details_download">Sorry, c:geo failed to download trackable details because of</string>
+ <string name="err_tb_forgot">Sorry, c:geo forgot which trackable you want.</string>
+ <string name="err_tb_forgot_saw">Sorry, c:geo forgot which trackable you saw.</string>
+ <string name="err_tb_find">Sorry, c:geo can\'t find trackable</string>
+ <string name="err_tb_find_that">Sorry, c:geo can\'t find that trackable.</string>
+
+ <string name="err_waypoint_cache_unknown">Sorry, c:geo doesn\'t know to which cache you want to add waypoint.</string>
+ <string name="err_waypoint_unknown">Sorry, c:geo forgot what waypoint you want to display.</string>
+ <string name="err_waypoint_add_failed">Sorry, c:geo failed to add your waypoint.</string>
+ <string name="err_waypoint_load_failed">Sorry, c:geo failed to load waypoint.</string>
+ <string name="err_waypoint_delete_failed">Sorry, c:geo can\'t delete waypoint.</string>
+ <string name="err_point_unknown_position">Sorry, 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 or 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 with or without units.</string>
+ <string name="err_point_location_error">Sorry, c:geo can\'t get location of waypoint.</string>
+ <string name="err_navigation_not_found">c:geo can\'t find any supported navigation.</string>
+
+ <string name="err_log_load_data">Sorry, c:geo can\'t load data required to log visit.</string>
+ <string name="err_log_load_data_again">Sorry, c:geo can\'t load data required to log visit. Trying again.</string>
+ <string name="err_log_load_data_still">c:geo is still loading data required to post log. Please wait a little while longer.</string>
+ <string name="err_log_failed_server">Sorry, c:geo failed to post log because server is not responding.</string>
+ <string name="err_log_post_failed">It seems that your log was not posted. Please check it on geocaching.com.</string>
+ <string name="err_log_post_failed_because">Sorry, c:geo failed to post log because of </string>
+
+ <string name="err_search_address_no_match">Sorry, c:geo found no matching place.</string>
+ <string name="err_search_address_forgot">Sorry, c:geo forgot address you try to find.</string>
+ <string name="err_search_address">Searching for places</string>
+ <string name="err_parse_lat">Sorry, c:geo can\'t parse latitude.</string>
+ <string name="err_parse_lon">Sorry, c:geo can\'t parse longitude.</string>
+ <string name="err_parse_bear">Sorry, c:geo can\'t parse bearing.</string>
+ <string name="err_parse_dist">Sorry, c:geo can\'t parse distance.</string>
+
+ <string name="warn_save_nothing">There is nothing to be saved.</string>
+ <string name="warn_no_cache_coord">There is no cache with coordinates.</string>
+ <string name="warn_no_coordinates">No coordinates given.</string>
+ <string name="warn_no_keyword">No keyword given.</string>
+ <string name="warn_no_username">No username given.</string>
+ <string name="warn_search_help_title">Need some help?</string>
+ <string name="warn_search_help_address">"Fill address or location name. For example use street address \"Radlicka 100, Prague, Czech Republic\", city name \"Berlin\" or just name of something like \"Yellowstone Park\".</string>
+ <string name="warn_search_help_gccode">Fill code of geocache. For example \"GC1VCAZ\".</string>
+ <string name="warn_search_help_keyword">Fill some word that is supposed to be somewhere in cache name you are trying to find.</string>
+ <string name="warn_search_help_user">Fill name of user at Geocaching.com.</string>
+ <string name="warn_search_help_tb">Fill code of trackable. For example \"TB29QMZ\".</string>
+ <string name="warn_log_text_fill">Please, fill some log text.</string>
+
+ <string name="info_altitude">Current altitude</string>
+ <string name="info_distance">Distance traveled</string>
+ <string name="info_distance_cleared">Traveled distance was cleared.</string>
+ <string name="info_since">\n(since </string>
+
+ <string name="info_log_posted">c:geo successfully posted log.</string>
+ <string name="info_log_saved">c:geo successfully saved log.</string>
+ <string name="info_log_cleared">Log was cleared.</string>
+ <string name="info_log_type_changed">Type of log has been changed!</string>
+
+ <!-- location service -->
+ <string name="loc_last">Last known</string>
+ <string name="loc_net">Network</string>
+ <string name="loc_gps">GPS</string>
+ <string name="loc_sat">Sat</string>
+ <string name="loc_trying">Trying to locate</string>
+ <string name="loc_no_addr">Unknown address</string>
+
+ <!-- standard menu -->
+ <string name="menu_about">About c:geo</string>
+ <string name="menu_helpers">Utility programs</string>
+ <string name="menu_settings">Settings</string>
+ <string name="menu_history">History</string>
+ <string name="menu_filter">Filter</string>
+
+ <!-- main screen -->
+ <string name="live_map_button">Live map</string>
+ <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="about_button">About</string>
+ <string name="settings_button">Settings</string>
+ <string name="type">Type</string>
+ <string name="now_searching">Now searching</string>
+
+ <!-- caches -->
+ <string name="caches_searching">Searching for caches</string>
+ <string name="caches_no_cache">There is no cache</string>
+ <string name="caches_more_caches">Not enough? Get more caches!</string>
+ <string name="caches_more_caches_no">That\'s all. No more caches.</string>
+ <string name="caches_more_caches_loading">Loading caches...</string>
+ <string name="caches_downloading">Downloading caches...\nETA: </string>
+ <string name="caches_progress_loading_title">Loading caches</string>
+ <string name="caches_progress_loading_text">Caches stored in device</string>
+ <string name="caches_eta_ltm">Less than a minute</string>
+ <string name="caches_eta_mins"> minutes</string>
+ <string name="caches_eta_min"> minute</string>
+ <string name="caches_no_caches"> (no caches)</string>
+ <string name="caches_store_offline">Store for Offline</string>
+ <string name="caches_store_selected">Store selected</string>
+ <string name="caches_stored">Stored</string>
+ <string name="caches_history">History</string>
+ <string name="caches_on_map">Show on map</string>
+ <string name="caches_sort">Sort</string> <!-- since: 2.10 RC2 -->
+ <string name="caches_sort_title">Sort by</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_distance">distance</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_difficulty">difficulty</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_terrain">terrain</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_size">size</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_favorites">popularity</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_name">name</string> <!-- since: 2.10 RC3 -->
+ <string name="caches_sort_gccode">GC-code (age)</string> <!-- since: 2.2 -->
+ <string name="caches_sort_rating">rating</string>
+ <string name="caches_sort_vote">vote (own rating)</string>
+ <string name="caches_sort_inventory">count of inventory</string>
+ <string name="caches_select">Select from list</string>
+ <string name="caches_select_mode">Select mode</string>
+ <string name="caches_select_mode_exit">Exit select mode</string>
+ <string name="caches_select_invert">Invert selection</string>
+ <string name="caches_nearby">Nearby</string>
+ <string name="caches_manage">Manage</string>
+ <string name="caches_drop_selected">Drop selected</string>
+ <string name="caches_drop_selected_ask">Do you want to remove selected caches from device?</string>
+ <string name="caches_drop_all">Drop all</string>
+ <string name="caches_drop_all_ask">Do you want to remove all caches from current list?</string>
+ <string name="caches_drop_stored">Drop stored</string>
+ <string name="caches_drop_progress">Removing caches</string>
+ <string name="caches_refresh_selected">Refresh selected</string>
+ <string name="caches_refresh_all">Refresh all</string>
+ <string name="caches_map_cgeo">c:geo</string>
+ <string name="caches_map_locus">Locus</string>
+ <string name="caches_recaptcha_title">reCAPTCHA</string>
+ <string name="caches_recaptcha_explanation">Please, write text from image. It\'s important to download coordinates of caches. It\'s optional and can be switched off in Settings.</string>
+ <string name="caches_recaptcha_hint">Text from image</string>
+ <string name="caches_recaptcha_continue">Continue</string>
+ <string name="caches_filter">Filter</string>
+ <string name="caches_filter_title">Filter by</string>
+ <string name="caches_filter_size">size</string>
+ <string name="caches_filter_type">type</string>
+ <string name="caches_filter_track">with trackables</string>
+ <string name="caches_filter_clear">clear filters</string>
+ <string name="caches_filter_size_title">Choose size</string>
+ <string name="caches_filter_size_micro">micro</string>
+ <string name="caches_filter_size_small">small</string>
+ <string name="caches_filter_size_regular">regular</string>
+ <string name="caches_filter_size_large">large</string>
+ <string name="caches_filter_size_other">other</string>
+ <string name="caches_filter_size_virtual">virtual</string>
+ <string name="caches_filter_size_notchosen">not chosen</string>
+ <string name="caches_filter_type_title">Choose type</string>
+ <string name="caches_filter_type_traditional">Traditional cache</string>
+ <string name="caches_filter_type_multi">Multi-cache</string>
+ <string name="caches_filter_type_mystery">Unknown cache</string>
+ <string name="caches_filter_type_letterbox">Letterbox Hybrid</string>
+ <string name="caches_filter_type_event">Event cache</string>
+ <string name="caches_filter_type_mega">Mega-event cache</string>
+ <string name="caches_filter_type_earth">Earth cache</string>
+ <string name="caches_filter_type_cito">Cache In Trash Out event</string>
+ <string name="caches_filter_type_webcam">Webcam cache</string>
+ <string name="caches_filter_type_virtual">Virtual cache</string>
+ <string name="caches_filter_type_wherigo">Wherigo cache</string>
+ <string name="caches_filter_type_lostfound">Lost &amp; Found</string>
+ <string name="caches_filter_type_ape">Project APE cache</string>
+ <string name="caches_filter_type_gchq">Groundspeak HQ</string>
+ <string name="caches_filter_type_gps">GPS Cache exhibit</string>
+
+ <!-- caches lists -->
+ <string name="list_menu">List</string>
+ <string name="list_menu_create">Create new list</string>
+ <string name="list_menu_drop">Drop current list</string>
+ <string name="list_menu_change">Change list</string> <!-- since: 2.2 -->
+ <string name="list_title">Pick a list</string>
+ <string name="list_inbox">Stored</string>
+ <string name="list_wpt">Waypoints</string>
+ <string name="list_dialog_create_title">New list</string>
+ <string name="list_dialog_create">Create</string>
+ <string name="list_dialog_cancel">Cancel</string>
+ <string name="list_dialog_create_ok">New list was created</string>
+ <string name="list_dialog_create_err">c:geo failed to create new list</string>
+ <string name="list_dialog_remove_title">Remove list</string>
+ <string name="list_dialog_remove_description">Do you want to remove current list of caches? All caches remaining in the list will be moved to \"Stored\".</string>
+ <string name="list_dialog_remove">Remove</string>
+ <string name="list_dialog_remove_ok">List was removed</string>
+ <string name="list_dialog_remove_err">c:geo failed to remove current list</string>
+
+ <!-- about -->
+ <string name="about_changelog">Changelog</string>
+ <string name="about_donate">Donate</string>
+ <string name="about_detail">Details</string>
+ <string name="about_donation_less">Donate\nless</string>
+ <string name="about_donation_more">Donate\ndevelopement</string>
+ <string name="about_contributors">Contributors</string>
+
+ <!-- init -->
+ <string name="init_geocaching">Geocaching.com</string>
+ <string name="init_gcvote">GCvote.com</string>
+ <string name="init_go4cache">Go 4 Cache</string>
+ <string name="init_twitter">Twitter</string>
+ <string name="init_username">Username</string>
+ <string name="init_password">Password</string>
+ <string name="init_passvote">Password</string>
+ <string name="init_login">Check login</string>
+ <string name="init_login_popup">Login</string>
+ <string name="init_login_popup_working">Logging to geocaching.com...</string>
+ <string name="init_login_popup_ok">Login ok.</string>
+ <string name="init_login_popup_failed">Login failed.</string>
+ <string name="init_login_popup_failed_reason">Login failed because of </string>
+ <string name="init_legal">Legal note</string>
+ <string name="init_go4cache_connect">Connect to Go 4 Cache</string>
+ <string name="init_twitter_authorize">Authorize c:geo</string>
+ <string name="init_twitter_publish">Publish status when cache found</string>
+ <string name="init_signature">Signature</string>
+ <string name="init_signature_help_button">Help</string>
+ <string name="init_signature_help_title">Signature tips and tricks</string>
+ <string name="init_signature_help_text">Write your signature to use in log text.\nSpecial strings that can be used are: [DATE] , [TIME], [USER] &amp; [NUMBER].\nThese will be expanded when the signature is inserted.</string>
+ <string name="init_languages">Translation</string>
+ <string name="init_languages_description">Which languages you don\'t need to translate? Please provide two-character language codes.</string>
+ <string name="init_languages_hint">en es de cs</string>
+ <string name="init_translate">Translate description &amp; hint</string>
+ <string name="init_other">Other options</string>
+ <string name="init_skin">Light skin\n(needs restart of c:geo)</string>
+ <string name="init_transparent">Use transparent c:geo mainscreen</string>
+ <string name="init_address">Show address on mainscreen</string>
+ <string name="init_captcha">Show CAPTCHA if necessary</string>
+ <string name="init_useenglish">Use English inside c:geo\n(restart needed)</string>
+ <string name="init_exclude">Exclude own and found caches</string>
+ <string name="init_disabled">Exclude disabled caches</string>
+ <string name="init_offline">Store static maps for offline use</string>
+ <string name="init_units">Use miles/feet\n(imperial units)</string>
+ <string name="init_nav">Use Google Navigation</string>
+ <string name="init_autoload">Auto-loading long description</string>
+ <string name="init_livelist">Show direction to caches in its list</string>
+ <string name="init_browser">Identify c:geo as standard browser</string>
+ <string name="init_altitude">Altitude correction</string>
+ <string name="init_altitude_description">If GPS is giving wrong altitude to you, you can correct with a positive or negative number. Correction is always in metres.</string>
+ <string name="init_clear">Clear login</string>
+ <string name="init_cleared">c:geo cleared login information.</string>
+ <string name="init_backup">Backup</string>
+ <string name="init_backup_backup">Backup</string>
+ <string name="init_backup_note">Please note this option will backup/restore the database containing caches and waypoints, not settings. Your login information (passwords) will not leave this application.</string>
+ <string name="init_backup_restore">Restore</string>
+ <string name="init_backup_success">Database of c:geo was successfully copied to the file</string>
+ <string name="init_backup_failed">Backup of database of c:geo failed.</string>
+ <string name="init_restore_success">Restoration completed.</string>
+ <string name="init_restore_failed">Restoration failed.</string>
+ <string name="init_backup_last">Available backup from</string>
+ <string name="init_backup_last_no">There is no file with backup.</string>
+ <string name="init_mapsources">Map Sources</string> <!-- since: 2.26 RC3 -->
+ <string name="init_mapsources_description">Here you can select the source for your maps. As an alternative to Google maps various OpenStreetMap styles are available and even off line map files (see http://code.google.com/p/mapsforge/ for details).</string> <!-- since: 2.26 RC3 -->
+ <string name="init_mapsource_select">Select map source</string>
+
+ <!-- map sources -->
+ <string-array name="map_sources">
+ <item>Google Maps</item>
+ <item>OSM: Mapnik</item>
+ <item>OSM: Osmarender</item>
+ <item>OSM: Cyclemap</item>
+ <item>OSM: Offline</item>
+ </string-array>
+
+ <string name="init_sendToCgeo">Send to c:geo</string>
+ <string name="init_sendToCgeo_name">Your device name:</string>
+ <string name="init_sendToCgeo_description">Send to c:geo allows you to recieve caches directly from geocaching site using special plugin for Firefox or Chrome. Before registration please read <a href="http://send2cgeo.carnero.cc/">http://send2cgeo.carnero.cc/</a>.</string>
+ <string name="init_sendToCgeo_register">Request registration</string>
+ <string name="init_sendToCgeo_registering">Registering your device for "Send to c:geo"...</string>
+ <string name="init_sendToCgeo_register_ok">Registration succesful. PIN code is ####. Use it on c:geo website to add this device to your browser.</string>
+ <string name="init_sendToCgeo_register_fail">Registration failed.</string>
+
+ <!-- auth -->
+ <string name="auth_twitter">Twitter</string>
+ <string name="auth_authorize">Authorize c:geo</string>
+ <string name="auth_start">Start authorization</string>
+ <string name="auth_again">Start again</string>
+ <string name="auth_pin_hint">PIN assigned by Twitter</string>
+ <string name="auth_finish">Finish</string>
+ <string name="auth_dialog_wait">Waiting for Twitter...</string>
+ <string name="auth_dialog_pin_title">PIN code</string>
+ <string name="auth_dialog_pin_message">Please type in PIN code provided by Twitter website. It\'s mandatory to complete authorization.</string>
+ <string name="auth_dialog_completed">c:geo is now authorized to post on Twitter.</string>
+
+ <!-- cache -->
+ <string name="cache_count_no">No cache</string>
+ <string name="cache_count_one">One cache</string>
+ <string name="cache_count_more">Caches</string>
+ <string name="cache_offline">Offline</string>
+ <string name="cache_offline_refresh">Refresh</string>
+ <string name="cache_offline_drop">Drop</string>
+ <string name="cache_offline_store">Store</string>
+ <string name="cache_offline_stored">Stored in device</string>
+ <string name="cache_offline_not_ready">Not ready\nfor offline use</string>
+ <string name="cache_offline_time_about">about</string>
+ <string name="cache_offline_time_mins">minutes ago</string>
+ <string name="cache_offline_time_mins_few">a few minutes ago</string>
+ <string name="cache_offline_time_hour">one hour ago</string>
+ <string name="cache_offline_time_hours">hours ago</string>
+ <string name="cache_offline_time_days">days ago</string>
+ <string name="cache_premium">Premium</string>
+ <string name="cache_attributes">Attributes</string>
+ <string name="cache_inventory">Inventory</string>
+ <string name="cache_log_offline">Offline log</string>
+ <string name="cache_description">Description</string>
+ <string name="cache_description_long">Long description</string>
+ <string name="cache_waypoints">Waypoints</string>
+ <string name="cache_waypoints_add">Add waypoint</string>
+ <string name="cache_hint">Hint</string>
+ <string name="cache_logs">Logbook</string>
+ <string name="cache_dialog_loading_details">Loading cache details...</string>
+ <string name="cache_dialog_loading_description">Loading cache description...</string>
+ <string name="cache_dialog_offline_save_title">Offline</string>
+ <string name="cache_dialog_offline_save_message">Saving cache for offline use...</string>
+ <string name="cache_dialog_offline_drop_title">Offline</string>
+ <string name="cache_dialog_offline_drop_message">Removing cache from device memory...</string>
+ <string name="cache_dialog_refresh_title">Refresh</string>
+ <string name="cache_dialog_refresh_message">Reloading cache details...</string>
+ <string name="cache_menu_navigate">Navigate</string>
+ <string name="cache_menu_compass">Compass</string>
+ <string name="cache_menu_tbt">Turn-by-turn</string>
+ <string name="cache_menu_radar">Radar</string>
+ <string name="cache_menu_map">Map</string>
+ <string name="cache_menu_map_static">Static maps</string>
+ <string name="cache_menu_locus">Locus</string>
+ <string name="cache_menu_rmaps">Rmaps</string>
+ <string name="cache_menu_map_ext">Show on ext. map</string>
+ <string name="cache_menu_map_short">Maps</string>
+ <string name="cache_menu_map_ext_short">Ext. map</string>
+ <string name="cache_menu_browser">Open in browser</string>
+ <string name="cache_menu_visit">Log visit</string>
+ <string name="cache_menu_spoilers">Spoiler images</string>
+ <string name="cache_menu_around">Caches around</string>
+ <string name="cache_menu_event">Add to calendar</string>
+ <string name="cache_menu_details">Details</string>
+ <string name="cache_menu_share">Share cache</string>
+ <string name="cache_menu_move_list">Move to other list</string>
+ <string name="cache_status">Status</string>
+ <string name="cache_status_offline_log">Saved log</string>
+ <string name="cache_status_found">Found</string>
+ <string name="cache_status_archived">Archived</string>
+ <string name="cache_status_disabled">Disabled</string>
+ <string name="cache_status_premium">Premium members only</string>
+ <string name="cache_geocode">GC-code</string>
+ <string name="cache_name">Name</string>
+ <string name="cache_type">Type</string>
+ <string name="cache_distance">Distance</string>
+ <string name="cache_difficulty">Difficulty</string>
+ <string name="cache_terrain">Terrain</string>
+ <string name="cache_rating">Rating</string>
+ <string name="cache_rating_of">of</string>
+ <string name="cache_favourite">Favorite</string>
+ <string name="cache_owner">Owner</string>
+ <string name="cache_hidden">Hidden</string>
+ <string name="cache_event">Date</string>
+ <string name="cache_location">Location</string>
+ <string name="cache_coordinates">Coordinates</string>
+ <string name="cache_elevation">Elevation</string>
+ <string name="cache_calendars">Select calendar</string>
+ <string name="cache_spoiler_images_title">Spoiler images</string>
+ <string name="cache_spoiler_images_loading">Loading spoiler images...</string>
+ <string name="cache_log_types">Log types</string> <!-- since: 2.10 RC2 -->
+ <string name="cache_coordinates_no">This cache has no coordinates.</string> <!-- since: 2.26 RC2 -->
+
+ <!-- gpx -->
+ <string name="gpx_import_searching_in">Searching for .gpx files\nin</string>
+ <string name="gpx_import_loading_stored">Loading caches from .gpx file\nStored:</string>
+ <string name="gpx_import_no_files">Sorry, c:geo found no .gpx files.</string>
+ <string name="gpx_import_caches_imported">caches imported</string>
+ <string name="gpx_import_searching">Searching for .gpx files</string>
+ <string name="gpx_import_loading">Loading caches from .gpx file</string>
+ <string name="gpx_import_title">Import GPX</string>
+ <string name="gpx_import_title_reading_file">Reading file</string>
+ <string name="gpx_import_title_searching">Searching</string>
+ <string name="gpx_import_title_caches_imported">Result</string>
+
+ <!-- import -->
+ <string name="import_title">Import...</string>
+ <string name="web_import_title">Import from web</string>
+ <string name="web_import_server_problem">There was a problem while communicating with server. Please re-register your phone and try again.</string>
+ <string name="web_import_waiting">Waiting for new caches from web...</string>
+ <string name="web_downloading">Downloading</string>
+ <string name="web_downloaded">Downloaded</string>
+
+ <!-- event -->
+ <string name="event_success">Event cache added to calendar</string>
+ <string name="event_fail">Failed to add event cache to calendar</string>
+
+ <!-- popup -->
+ <string name="popup_more">More details</string>
+ <string name="popup_offline">Offline</string>
+
+ <!-- waypoint -->
+ <string name="waypoint">Waypoint</string>
+ <string name="waypoint_title">Waypoint</string>
+ <string name="waypoint_custom">Custom</string>
+ <string name="waypoint_my_coordinates">My coordinates</string>
+ <string name="waypoint_bearing">Bearing</string>
+ <string name="waypoint_distance">Distance</string>
+ <string name="waypoint_name">Name</string>
+ <string name="waypoint_edit">Edit</string>
+ <string name="waypoint_delete">Delete</string>
+ <string name="waypoint_edit_title">Edit waypoint</string>
+ <string name="waypoint_add_title">Add waypoint</string>
+ <string name="waypoint_note">Note</string>
+ <string name="waypoint_save">Save</string>
+ <string name="waypoint_loading">Loading waypoint...</string>
+ <string name="waypoint_unknown_coordinates">Coordinates unknown</string>
+
+ <!-- visit -->
+ <string name="visit_tweet">Post this find to Twitter</string>
+
+ <!-- map -->
+ <string name="map_map">Map</string>
+ <string name="map_live">Live map</string>
+ <string name="map_view_satellite">Satellite view</string>
+ <string name="map_view_map">Map view</string>
+ <string name="map_trail_show">Show trail</string>
+ <string name="map_trail_hide">Hide trail</string>
+ <string name="map_circles_show">Show circles</string> <!-- since: 2.23 RC3 -->
+ <string name="map_circles_hide">Hide circles</string> <!-- since: 2.23 RC3 -->
+ <string name="map_live_enable">Enable live</string>
+ <string name="map_live_disable">Disable live</string>
+ <string name="map_static_title">Static maps</string>
+ <string name="map_static_loading">Loading static maps...</string>
+ <string name="map_token_err">Since c:geo is able to download only partial data, coordinates of caches could be inaccurate.</string> <!-- since: 2.26 RC3 -->
+
+ <!-- search -->
+ <string name="search_bar_hint">Search for caches</string>
+ <string name="search_bar_desc">Caches (GC-code, keyword), Trackables (TB-code)</string>
+ <string name="search_coordinates">Coordinates</string>
+ <string name="search_coordinates_button">Search by coordinates</string>
+ <string name="search_address">Address</string>
+ <string name="search_address_button">Search by address</string>
+ <string name="search_gc">Geocode</string>
+ <string name="search_gc_button">Search by geocode</string>
+ <string name="search_kw">Keywords</string>
+ <string name="search_kw_prefill">Keyword</string>
+ <string name="search_kw_button">Search by keyword</string>
+ <string name="search_kw_caches">Caches by keyword</string>
+ <string name="search_caches_found_by">Caches found by</string>
+ <string name="search_caches_hidden_by">Caches hidden by</string>
+ <string name="search_fbu">Found by user</string>
+ <string name="search_fbu_prefill">User name</string>
+ <string name="search_fbu_button">Search by user name</string>
+ <string name="search_hbu">Hidden by users</string>
+ <string name="search_hbu_prefill">Owner</string>
+ <string name="search_hbu_button">Search by owner name</string>
+ <string name="search_tb">Trackable</string>
+ <string name="search_tb_hint">Trackable identification</string>
+ <string name="search_tb_button">Search for trackable</string>
+ <string name="search_destination">Destination</string>
+ <string name="search_direction_rel">From this position</string>
+ <string name="search_lat">Lat</string>
+ <string name="search_lon">Lon</string>
+ <string name="search_caches">Search for caches</string>
+ <string name="search_caches_near">Caches near</string>
+ <string name="search_address_started">Searching for places</string>
+ <string name="search_address_result">Found places</string>
+
+ <!-- trackable -->
+ <string name="trackable">Trackable</string>
+ <string name="trackable_select_title">Trackables</string>
+ <string name="trackable_details_loading">Loading trackable details...</string>
+ <string name="trackable_log_touch">Log touch</string>
+ <string name="trackable_browser_open">Open in Browser</string>
+ <string name="trackable_goal">Goal</string>
+ <string name="trackable_details">Details</string>
+ <string name="trackable_image">Image</string>
+ <string name="trackable_code">TB-Code</string>
+ <string name="trackable_name">Name</string>
+ <string name="trackable_type">Type</string>
+ <string name="trackable_owner">Owner</string>
+ <string name="trackable_spotted">Spotted</string>
+ <string name="trackable_spotted_in_cache">In</string>
+ <string name="trackable_spotted_at_user">In the hands of</string>
+ <string name="trackable_spotted_unknown_location">Unknown location</string>
+ <string name="trackable_spotted_owner">In the hands of the owner</string>
+ <string name="trackable_origin">Origin</string>
+ <string name="trackable_unknown">Unknown</string>
+ <string name="trackable_released">Released</string>
+ <string name="trackable_distance">Travelled</string>
+ <string name="trackable_touch">Touch</string>
+
+ <!-- user -->
+ <string name="user_menu_title">About</string>
+ <string name="user_menu_view_hidden">Caches hidden</string>
+ <string name="user_menu_view_found">Caches found</string>
+ <string name="user_menu_open_browser">Open profile in browser</string>
+
+ <!-- navigation -->
+ <string name="navigation">Navigation</string>
+ <string name="compass_title">Compass</string>
+ <string name="use_gps">Use GPS</string>
+ <string name="use_compass">Use compass</string>
+ <string name="destination_select">Select destination</string>
+ <string name="destination_set">Set destination</string>
+
+ <!-- license -->
+ <string name="license">License</string>
+ <string name="license_show">Show license</string>
+ <string name="license_dismiss">Dismiss</string>
+
+ <!-- helpers -->
+ <string name="helper_manual_title">Manual</string>
+ <string name="helper_manual_description">Comprehensive manual for c:geo that contains description of all possibilities of this application (even hidden ones).</string>
+ <string name="helper_locus_title">Locus</string>
+ <string name="helper_locus_description">Simple usable application showing Online maps and allowing to download them directly into Offline mode (raster maps only). Also support track recording, POI handling and many other useful functions.</string>
+ <string name="helper_gpsstatus_title">GPS Status</string>
+ <string name="helper_gpsstatus_description">You can use radar from this application with c:geo. It also offers a lot of other GPS-related information.</string>
+ <string name="helper_bluetoothgps_title">Bluetooth GPS</string>
+ <string name="helper_bluetoothgps_description">Allows you to use external GPS device to get better reception, more precise location and can spare battery of your phone.</string>
+
+ <!-- attributes (permissions -> allowed, not allowed) -->
+ <string name="attribute_dogs_yes">Dogs allowed</string>
+ <string name="attribute_dogs_no">Dogs not allowed</string>
+ <string name="attribute_bicycles_yes">Bicycles allowed</string>
+ <string name="attribute_bicycles_no">Bicycles not allowed</string>
+ <string name="attribute_motorcycles_yes">Motorcycles allowed</string>
+ <string name="attribute_motorcycles_no">Motorcycles not allowed</string>
+ <string name="attribute_quads_yes">Quads allowed</string>
+ <string name="attribute_quads_no">Quads not allowed</string>
+ <string name="attribute_jeeps_yes">Off-road vehicles allowed</string>
+ <string name="attribute_jeeps_no">Off-road vehicles not allowed</string>
+ <string name="attribute_snowmobiles_yes">Snowmobiles allowed</string>
+ <string name="attribute_snowmobiles_no">Snowmobiles not allowed</string>
+ <string name="attribute_horses_yes">Horses allowed</string>
+ <string name="attribute_horses_no">Horses not allowed</string>
+ <string name="attribute_campfires_yes">Campfires allowed</string>
+ <string name="attribute_campfires_no">Campfires not allowed</string>
+ <string name="attribute_rv_yes">Truck driver/RV allowed</string>
+ <string name="attribute_rv_no">Truck driver/RV not allowed</string>
+
+ <!-- attributes (conditions -> yes, no) -->
+ <string name="attribute_kids_yes">Recommended for kids</string>
+ <string name="attribute_kids_no">Not recommended for kids</string>
+ <string name="attribute_onehour_yes">Takes less than an hour</string>
+ <string name="attribute_onehour_no">Takes more than an hour</string>
+ <string name="attribute_scenic_yes">Scenic view</string>
+ <string name="attribute_scenic_no">No scenic view</string>
+ <string name="attribute_hiking_yes">Significant hike</string>
+ <string name="attribute_hiking_no">No significant hike</string>
+ <string name="attribute_climbing_yes">Difficult climbing</string>
+ <string name="attribute_climbing_no">No difficult climbing</string>
+ <string name="attribute_wading_yes">May require wading</string>
+ <string name="attribute_wading_no">May not require wading</string>
+ <string name="attribute_swimming_yes">May require swimming</string>
+ <string name="attribute_swimming_no">May not require swimming</string>
+ <string name="attribute_available_yes">Available at all times</string>
+ <string name="attribute_available_no">Not available at all times</string>
+ <string name="attribute_night_yes">Recommended at night</string>
+ <string name="attribute_night_no">Not recommended at night</string>
+ <string name="attribute_winter_yes">Available during winter</string>
+ <string name="attribute_winter_no">Not available during winter</string>
+ <string name="attribute_stealth_yes">Stealth required</string>
+ <string name="attribute_stealth_no">Stealth not required</string>
+ <string name="attribute_firstaid_yes">Needs maintenance</string>
+ <string name="attribute_firstaid_no">Needs no maintenance</string>
+ <string name="attribute_cow_yes">Watch for livestock</string>
+ <string name="attribute_cow_no">No livestock</string>
+ <string name="attribute_field_puzzle_yes">Field puzzle</string>
+ <string name="attribute_field_puzzle_no">No field puzzle</string>
+ <string name="attribute_nightcache_yes">Night cache</string>
+ <string name="attribute_nightcache_no">No night cache</string>
+ <string name="attribute_parkngrab_yes">Park and grab</string>
+ <string name="attribute_parkngrab_no">No park and grab</string>
+ <string name="attribute_abandonedbuilding_yes">Abandoned structure</string>
+ <string name="attribute_abandonedbuilding_no">No abandoned structure</string>
+ <string name="attribute_hike_short_yes">Short hike (less than 1 km)</string>
+ <string name="attribute_hike_short_no">No short hike</string>
+ <string name="attribute_hike_med_yes">Medium hike (1 km to 10 km)</string>
+ <string name="attribute_hike_med_no">No medium hike</string>
+ <string name="attribute_hike_long_yes">Long hike (more than 10 km)</string>
+ <string name="attribute_hike_long_no">No long hike</string>
+ <string name="attribute_landf_yes">Lost and found tour</string>
+ <string name="attribute_landf_no">No lost and found tour</string>
+ <string name="attribute_sponsored_yes">Sponsored cache</string>
+ <string name="attribute_sponsored_no">Non sponsored cache</string>
+
+ <!-- attributes (equipment -> required, not required) -->
+ <string name="attribute_fee_yes">Access or parking fee required</string>
+ <string name="attribute_fee_no">Access or parking fee not required</string>
+ <string name="attribute_rappelling_yes">Climbing gear required</string>
+ <string name="attribute_rappelling_no">Climbing gear not required</string>
+ <string name="attribute_boat_yes">Boat required</string>
+ <string name="attribute_boat_no">Boat not required</string>
+ <string name="attribute_scuba_yes">Scuba gear required</string>
+ <string name="attribute_scuba_no">Scuba gear not required</string>
+ <string name="attribute_flashlight_yes">Flashlight required</string>
+ <string name="attribute_flashlight_no">Flashlight not required</string>
+ <string name="attribute_UV_yes">UV light required</string>
+ <string name="attribute_UV_no">UV light not required</string>
+ <string name="attribute_snowshoes_yes">Snowshoes required</string>
+ <string name="attribute_snowshoes_no">Snowshoes not required</string>
+ <string name="attribute_skiis_yes">Cross country skis required</string>
+ <string name="attribute_skiis_no">Cross country skis not required</string>
+ <string name="attribute_s_tool_yes">Special tools required</string>
+ <string name="attribute_s_tool_no">Special tools not required</string>
+ <string name="attribute_wirelessbeacon_yes">Wireless beacon</string>
+ <string name="attribute_wirelessbeacon_no">No wireless beacon</string>
+
+ <!-- attributes (hazards -> present, not present) -->
+ <string name="attribute_poisonoak_yes">Poisonous plants</string>
+ <string name="attribute_poisonoak_no">No poisonous plants</string>
+ <string name="attribute_dangerousanimals_yes">Dangerous animals</string>
+ <string name="attribute_dangerousanimals_no">No dangerous animals</string>
+ <string name="attribute_ticks_yes">Ticks</string>
+ <string name="attribute_ticks_no">No ticks</string>
+ <string name="attribute_mine_yes">Abandoned mines</string>
+ <string name="attribute_mine_no">No abandoned mines</string>
+ <string name="attribute_cliff_yes">Cliff</string>
+ <string name="attribute_cliff_no">No cliff</string>
+ <string name="attribute_hunting_yes">Hunting</string>
+ <string name="attribute_hunting_no">No hunting</string>
+ <string name="attribute_danger_yes">Dangerous area</string>
+ <string name="attribute_danger_no">No dangerous area</string>
+ <string name="attribute_thorn_yes">Thorns</string>
+ <string name="attribute_thorn_no">No thorns</string>
+
+ <!-- attributes (facilities -> yes, no) -->
+ <string name="attribute_wheelchair_yes">Wheelchair accessible</string>
+ <string name="attribute_wheelchair_no">Not wheelchair accessible</string>
+ <string name="attribute_parking_yes">Parking available</string>
+ <string name="attribute_parking_no">No parking available</string>
+ <string name="attribute_public_yes">Public transportation</string>
+ <string name="attribute_public_no">No public transportation</string>
+ <string name="attribute_water_yes">Drinking water nearby</string>
+ <string name="attribute_water_no">No drinking water nearby</string>
+ <string name="attribute_restrooms_yes">Public restrooms nearby</string>
+ <string name="attribute_restrooms_no">No public restrooms nearby</string>
+ <string name="attribute_phone_yes">Telephone nearby</string>
+ <string name="attribute_phone_no">No telephone nearby</string>
+ <string name="attribute_picnic_yes">Picnic tables nearby</string>
+ <string name="attribute_picnic_no">No picnic tables nearby</string>
+ <string name="attribute_camping_yes">Camping available</string>
+ <string name="attribute_camping_no">No camping available</string>
+ <string name="attribute_stroller_yes">Stroller accessible</string>
+ <string name="attribute_stroller_no">Not stroller accessible</string>
+ <string name="attribute_fuel_yes">Fuel nearby</string>
+ <string name="attribute_fuel_no">No fuel nearby</string>
+ <string name="attribute_food_yes">Food nearby</string>
+ <string name="attribute_food_no">No food nearby</string>
+
+ <!-- next things -->
+ <string name="legal_note">To use services of geocaching.com, terms and conditions of <a href="http://www.geocaching.com/about/termsofuse.aspx">Groundspeak disclaimer</a> have to be agreed.</string>
+ <string name="quote">To make geocaching easier, to make users lazier.</string>
+ <string name="powered_by">carnero</string>
+ <string name="author">Author: <a href="http://carnero.cc/">carnero</a></string>
+ <string name="support">Support: <a href="mailto:support@cgeo.org">support@cgeo.org</a></string>
+ <string name="website">Website: <a href="http://support@cgeo.org/">support@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="nutshellmanual">Manual: <a href="http://cgeo.carnero.cc/manual">c:geo in a Nutshell</a></string>
+ <string name="about_go4cache">Service <b>Go 4 Cache</b> shows other geocachers on the map (in <b>c:geo</b> or in browser) in real time. It can show, for example, what cache they\'re searching for. By connecting to <b>Go 4 Cache</b> <b>c:geo</b> is allowed to publish current location when geocaching (only when <b>c:geo</b> is running).</string>
+ <string name="about_twitter">Should <b>c:geo</b> publish new status on Twitter everytime a cache is logged?</string>
+ <string name="about_auth_1">The following process allows <b>c:geo</b> to access Twitter - if agreed.</string>
+ <string name="about_auth_2">Click on \"authorize c:geo\" button will start the process. This process will open up a web browser with Twitter page. Login on this page and allow <b>c:geo</b> to access your account. If accepted, Twitter will show up a numeric PIN code. This PIN must be pasted into <b>c:geo</b> and be confirmed. That\'s all.</string>
+
+ <!-- ====== please, do not translate (and include in translation) things below this line ====== -->
+
+ <!-- contributors -->
+ <string name="contributors">\n
+ · Sony Ericsson (free XPERIA X10 for development)\n
+ \n
+ · 0xErnie (localization DE)\n
+ · Bananeweizen (code, loc. DE)\n
+ · Charles (localization FR)\n
+ · Denny (localization DA)\n
+ · F. Coello (localization ES)\n
+ · Filipe C. (code)\n
+ · <a href="http://iirojappinen.com/">Iiro Jäppinen</a> (graphic)\n
+ · inkantis (localization PL)\n
+ · <a href="http://www.jaytech.cz/">Jan Žatecký</a> (graphic)\n
+ · Pascal (localization NL)\n
+ · Peter (localization HU)\n
+ · Rainer S. (code)\n
+ · Ray (code, loc. JA)\n
+ · <a href="http://seromenho.com/">Ricardo Seromenho</a> (localization PT)\n
+ · serenity (localization FR)\n
+ · Shan, a.k.a. ShakurNO (localization NO)\n
+ · thiasB (code, loc. DE EN)\n
+ · YraFyra (code, loc. SV)\n
+ </string>
+
+ <!-- changelog -->
+ <string name="changelog">\n
+ <b>2.26</b> (__.07.2011)\n
+ · new: Autoinsert of signature\n
+ · new: Send to c:geo from web\n
+ · fix: Live map, better loading\n
+ · fix: Overwriting coords with wrong ones\n
+ · fix: Loading caches on Live map\n
+ · fix: GCVote issues\n
+ \n
+ <b>2.25</b> (11.06.2011)\n
+ · fix: Performance &amp; usability\n
+ · fix: Maps in Japan\n
+ \n
+ <b>2.24</b> (31.05.2011)\n
+ · fix: Performance optimizations\n
+ · fix: Other users on map\n
+ · fix: Displaying single cache on map\n
+ · fix: LOT of different things\n
+ · new: Distance circles for caches\n
+ \n
+ <b>2.22</b> (18.05.2011)\n
+ · fix: Few minor problems\n
+ \n
+ <b>2.21.x</b> (10.05.2011)\n
+ · fix: Names in list\n
+ · fix: Found caches\n
+ · fix: Switching to English\n
+ · fix: Live map\n
+ · fix: Logging of trackables\n
+ \n
+ <b>2.20</b> (06.05.2011)\n
+ · Fixed many issues from prev. version\n
+ · Finished adaptation\n
+ \n
+ <b>2.13.x</b> (05.05.2011)\n
+ · change: Optimized map\n
+ · change: Search for GPX files in /gpx\n
+ · fix: Adaptation on GC.com changes\n
+ · fix: Posting logs with a lot of TBs\n
+ · fix: Logtypes for cache owner\n
+ · fix: Displaying spoiler images\n
+ · missing: Other users on map\n
+ · missing: Action for all TBs when logging\n
+ \n
+ <b>2.13</b> (14.04.2011)\n
+ · fix: Own waypoints on map\n
+ \n
+ <b>2.12, 2.11</b> (13.04.2011)\n
+ · fix: Sorting caches with disabled GPS\n
+ · fix: Compatibility issues for &lt;2.1\n
+ \n
+ <b>2.10</b> (13.04.2011)\n
+ · fix: Moving caches during refresh\n
+ · fix: Opening Radar\n
+ · remove: Closest cache bubble on Live map\n
+ · new: Remembering last used list\n
+ · new: Number of logs in detail\n
+ · new: Sorting caches in list\n
+ \n
+ <b>2.09</b> (24.03.2011)\n
+ · new: Caches lists\n
+ · fix: Disabling of Twitter\n
+ · fix: Unified navigation options\n
+ · fix: Line breaks in logs\n
+ \n
+ <b>2.08</b> (17.03.2011)\n
+ · fix: Faster displaying caches on the map\n
+ · change: Visual style of loading of caches\n
+ · return: Static maps\n
+ \n
+ <b>2.07</b> (16.03.2011)\n
+ · new: Approx. elevation in details\n
+ · new: Terrain preview\n
+ · new: Own waypoints on map\n
+ · new: Translation of description &amp; hint\n
+ · new: Database backup/restore\n
+ · remove: Static maps\n
+ \n
+ <b>2.06</b> (10.03.2011)\n
+ · fix: Size of caches in lists\n
+ · fix: Marking own caches\n
+ · new: Translation PL\n
+ \n
+ <b>2.05</b> (09.03.2011)\n
+ · fix: Marking caches as found\n
+ · fix: Own caches\n
+ · fix: Some optimizations\n
+ · fix: Event caches\n
+ · new: Trackable icon\n
+ · new: Search using HW key\n
+ · new: List of supported apps\n
+ \n
+ <b>2.04</b> (20.02.2011)\n
+ · new: Logs for trackables\n
+ · new: Access to map from "any dest."\n
+ · new: Ability to force English\n
+ · fix: Favorites count\n
+ · update: Translation\n
+ \n
+ <b>2.03</b> (13.02.2011)\n
+ · fix: Loading images in cache description\n
+ · fix: GC/TB code input\n
+ · update: Translation (SV, PT)\n
+ \n
+ <b>2.02</b> (02.02.2011)\n
+ · new: History of logged caches (online&amp;offline)\n
+ · fix: Number of found caches in signature\n
+ · fix: Exact position of caches on Live Map\n
+ · fix: Adaptation for GC.com changes\n
+ \n
+ <b>2.01</b> (23.01.2011)\n
+ · fix: Fixed crashing due to loading large images\n
+ \n
+ <b>2.00</b> (23.01.2011)\n
+ · new: Context menu for geocachers (in cache detail)\n
+ · new: Option to add date, time and signature at once\n
+ · new: Better trackable support\n
+ · new: Signature template\n
+ · new: Any destination saves last used location\n
+ · fix: End of line in logs\n
+ \n</string>
+</resources> \ No newline at end of file
diff --git a/res/values/styles.xml b/res/values/styles.xml
new file mode 100644
index 0000000..bc42e23
--- /dev/null
+++ b/res/values/styles.xml
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<!-- system definitions -->
+ <style name="cgeo" parent="android:Theme.NoTitleBar">
+ </style>
+
+ <style name="button" parent="@android:style/Widget.Button">
+ <item name="android:padding">6dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color</item>
+ <item name="android:background">?button</item>
+ <item name="android:focusable">true</item>
+ <item name="android:clickable">true</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="edittext" parent="@android:style/Widget.EditText">
+ <item name="android:padding">6dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:autoText">true</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color</item>
+ <item name="android:textColorHint">?text_color_hint</item>
+ <item name="android:background">?input</item>
+ <item name="android:focusable">true</item>
+ <item name="android:gravity">top|left</item>
+ <item name="android:capitalize">none</item>
+ </style>
+
+<!-- own definitions -->
+<!-- actionbar -->
+ <style name="action_bar">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@drawable/actionbar_background</item>
+ </style>
+
+ <style name="action_bar_icon_cgeo">
+ <item name="android:layout_width">@dimen/actionbar_height</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:padding">4dip</item>
+ <item name="android:gravity">center</item>
+ <item name="android:scaleType">center</item>
+ <item name="android:src">@drawable/actionbar_cgeo</item>
+ </style>
+
+ <style name="action_bar_action">
+ <item name="android:layout_width">@dimen/actionbar_height</item>
+ <item name="android:layout_height">@dimen/actionbar_height</item>
+ <item name="android:padding">2dip</item>
+ <item name="android:gravity">center</item>
+ <item name="android:scaleType">center</item>
+ <item name="android:src">@drawable/actionbar_home</item>
+ </style>
+
+ <style name="action_bar_separator">
+ <item name="android:layout_width">@dimen/actionbar_separator_width</item>
+ <item name="android:layout_height">@dimen/actionbar_separator_height</item>
+ <item name="android:layout_marginLeft">4dip</item>
+ <item name="android:layout_marginRight">4dip</item>
+ <item name="android:layout_marginTop">4dip</item>
+ <item name="android:layout_marginBottom">4dip</item>
+ <item name="android:gravity">center</item>
+ <item name="android:background">@drawable/actionbar_separator</item>
+ </style>
+
+ <style name="action_bar_progress" parent="@android:style/Widget.ProgressBar.Small">
+ <item name="android:id">@id/actionbar_progress</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">14dip</item>
+ <item name="android:layout_marginRight">15dip</item>
+ <item name="android:layout_marginTop">14dip</item>
+ <item name="android:indeterminate">true</item>
+ </style>
+
+ <style name="action_bar_title">
+ <item name="android:id">@id/actionbar_title</item>
+ <item name="android:layout_width">0dip</item>
+ <item name="android:layout_height">fill_parent</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:padding">4dip</item>
+ <item name="android:gravity">center_vertical|left</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:lines">1</item>
+ <item name="android:textSize">20dip</item>
+ <item name="android:textColor">@color/just_white</item>
+ <item name="android:text">c:geo</item>
+ </style>
+
+<!-- button: full width -->
+ <style name="button">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ </style>
+
+<!-- button: small -->
+ <style name="button_small">
+ <item name="android:layout_width">125dip</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:layout_marginLeft">6dip</item>
+ <item name="android:layout_marginRight">6dip</item>
+ <item name="android:layout_marginTop">3dip</item>
+ <item name="android:layout_marginBottom">3dip</item>
+ <item name="android:padding">3dip</item>
+ <item name="android:textSize">14dip</item>
+ </style>
+
+<!-- edittext -->
+ <style name="edittext">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ </style>
+
+ <style name="edittext_dialog">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">10dip</item>
+ <item name="android:layout_marginRight">10dip</item>
+ <item name="android:layout_marginBottom">5dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ <item name="android:textColorHint">@color/text_hint_dark</item>
+ <item name="android:background">@drawable/input_bcg_dark</item>
+ </style>
+
+<!-- mainscreen icon -->
+ <style name="icon_mainscreen">
+ <item name="android:layout_width">48dip</item>
+ <item name="android:layout_height">48dip</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:gravity">center</item>
+ <item name="android:layout_margin">4dip</item>
+ </style>
+
+ <style name="icon_mainscreen_text">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingTop">1dip</item>
+ <item name="android:paddingBottom">1dip</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">13dip</item>
+ <item name="android:textColor">@color/text_icon</item>
+ <item name="android:background">@drawable/icon_bcg</item>
+ </style>
+
+ <style name="icon_mainscreen_count">
+ <item name="android:visibility">gone</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:layout_alignParentTop">true</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:layout_marginRight">4dip</item>
+ <item name="android:layout_marginLeft">4dip</item>
+ <item name="android:gravity">center</item>
+ <item name="android:paddingTop">2dip</item>
+ <item name="android:paddingBottom">2dip</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:lines">1</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">11dip</item>
+ <item name="android:textColor">@color/just_white</item>
+ <item name="android:background">@drawable/count_bcg</item>
+ <item name="android:text"></item>
+ </style>
+
+<!-- current location -->
+ <style name="location_current">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:paddingLeft">5dip</item>
+ <item name="android:paddingRight">5dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">14dip</item>
+ <item name="android:textColor">@color/text_icon</item>
+ <item name="android:background">@drawable/icon_bcg</item>
+ </style>
+
+ <style name="location_current_type">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_alignParentRight">true</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
+
+ <style name="location_current_accuracy">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_centerHorizontal">true</item>
+ <item name="android:layout_gravity">right</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
+
+ <style name="location_current_satellites">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentBottom">true</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:layout_gravity">left</item>
+ <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingRight">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">12dip</item>
+ <item name="android:textColor">@color/text_dark</item>
+ </style>
+
+<!-- separators -->
+ <style name="separator_horizontal">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">1dip</item>
+ <item name="android:layout_centerInParent">true</item>
+ <item name="android:background">?separator_color</item>
+ </style>
+
+ <style name="separator_horizontal_layout">
+ <item name="android:layout_width">fill_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginTop">2dip</item>
+ <item name="android:layout_marginBottom">2dip</item>
+ </style>
+
+ <style name="separator_horizontal_headline">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_alignParentLeft">true</item>
+ <item name="android:layout_marginLeft">15dip</item>
+ <item name="android:padding">3dip</item>
+ <item name="android:lines">1</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:scrollHorizontally">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">22dip</item>
+ <item name="android:textColor">?text_color_headline</item>
+ <item name="android:background">?background_color</item>
+ </style>
+</resources>
diff --git a/res/values/themes.xml b/res/values/themes.xml
new file mode 100644
index 0000000..90d886c
--- /dev/null
+++ b/res/values/themes.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="cgeo" parent="android:Theme.NoTitleBar">
+ <!-- system elements -->
+ <item name="android:buttonStyle">@style/button</item>
+ <item name="android:editTextStyle">@style/edittext</item>
+ </style>
+
+ <style name="cgeo_transparent" parent="android:Theme.Dialog">
+ <!-- system elements -->
+ <item name="android:buttonStyle">@style/button</item>
+ <item name="android:editTextStyle">@style/edittext</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ </style>
+
+ <style name="dark" parent="cgeo">
+ <!-- system values -->
+
+ <!-- own values: colors -->
+ <item name="just_color">@color/just_black</item>
+ <item name="text_color">@color/text_dark</item>
+ <item name="text_color_headline">@color/text_headline_dark</item>
+ <item name="text_color_grey">@color/text_grey_dark</item>
+ <item name="text_color_hint">@color/text_hint_dark</item>
+ <item name="text_color_link">@color/link</item>
+ <item name="button_color_enabled">@color/button_enabled</item>
+ <item name="button_color_disabled">@color/button_disabled</item>
+ <item name="background_color">@color/background_dark</item>
+ <item name="background_color_notice">@color/background_dark_notice</item>
+ <item name="background_color_transparent">@color/background_dark_transparent</item>
+ <item name="separator_color">@color/separator_dark</item>
+
+ <!-- own values: drawables -->
+ <item name="button">@drawable/action_button_dark</item>
+ <item name="input">@drawable/input_bcg_dark</item>
+ <item name="inventory">@drawable/inventory_background_dark</item>
+ <item name="favourite">@drawable/favourite_background_dark</item>
+ <item name="favourite_r">@drawable/favourite_background_red_dark</item>
+ <item name="favourite_o">@drawable/favourite_background_orange_dark</item>
+ <item name="favourite_g">@drawable/favourite_background_green_dark</item>
+ <item name="close">@drawable/map_close_dark</item>
+
+ <!-- own values: other -->
+ <item name="compass">0</item>
+ </style>
+
+ <style name="light" parent="cgeo">
+ <!-- system values -->
+
+ <!-- own values: colors -->
+ <item name="just_color">@color/just_black</item>
+ <item name="text_color">@color/text_light</item>
+ <item name="text_color_headline">@color/text_headline_light</item>
+ <item name="text_color_grey">@color/text_grey_light</item>
+ <item name="text_color_hint">@color/text_hint_light</item>
+ <item name="text_color_link">@color/link</item>
+ <item name="button_color_enabled">@color/button_enabled</item>
+ <item name="button_color_disabled">@color/button_disabled</item>
+ <item name="background_color">@color/background_light</item>
+ <item name="background_color_notice">@color/background_light_notice</item>
+ <item name="background_color_transparent">@color/background_light_transparent</item>
+ <item name="separator_color">@color/separator_light</item>
+
+ <!-- own values: drawables -->
+ <item name="button">@drawable/action_button_light</item>
+ <item name="input">@drawable/input_bcg_light</item>
+ <item name="inventory">@drawable/inventory_background_light</item>
+ <item name="favourite">@drawable/favourite_background_light</item>
+ <item name="favourite_r">@drawable/favourite_background_red_light</item>
+ <item name="favourite_o">@drawable/favourite_background_orange_light</item>
+ <item name="favourite_g">@drawable/favourite_background_green_light</item>
+ <item name="close">@drawable/map_close_light</item>
+
+ <!-- own values: other -->
+ <item name="compass">1</item>
+ </style>
+
+ <style name="transparent" parent="cgeo_transparent">
+ <!-- system values -->
+
+ <!-- own values: colors -->
+ <item name="just_color">@color/just_black</item>
+ <item name="text_color">@color/text_dark</item>
+ <item name="text_color_headline">@color/text_headline_dark</item>
+ <item name="text_color_grey">@color/text_grey_dark</item>
+ <item name="text_color_hint">@color/text_hint_dark</item>
+ <item name="text_color_link">@color/link</item>
+ <item name="button_color_enabled">@color/button_enabled</item>
+ <item name="button_color_disabled">@color/button_disabled</item>
+ <item name="background_color">@color/background_dark</item>
+ <item name="background_color_notice">@color/background_dark_notice</item>
+ <item name="background_color_transparent">@color/background_dark_transparent</item>
+ <item name="separator_color">@color/separator_dark</item>
+
+ <!-- own values: drawables -->
+ <item name="button">@drawable/action_button_dark</item>
+ <item name="input">@drawable/input_bcg_dark</item>
+ <item name="inventory">@drawable/inventory_background_dark</item>
+ <item name="favourite">@drawable/favourite_background_dark</item>
+ <item name="favourite_r">@drawable/favourite_background_red_dark</item>
+ <item name="favourite_o">@drawable/favourite_background_orange_dark</item>
+ <item name="favourite_g">@drawable/favourite_background_green_dark</item>
+ <item name="close">@drawable/map_close_dark</item>
+
+ <!-- own values: other -->
+ <item name="compass">0</item>
+ </style>
+</resources>
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
new file mode 100644
index 0000000..b11d6bc
--- /dev/null
+++ b/res/xml/searchable.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+ android:label="@string/app_name"
+ android:hint="@string/search_bar_hint"
+ android:searchSettingsDescription="@string/search_bar_desc"
+ android:includeInGlobalSearch="true"
+ android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
+</searchable> \ No newline at end of file
diff --git a/src/cgeo/geocaching/cg8.java b/src/cgeo/geocaching/cg8.java
new file mode 100644
index 0000000..698988e
--- /dev/null
+++ b/src/cgeo/geocaching/cg8.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.view.Display;
+
+public class cg8 {
+ private Activity activity = null;
+
+ public cg8(Activity activityIn) {
+ activity = activityIn;
+ }
+
+ public int getRotation() {
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ return display.getRotation();
+ }
+}
diff --git a/src/cgeo/geocaching/cg8wrap.java b/src/cgeo/geocaching/cg8wrap.java
new file mode 100644
index 0000000..2903c8d
--- /dev/null
+++ b/src/cgeo/geocaching/cg8wrap.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+
+public class cg8wrap {
+ static {
+ try {
+ Class.forName("cgeo.geocaching.cg8");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private cg8 cg8;
+
+ public static void check() {
+ // nothing
+ }
+
+ public cg8wrap(Activity activityIn) {
+ cg8 = new cg8(activityIn);
+ }
+
+ public int getRotation() {
+ return cg8.getRotation();
+ }
+}
diff --git a/src/cgeo/geocaching/cgAddressImg.java b/src/cgeo/geocaching/cgAddressImg.java
new file mode 100644
index 0000000..bdc0ccf
--- /dev/null
+++ b/src/cgeo/geocaching/cgAddressImg.java
@@ -0,0 +1,60 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import android.graphics.Rect;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgAddressImg {
+ public static BitmapDrawable getDrawable(String url) {
+ Bitmap imagePre = null;
+
+ if (url == null || url.length() == 0) return null;
+
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ for (int i = 0; i < 2; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgAddressImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ Log.i(cgSettings.tag, "[" + entity.getContentLength() + "B] Downloading address map " + url);
+
+ if (bufferedEntity != null) imagePre = BitmapFactory.decodeStream(bufferedEntity.getContent(), null, null);
+ if (imagePre != null) break;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgAddressImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+
+ if (imagePre == null) {
+ Log.d(cgSettings.tag, "cgAddressImg.getDrawable: Failed to obtain image");
+
+ return null;
+ }
+
+ final BitmapDrawable image = new BitmapDrawable(imagePre);
+ image.setBounds(new Rect(0, 0, imagePre.getWidth(), imagePre.getHeight()));
+
+ // imagePre.recycle();
+ imagePre = null;
+
+ return image;
+ }
+}
diff --git a/src/cgeo/geocaching/cgBase.java b/src/cgeo/geocaching/cgBase.java
new file mode 100644
index 0000000..9a13bda
--- /dev/null
+++ b/src/cgeo/geocaching/cgBase.java
@@ -0,0 +1,5828 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.net.URLConnection;
+import java.net.HttpURLConnection;
+import java.util.Map;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import android.util.Log;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.style.StrikethroughSpan;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.URLDecoder;
+import java.security.MessageDigest;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class cgBase {
+
+ public static HashMap<String, String> cacheTypes = new HashMap<String, String>();
+ public static HashMap<String, String> cacheTypesInv = new HashMap<String, String>();
+ public static HashMap<String, String> cacheIDs = new HashMap<String, String>();
+ public static HashMap<String, String> cacheIDsChoices = new HashMap<String, String>();
+ public static HashMap<String, String> waypointTypes = new HashMap<String, String>();
+ public static HashMap<String, Integer> logTypes = new HashMap<String, Integer>();
+ public static HashMap<String, Integer> logTypes0 = new HashMap<String, Integer>();
+ public static HashMap<Integer, String> logTypes1 = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypes2 = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypesTrackable = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> logTypesTrackableAction = new HashMap<Integer, String>();
+ public static HashMap<Integer, String> errorRetrieve = new HashMap<Integer, String>();
+ public static SimpleDateFormat dateIn = new SimpleDateFormat("MM/dd/yyyy");
+ public static SimpleDateFormat dateEvIn = new SimpleDateFormat("dd MMMMM yyyy", Locale.ENGLISH); // 28 March 2009
+ public static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
+ public static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
+ public static SimpleDateFormat dateSqlIn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 2010-07-25 14:44:01
+ public static SimpleDateFormat dateGPXIn = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // 2010-04-20T07:00:00Z
+ public static DateFormat dateOut = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());
+ public static DateFormat timeOut = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault());
+ public static DateFormat dateOutShort = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
+ private Resources res = null;
+ private HashMap<String, String> cookies = new HashMap<String, String>();
+ private final String passMatch = "[/\\?&]*[Pp]ass(word)?=[^&^#^$]+";
+ private final Pattern patternLoggedIn = Pattern.compile("<span class=\"Success\">You are logged in as[^<]*<strong[^>]*>([^<]+)</strong>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternLogged2In = Pattern.compile("<strong>[^\\w]*Hello,[^<]*<a[^>]+>([^<]+)</a>[^<]*</strong>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternViewstate = Pattern.compile("id=\"__VIEWSTATE\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ private final Pattern patternViewstate1 = Pattern.compile("id=\"__VIEWSTATE1\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ public static final double kmInMiles = 1 / 1.609344;
+ public static final double deg2rad = Math.PI / 180;
+ public static final double rad2deg = 180 / Math.PI;
+ public static final float erad = 6371.0f;
+ public static final int mapAppAny = 0;
+ public static final int mapAppLocus = 1;
+ public static final int mapAppRmaps = 2;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ public String version = null;
+ private String idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4";
+ Context context = null;
+ final private static HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ final private static HashMap<String, Integer> wpIcons = new HashMap<String, Integer>();
+
+ public static final int LOG_FOUND_IT = 2;
+ public static final int LOG_DIDNT_FIND_IT = 3;
+ public static final int LOG_NOTE = 4;
+ public static final int LOG_PUBLISH_LISTING = 1003; // unknown ID; used number doesn't match any GC.com's ID
+ public static final int LOG_ENABLE_LISTING = 23;
+ public static final int LOG_ARCHIVE = 5;
+ public static final int LOG_TEMP_DISABLE_LISTING = 22;
+ public static final int LOG_NEEDS_ARCHIVE = 7;
+ public static final int LOG_WILL_ATTEND = 9;
+ public static final int LOG_ATTENDED = 10;
+ public static final int LOG_RETRIEVED_IT = 13;
+ public static final int LOG_PLACED_IT = 14;
+ public static final int LOG_GRABBED_IT = 19;
+ public static final int LOG_NEEDS_MAINTENANCE = 45;
+ public static final int LOG_OWNER_MAINTENANCE = 46;
+ public static final int LOG_UPDATE_COORDINATES = 47;
+ public static final int LOG_DISCOVERED_IT = 48;
+ public static final int LOG_POST_REVIEWER_NOTE = 18;
+ public static final int LOG_VISIT = 1001; // unknown ID; used number doesn't match any GC.com's ID
+ public static final int LOG_WEBCAM_PHOTO_TAKEN = 11;
+ public static final int LOG_ANNOUNCEMENT = 74;
+
+ public cgBase(cgeoapplication appIn, cgSettings settingsIn, SharedPreferences prefsIn) {
+ context = appIn.getBaseContext();
+ res = appIn.getBaseContext().getResources();
+
+ // cache types
+ cacheTypes.put("traditional cache", "traditional");
+ cacheTypes.put("multi-cache", "multi");
+ cacheTypes.put("unknown cache", "mystery");
+ cacheTypes.put("letterbox hybrid", "letterbox");
+ cacheTypes.put("event cache", "event");
+ cacheTypes.put("mega-event cache", "mega");
+ cacheTypes.put("earthcache", "earth");
+ cacheTypes.put("cache in trash out event", "cito");
+ cacheTypes.put("webcam cache", "webcam");
+ cacheTypes.put("virtual cache", "virtual");
+ cacheTypes.put("wherigo cache", "wherigo");
+ cacheTypes.put("lost & found", "lostfound");
+ cacheTypes.put("project ape cache", "ape");
+ cacheTypes.put("groundspeak hq", "gchq");
+ cacheTypes.put("gps cache exhibit", "gps");
+
+ // cache types inverted
+ cacheTypesInv.put("traditional", res.getString(R.string.traditional));
+ cacheTypesInv.put("multi", res.getString(R.string.multi));
+ cacheTypesInv.put("mystery", res.getString(R.string.mystery));
+ cacheTypesInv.put("letterbox", res.getString(R.string.letterbox));
+ cacheTypesInv.put("event", res.getString(R.string.event));
+ cacheTypesInv.put("mega", res.getString(R.string.mega));
+ cacheTypesInv.put("earth", res.getString(R.string.earth));
+ cacheTypesInv.put("cito", res.getString(R.string.cito));
+ cacheTypesInv.put("webcam", res.getString(R.string.webcam));
+ cacheTypesInv.put("virtual", res.getString(R.string.virtual));
+ cacheTypesInv.put("wherigo", res.getString(R.string.wherigo));
+ cacheTypesInv.put("lostfound", res.getString(R.string.lostfound));
+ cacheTypesInv.put("ape", res.getString(R.string.ape));
+ cacheTypesInv.put("gchq", res.getString(R.string.gchq));
+ cacheTypesInv.put("gps", res.getString(R.string.gps));
+
+ // cache ids
+ cacheIDs.put("all", "9a79e6ce-3344-409c-bbe9-496530baf758"); // hard-coded also in cgSettings
+ cacheIDs.put("traditional", "32bc9333-5e52-4957-b0f6-5a2c8fc7b257");
+ cacheIDs.put("multi", "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74");
+ cacheIDs.put("mystery", "40861821-1835-4e11-b666-8d41064d03fe");
+ cacheIDs.put("letterbox", "4bdd8fb2-d7bc-453f-a9c5-968563b15d24");
+ cacheIDs.put("event", "69eb8534-b718-4b35-ae3c-a856a55b0874");
+ cacheIDs.put("mega-event", "69eb8535-b718-4b35-ae3c-a856a55b0874");
+ cacheIDs.put("earth", "c66f5cf3-9523-4549-b8dd-759cd2f18db8");
+ cacheIDs.put("cito", "57150806-bc1a-42d6-9cf0-538d171a2d22");
+ cacheIDs.put("webcam", "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d");
+ cacheIDs.put("virtual", "294d4360-ac86-4c83-84dd-8113ef678d7e");
+ cacheIDs.put("wherigo", "0544fa55-772d-4e5c-96a9-36a51ebcf5c9");
+ cacheIDs.put("lostfound", "3ea6533d-bb52-42fe-b2d2-79a3424d4728");
+ cacheIDs.put("ape", "2555690d-b2bc-4b55-b5ac-0cb704c0b768");
+ cacheIDs.put("gchq", "416f2494-dc17-4b6a-9bab-1a29dd292d8c");
+ cacheIDs.put("gps", "72e69af2-7986-4990-afd9-bc16cbbb4ce3");
+
+ // cache choices
+ cacheIDsChoices.put(res.getString(R.string.all), cacheIDs.get("all"));
+ cacheIDsChoices.put(res.getString(R.string.traditional), cacheIDs.get("traditional"));
+ cacheIDsChoices.put(res.getString(R.string.multi), cacheIDs.get("multi"));
+ cacheIDsChoices.put(res.getString(R.string.mystery), cacheIDs.get("mystery"));
+ cacheIDsChoices.put(res.getString(R.string.letterbox), cacheIDs.get("letterbox"));
+ cacheIDsChoices.put(res.getString(R.string.event), cacheIDs.get("event"));
+ cacheIDsChoices.put(res.getString(R.string.mega), cacheIDs.get("mega"));
+ cacheIDsChoices.put(res.getString(R.string.earth), cacheIDs.get("earth"));
+ cacheIDsChoices.put(res.getString(R.string.cito), cacheIDs.get("cito"));
+ cacheIDsChoices.put(res.getString(R.string.webcam), cacheIDs.get("webcam"));
+ cacheIDsChoices.put(res.getString(R.string.virtual), cacheIDs.get("virtual"));
+ cacheIDsChoices.put(res.getString(R.string.wherigo), cacheIDs.get("whereigo"));
+ cacheIDsChoices.put(res.getString(R.string.lostfound), cacheIDs.get("lostfound"));
+ cacheIDsChoices.put(res.getString(R.string.ape), cacheIDs.get("ape"));
+ cacheIDsChoices.put(res.getString(R.string.gchq), cacheIDs.get("gchq"));
+ cacheIDsChoices.put(res.getString(R.string.gps), cacheIDs.get("gps"));
+
+ // waypoint types
+ waypointTypes.put("flag", res.getString(R.string.wp_final));
+ waypointTypes.put("stage", res.getString(R.string.wp_stage));
+ waypointTypes.put("puzzle", res.getString(R.string.wp_puzzle));
+ waypointTypes.put("pkg", res.getString(R.string.wp_pkg));
+ waypointTypes.put("trailhead", res.getString(R.string.wp_trailhead));
+ waypointTypes.put("waypoint", res.getString(R.string.wp_waypoint));
+
+ // log types
+ logTypes.put("icon_smile", LOG_FOUND_IT);
+ logTypes.put("icon_sad", LOG_DIDNT_FIND_IT);
+ logTypes.put("icon_note", LOG_NOTE);
+ logTypes.put("icon_greenlight", LOG_PUBLISH_LISTING);
+ logTypes.put("icon_enabled", LOG_ENABLE_LISTING);
+ logTypes.put("traffic_cone", LOG_ARCHIVE);
+ logTypes.put("icon_disabled", LOG_TEMP_DISABLE_LISTING);
+ logTypes.put("icon_remove", LOG_NEEDS_ARCHIVE);
+ logTypes.put("icon_rsvp", LOG_WILL_ATTEND);
+ logTypes.put("icon_attended", LOG_ATTENDED);
+ logTypes.put("picked_up", LOG_RETRIEVED_IT);
+ logTypes.put("dropped_off", LOG_PLACED_IT);
+ logTypes.put("transfer", LOG_GRABBED_IT);
+ logTypes.put("icon_needsmaint", LOG_NEEDS_MAINTENANCE);
+ logTypes.put("icon_maint", LOG_OWNER_MAINTENANCE);
+ logTypes.put("coord_update", LOG_UPDATE_COORDINATES);
+ logTypes.put("icon_discovered", LOG_DISCOVERED_IT);
+ logTypes.put("big_smile", LOG_POST_REVIEWER_NOTE);
+ logTypes.put("icon_visited", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes.put("icon_camera", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes.put("icon_announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID
+
+ logTypes0.put("found it", LOG_FOUND_IT);
+ logTypes0.put("didn't find it", LOG_DIDNT_FIND_IT);
+ logTypes0.put("write note", LOG_NOTE);
+ logTypes0.put("publish listing", LOG_PUBLISH_LISTING);
+ logTypes0.put("enable listing", LOG_ENABLE_LISTING);
+ logTypes0.put("archive", LOG_ARCHIVE);
+ logTypes0.put("temporarily disable listing", LOG_TEMP_DISABLE_LISTING);
+ logTypes0.put("needs archived", LOG_NEEDS_ARCHIVE);
+ logTypes0.put("will attend", LOG_WILL_ATTEND);
+ logTypes0.put("attended", LOG_ATTENDED);
+ logTypes0.put("retrieved it", LOG_RETRIEVED_IT);
+ logTypes0.put("placed it", LOG_PLACED_IT);
+ logTypes0.put("grabbed it", LOG_GRABBED_IT);
+ logTypes0.put("needs maintenance", LOG_NEEDS_MAINTENANCE);
+ logTypes0.put("owner maintenance", LOG_OWNER_MAINTENANCE);
+ logTypes0.put("update coordinates", LOG_UPDATE_COORDINATES);
+ logTypes0.put("discovered it", LOG_DISCOVERED_IT);
+ logTypes0.put("post reviewer note", LOG_POST_REVIEWER_NOTE);
+ logTypes0.put("visit", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes0.put("webcam photo taken", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID
+ logTypes0.put("announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID
+
+ logTypes1.put(LOG_FOUND_IT, res.getString(R.string.log_found));
+ logTypes1.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf));
+ logTypes1.put(LOG_NOTE, res.getString(R.string.log_note));
+ logTypes1.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published));
+ logTypes1.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled));
+ logTypes1.put(LOG_ARCHIVE, res.getString(R.string.log_archived));
+ logTypes1.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled));
+ logTypes1.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived));
+ logTypes1.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend));
+ logTypes1.put(LOG_ATTENDED, res.getString(R.string.log_attended));
+ logTypes1.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved));
+ logTypes1.put(LOG_PLACED_IT, res.getString(R.string.log_placed));
+ logTypes1.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed));
+ logTypes1.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed));
+ logTypes1.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained));
+ logTypes1.put(LOG_UPDATE_COORDINATES, res.getString(R.string.log_update));
+ logTypes1.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered));
+ logTypes1.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed));
+ logTypes1.put(LOG_VISIT, res.getString(R.string.log_taken));
+ logTypes1.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam));
+ logTypes1.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement));
+
+ logTypes2.put(LOG_FOUND_IT, res.getString(R.string.log_found)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox
+ logTypes2.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_NOTE, res.getString(R.string.log_note)); // traditional, multi, unknown, earth, wherigo, virtual, event, letterbox, webcam, trackable
+ logTypes2.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published)); // X
+ logTypes2.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled)); // owner
+ logTypes2.put(LOG_ARCHIVE, res.getString(R.string.log_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled)); // owner
+ logTypes2.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend)); // event
+ logTypes2.put(LOG_ATTENDED, res.getString(R.string.log_attended)); // event
+ logTypes2.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam)); // webcam
+ logTypes2.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved)); //trackable
+ logTypes2.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed)); //trackable
+ logTypes2.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed)); // traditional, unknown, multi, wherigo, virtual, letterbox, webcam
+ logTypes2.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained)); // owner
+ logTypes2.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered)); //trackable
+ logTypes2.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed)); // X
+ logTypes2.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement)); // X
+
+ // trackables for logs
+ logTypesTrackable.put(0, res.getString(R.string.log_tb_nothing)); // do nothing
+ logTypesTrackable.put(1, res.getString(R.string.log_tb_visit)); // visit cache
+ logTypesTrackable.put(2, res.getString(R.string.log_tb_drop)); // drop here
+ logTypesTrackableAction.put(0, ""); // do nothing
+ logTypesTrackableAction.put(1, "_Visited"); // visit cache
+ logTypesTrackableAction.put(2, "_DroppedOff"); // drop here
+
+ // retrieving errors (because of ____ )
+ errorRetrieve.put(1, res.getString(R.string.err_none));
+ errorRetrieve.put(0, res.getString(R.string.err_start));
+ errorRetrieve.put(-1, res.getString(R.string.err_parse));
+ errorRetrieve.put(-2, res.getString(R.string.err_server));
+ errorRetrieve.put(-3, res.getString(R.string.err_login));
+ errorRetrieve.put(-4, res.getString(R.string.err_unknown));
+ errorRetrieve.put(-5, res.getString(R.string.err_comm));
+ errorRetrieve.put(-6, res.getString(R.string.err_wrong));
+ errorRetrieve.put(-7, res.getString(R.string.err_license));
+
+ // init
+ app = appIn;
+ settings = settingsIn;
+ prefs = prefsIn;
+
+ try {
+ PackageManager manager = app.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0);
+ version = info.versionName;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (settings.asBrowser == 1) {
+ final long rndBrowser = Math.round(Math.random() * 6);
+ if (rndBrowser == 0) {
+ idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.322.2 Safari/533.1";
+ } else if (rndBrowser == 1) {
+ idBrowser = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)";
+ } else if (rndBrowser == 2) {
+ idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3";
+ } else if (rndBrowser == 3) {
+ idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10";
+ } else if (rndBrowser == 4) {
+ idBrowser = "Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11a Safari/525.20";
+ } else if (rndBrowser == 5) {
+ idBrowser = "Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2";
+ } else if (rndBrowser == 6) {
+ idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4";
+ } else {
+ idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9";
+ }
+ }
+ }
+
+ public String findViewstate(String page, int index) {
+ String viewstate = null;
+
+ if (index == 0) {
+ final Matcher matcherViewstate = patternViewstate.matcher(page);
+ while (matcherViewstate.find()) {
+ if (matcherViewstate.groupCount() > 0) {
+ viewstate = matcherViewstate.group(1);
+ }
+ }
+ } else if (index == 1) {
+ final Matcher matcherViewstate = patternViewstate1.matcher(page);
+ while (matcherViewstate.find()) {
+ if (matcherViewstate.groupCount() > 0) {
+ viewstate = matcherViewstate.group(1);
+ }
+ }
+ }
+
+ return viewstate;
+ }
+
+ public class loginThread extends Thread {
+
+ @Override
+ public void run() {
+ login();
+ }
+ }
+
+ public int login() {
+ final String host = "www.geocaching.com";
+ final String path = "/login/default.aspx";
+ cgResponse loginResponse = null;
+ String loginData = null;
+
+ String viewstate = null;
+ String viewstate1 = null;
+
+ final HashMap<String, String> loginStart = settings.getLogin();
+
+ if (loginStart == null) {
+ return -3; // no login information stored
+ }
+
+ loginResponse = request(true, host, path, "GET", new HashMap<String, String>(), false, false, false);
+ loginData = loginResponse.getData();
+ if (loginData != null && loginData.length() > 0) {
+ if (checkLogin(loginData) == true) {
+ Log.i(cgSettings.tag, "Already logged in Geocaching.com as " + loginStart.get("username"));
+
+ switchToEnglish(viewstate, viewstate1);
+
+ return 1; // logged in
+ }
+
+ viewstate = findViewstate(loginData, 0);
+ viewstate1 = findViewstate(loginData, 1);
+
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to find viewstate");
+ return -1; // no viewstate
+ }
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (1st)");
+ return -2; // no loginpage
+ }
+
+ final HashMap<String, String> login = settings.getLogin();
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ if (login == null || login.get("username") == null || login.get("username").length() == 0 || login.get("password") == null || login.get("password").length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.login: No login information stored");
+ return -3;
+ }
+
+ settings.deleteCookies();
+
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("ctl00$SiteContent$tbUsername", login.get("username"));
+ params.put("ctl00$SiteContent$tbPassword", login.get("password"));
+ params.put("ctl00$SiteContent$cbRememberMe", "on");
+ params.put("ctl00$SiteContent$btnSignIn", "Login");
+
+ loginResponse = request(true, host, path, "POST", params, false, false, false);
+ loginData = loginResponse.getData();
+
+ if (loginData != null && loginData.length() > 0) {
+ if (checkLogin(loginData) == true) {
+ Log.i(cgSettings.tag, "Successfully logged in Geocaching.com as " + login.get("username"));
+
+ switchToEnglish(findViewstate(loginData, 0), findViewstate(loginData, 1));
+
+ return 1; // logged in
+ } else {
+ if (loginData.indexOf("Your username/password combination does not match.") != -1) {
+ Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " because of wrong username/password");
+
+ return -6; // wrong login
+ } else {
+ Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " for some unknown reason");
+
+ return -4; // can't login
+ }
+ }
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)");
+
+ return -5; // no login page
+ }
+ }
+
+ public Boolean checkLogin(String page) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.checkLogin: No page given");
+ return false;
+ }
+
+ // on every page
+ final Matcher matcherLogged2In = patternLogged2In.matcher(page);
+ while (matcherLogged2In.find()) {
+ return true;
+ }
+
+ // after login
+ final Matcher matcherLoggedIn = patternLoggedIn.matcher(page);
+ while (matcherLoggedIn.find()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public String switchToEnglish(String viewstate, String viewstate1) {
+ final String host = "www.geocaching.com";
+ final String path = "/default.aspx";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ if (viewstate != null) {
+ params.put("__VIEWSTATE", viewstate);
+ }
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem"); // switch to english
+ params.put("__EVENTARGUMENT", "");
+
+ return request(false, host, path, "POST", params, false, false, false).getData();
+ }
+
+ public cgCacheWrap parseSearch(cgSearchThread thread, String url, String page, boolean showCaptcha) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: No page given");
+ return null;
+ }
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ final ArrayList<String> cids = new ArrayList<String>();
+ final ArrayList<String> guids = new ArrayList<String>();
+ String recaptchaChallenge = null;
+ String recaptchaText = null;
+
+ caches.url = url;
+
+ final Pattern patternCacheType = Pattern.compile("<td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=[^\"]+\"[^>]+>[^<]*<img src=\"[^\"]*/images/wpttypes/[^\\.]+\\.gif\" alt=\"([^\"]+)\" title=\"[^\"]+\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternGuidAndDisabled = Pattern.compile("<img src=\"[^\"]*/images/wpttypes/[^>]*>[^<]*</a></td><td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=([a-z0-9\\-]+)\" class=\"lnk([^\"]*)\">([^<]*<span>)?([^<]*)(</span>[^<]*)?</a>[^<]+<br />([^<]*)<span[^>]+>([^<]*)</span>([^<]*<img[^>]+>)?[^<]*<br />[^<]*</td>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternTbs = Pattern.compile("<a id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxTravelBugList\" class=\"tblist\" data-tbcount=\"([0-9]+)\" data-id=\"[^\"]*\"[^>]*>(.*)</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternTbsInside = Pattern.compile("(<img src=\"[^\"]+\" alt=\"([^\"]+)\" title=\"[^\"]*\" />[^<]*)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternDirection = Pattern.compile("<img id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxDistanceAndHeading\" title=\"[^\"]*\" src=\"[^\"]*/seek/CacheDir\\.ashx\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCode = Pattern.compile("\\|[^\\w]*(GC[a-z0-9]+)[^\\|]*\\|", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternId = Pattern.compile("name=\"CID\"[^v]*value=\"([0-9]+)\"", Pattern.CASE_INSENSITIVE);
+ final Pattern patternFavourite = Pattern.compile("<span id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxFavoritesValue\" title=\"[^\"]*\" class=\"favorite-rank\">([0-9]+)</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternTotalCnt = Pattern.compile("<td class=\"PageBuilderWidget\"><span>Total Records[^<]*<b>(\\d+)<\\/b>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRecaptcha = Pattern.compile("<script[^>]*src=\"[^\"]*/recaptcha/api/challenge\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRecaptchaChallenge = Pattern.compile("challenge : '([^']+)'", Pattern.CASE_INSENSITIVE);
+
+ caches.viewstate = findViewstate(page, 0);
+ caches.viewstate1 = findViewstate(page, 1);
+
+ // recaptcha
+ if (showCaptcha == true) {
+ try {
+ String recaptchaJsParam = null;
+ final Matcher matcherRecaptcha = patternRecaptcha.matcher(page);
+ while (matcherRecaptcha.find()) {
+ if (matcherRecaptcha.groupCount() > 0) {
+ recaptchaJsParam = matcherRecaptcha.group(1);
+ }
+ }
+
+ if (recaptchaJsParam != null) {
+ final String recaptchaJs = request(false, "www.google.com", "/recaptcha/api/challenge", "GET", "k=" + urlencode_rfc3986(recaptchaJsParam.trim()), 0, true).getData();
+
+ if (recaptchaJs != null && recaptchaJs.length() > 0) {
+ final Matcher matcherRecaptchaChallenge = patternRecaptchaChallenge.matcher(recaptchaJs);
+ while (matcherRecaptchaChallenge.find()) {
+ if (matcherRecaptchaChallenge.groupCount() > 0) {
+ recaptchaChallenge = matcherRecaptchaChallenge.group(1).trim();
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse recaptcha challenge
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse recaptcha challenge");
+ }
+
+ if (thread != null && recaptchaChallenge != null && recaptchaChallenge.length() > 0) {
+ thread.setChallenge(recaptchaChallenge);
+ thread.notifyNeed();
+ }
+ }
+
+ int startPos = -1;
+ int endPos = -1;
+
+ startPos = page.indexOf("<div id=\"ctl00_ContentBody_ResultsPanel\"");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <table
+
+ startPos = page.indexOf(">");
+ endPos = page.indexOf("ctl00_ContentBody_UnitTxt");
+ if (startPos == -1 || endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page");
+ return null;
+ }
+
+ 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;
+
+ for (int z = 1; z < rows_count; z++) {
+ cgCache cache = new cgCache();
+ String row = rows[z];
+
+ // check for cache type presence
+ if (row.indexOf("images/wpttypes") == -1) {
+ continue;
+ }
+
+ try {
+ final Matcher matcherGuidAndDisabled = patternGuidAndDisabled.matcher(row);
+
+ while (matcherGuidAndDisabled.find()) {
+ if (matcherGuidAndDisabled.groupCount() > 0) {
+ guids.add(matcherGuidAndDisabled.group(1));
+
+ cache.guid = matcherGuidAndDisabled.group(1);
+ if (matcherGuidAndDisabled.group(4) != null) {
+ cache.name = Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString();
+ }
+ if (matcherGuidAndDisabled.group(6) != null) {
+ cache.location = Html.fromHtml(matcherGuidAndDisabled.group(6).trim()).toString();
+ }
+
+ final String attr = matcherGuidAndDisabled.group(2);
+ if (attr != null) {
+ if (attr.contains("Strike") == true) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+
+ if (attr.contains("OldWarning") == true) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse GUID and/or Disabled
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data");
+ }
+
+ if (settings.excludeDisabled == 1 && (cache.disabled == true || cache.archived == true)) {
+ // skip disabled and archived caches
+ cache = null;
+ continue;
+ }
+
+ String inventoryPre = null;
+
+ // GC* code
+ try {
+ final Matcher matcherCode = patternCode.matcher(row);
+ while (matcherCode.find()) {
+ if (matcherCode.groupCount() > 0) {
+ cache.geocode = matcherCode.group(1).toUpperCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse code
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache code");
+ }
+
+ // cache type
+ try {
+ final Matcher matcherCacheType = patternCacheType.matcher(row);
+ while (matcherCacheType.find()) {
+ if (matcherCacheType.groupCount() > 0) {
+ cache.type = cacheTypes.get(matcherCacheType.group(1).toLowerCase());
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache type");
+ }
+
+ // cache direction - image
+ try {
+ final Matcher matcherDirection = patternDirection.matcher(row);
+ while (matcherDirection.find()) {
+ if (matcherDirection.groupCount() > 0) {
+ cache.directionImg = matcherDirection.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse direction image
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache direction image");
+ }
+
+ // cache inventory
+ try {
+ final Matcher matcherTbs = patternTbs.matcher(row);
+ while (matcherTbs.find()) {
+ if (matcherTbs.groupCount() > 0) {
+ cache.inventoryItems = Integer.parseInt(matcherTbs.group(1));
+ inventoryPre = matcherTbs.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse inventory
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory (1)");
+ }
+
+ if (inventoryPre != null && inventoryPre.trim().length() > 0) {
+ try {
+ final Matcher matcherTbsInside = patternTbsInside.matcher(inventoryPre);
+ while (matcherTbsInside.find()) {
+ if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null) {
+ final String inventoryItem = matcherTbsInside.group(2).toLowerCase();
+ if (inventoryItem.equals("premium member only cache")) {
+ continue;
+ } else {
+ if (cache.inventoryItems <= 0) {
+ cache.inventoryItems = 1;
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache inventory info
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory info");
+ }
+ }
+
+ // premium cache
+ if (row.indexOf("/images/small_profile.gif") != -1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+
+ // found it
+ if (row.indexOf("/images/icons/icon_smile") != -1) {
+ cache.found = true;
+ } else {
+ cache.found = false;
+ }
+
+ // own it
+ if (row.indexOf("/images/silk/star.png") != -1) {
+ cache.own = true;
+ } else {
+ cache.own = false;
+ }
+
+ // id
+ try {
+ final Matcher matcherId = patternId.matcher(row);
+ while (matcherId.find()) {
+ if (matcherId.groupCount() > 0) {
+ cache.cacheid = matcherId.group(1);
+ cids.add(cache.cacheid);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache id
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache id");
+ }
+
+ // favourite count
+ try {
+ final Matcher matcherFavourite = patternFavourite.matcher(row);
+ while (matcherFavourite.find()) {
+ if (matcherFavourite.groupCount() > 0) {
+ cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse favourite count
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse favourite count");
+ }
+
+ if (cache.nameSp == null) {
+ cache.nameSp = (new Spannable.Factory()).newSpannable(cache.name);
+ if (cache.disabled == true || cache.archived == true) { // strike
+ cache.nameSp.setSpan(new StrikethroughSpan(), 0, cache.nameSp.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ caches.cacheList.add(cache);
+ }
+
+ // total caches found
+ try {
+ final Matcher matcherTotalCnt = patternTotalCnt.matcher(page);
+ while (matcherTotalCnt.find()) {
+ if (matcherTotalCnt.groupCount() > 0) {
+ if (matcherTotalCnt.group(1) != null) {
+ caches.totalCnt = new Integer(matcherTotalCnt.group(1));
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache count
+ Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache count");
+ }
+
+ if (thread != null && recaptchaChallenge != null) {
+ if (thread.getText() == null) {
+ thread.waitForUser();
+ }
+
+ recaptchaText = thread.getText();
+ }
+
+ if (cids.size() > 0 && (recaptchaChallenge == null || (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0))) {
+ Log.i(cgSettings.tag, "Trying to get .loc for " + cids.size() + " caches");
+
+ try {
+ // get coordinates for parsed caches
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final StringBuilder params = new StringBuilder();
+ params.append("__EVENTTARGET=");
+ params.append("&");
+ params.append("__EVENTARGUMENT=");
+ params.append("&");
+ params.append("__VIEWSTATE=");
+ params.append(urlencode_rfc3986(caches.viewstate));
+ if (caches.viewstate1 != null) {
+ params.append("&");
+ params.append("__VIEWSTATE1=");
+ params.append(urlencode_rfc3986(caches.viewstate1));
+ params.append("&");
+ params.append("__VIEWSTATEFIELDCOUNT=2");
+ }
+
+ for (String cid : cids) {
+ params.append("&");
+ params.append("CID=");
+ params.append(urlencode_rfc3986(cid));
+ }
+
+ if (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0) {
+ params.append("&");
+ params.append("recaptcha_challenge_field=");
+ params.append(urlencode_rfc3986(recaptchaChallenge));
+ params.append("&");
+ params.append("recaptcha_response_field=");
+ params.append(urlencode_rfc3986(recaptchaText));
+ }
+ params.append("&");
+ params.append("ctl00%24ContentBody%24uxDownloadLoc=Download+Waypoints");
+
+ final String coordinates = request(false, host, path, "POST", params.toString(), 0, true).getData();
+
+ if (coordinates != null && coordinates.length() > 0) {
+ if (coordinates.indexOf("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") > -1) {
+ Log.i(cgSettings.tag, "User has not agreed to the license agreement. Can\'t download .loc file.");
+
+ caches.error = errorRetrieve.get(-7);
+
+ return caches;
+ }
+ }
+
+ if (coordinates != null && coordinates.length() > 0) {
+ final HashMap<String, cgCoord> cidCoords = new HashMap<String, cgCoord>();
+ final Pattern patternCidCode = Pattern.compile("name id=\"([^\"]+)\"");
+ final Pattern patternCidLat = Pattern.compile("lat=\"([^\"]+)\"");
+ final Pattern patternCidLon = Pattern.compile("lon=\"([^\"]+)\"");
+ // premium only >>
+ final Pattern patternCidDif = Pattern.compile("<difficulty>([^<]+)</difficulty>");
+ final Pattern patternCidTer = Pattern.compile("<terrain>([^<]+)</terrain>");
+ final Pattern patternCidCon = Pattern.compile("<container>([^<]+)</container>");
+ // >> premium only
+
+ final String[] points = coordinates.split("<waypoint>");
+
+ // parse coordinates
+ for (String point : points) {
+ final cgCoord pointCoord = new cgCoord();
+ final Matcher matcherCidCode = patternCidCode.matcher(point);
+ final Matcher matcherLatCode = patternCidLat.matcher(point);
+ final Matcher matcherLonCode = patternCidLon.matcher(point);
+ final Matcher matcherDifCode = patternCidDif.matcher(point);
+ final Matcher matcherTerCode = patternCidTer.matcher(point);
+ final Matcher matcherConCode = patternCidCon.matcher(point);
+ HashMap<String, Object> tmp = null;
+
+ if (matcherCidCode.find() == true) {
+ pointCoord.name = matcherCidCode.group(1).trim().toUpperCase();
+ }
+ if (matcherLatCode.find() == true) {
+ tmp = parseCoordinate(matcherLatCode.group(1), "lat");
+ pointCoord.latitude = (Double) tmp.get("coordinate");
+ }
+ if (matcherLonCode.find() == true) {
+ tmp = parseCoordinate(matcherLonCode.group(1), "lon");
+ pointCoord.longitude = (Double) tmp.get("coordinate");
+ }
+ if (matcherDifCode.find() == true) {
+ pointCoord.difficulty = new Float(matcherDifCode.group(1));
+ }
+ if (matcherTerCode.find() == true) {
+ pointCoord.terrain = new Float(matcherTerCode.group(1));
+ }
+ if (matcherConCode.find() == true) {
+ final int size = Integer.parseInt(matcherConCode.group(1));
+
+ if (size == 1) {
+ pointCoord.size = "not chosen";
+ } else if (size == 2) {
+ pointCoord.size = "micro";
+ } else if (size == 3) {
+ pointCoord.size = "regular";
+ } else if (size == 4) {
+ pointCoord.size = "large";
+ } else if (size == 5) {
+ pointCoord.size = "virtual";
+ } else if (size == 6) {
+ pointCoord.size = "other";
+ } else if (size == 8) {
+ pointCoord.size = "small";
+ } else {
+ pointCoord.size = "unknown";
+ }
+ }
+
+ cidCoords.put(pointCoord.name, pointCoord);
+ }
+
+ Log.i(cgSettings.tag, "Coordinates found in .loc file: " + cidCoords.size());
+
+ // save found cache coordinates
+ for (cgCache oneCache : caches.cacheList) {
+ if (cidCoords.containsKey(oneCache.geocode) == true) {
+ cgCoord thisCoords = cidCoords.get(oneCache.geocode);
+
+ oneCache.latitude = thisCoords.latitude;
+ oneCache.longitude = thisCoords.longitude;
+ oneCache.difficulty = thisCoords.difficulty;
+ oneCache.terrain = thisCoords.terrain;
+ oneCache.size = thisCoords.size;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseSearch.CIDs: " + e.toString());
+ }
+ }
+
+ // get direction images
+ cgDirectionImg dirImgDownloader = new cgDirectionImg(settings);
+ for (cgCache oneCache : caches.cacheList) {
+ if (oneCache.latitude == null && oneCache.longitude == null && oneCache.direction == null && oneCache.directionImg != null) {
+ dirImgDownloader.getDrawable(oneCache.geocode, oneCache.directionImg);
+ }
+ }
+ dirImgDownloader = null;
+
+ // get ratings
+ if (guids.size() > 0) {
+ Log.i(cgSettings.tag, "Trying to get ratings for " + cids.size() + " caches");
+
+ try {
+ final HashMap<String, cgRating> ratings = getRating(guids, null);
+
+ if (ratings != null) {
+ // save found cache coordinates
+ for (cgCache oneCache : caches.cacheList) {
+ if (ratings.containsKey(oneCache.guid) == true) {
+ cgRating thisRating = ratings.get(oneCache.guid);
+
+ oneCache.rating = thisRating.rating;
+ oneCache.votes = thisRating.votes;
+ oneCache.myVote = thisRating.myVote;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseSearch.GCvote: " + e.toString());
+ }
+ }
+
+ return caches;
+ }
+
+ public cgCacheWrap parseMapJSON(String url, String data) {
+ if (data == null || data.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No page given");
+ return null;
+ }
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ caches.url = url;
+
+ try {
+ final JSONObject yoDawg = new JSONObject(data);
+ final String json = yoDawg.getString("d");
+
+ if (json == null || json.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No JSON inside JSON");
+ return null;
+ }
+
+ final JSONObject dataJSON = new JSONObject(json);
+ final JSONObject extra = dataJSON.getJSONObject("cs");
+ if (extra != null && extra.length() > 0) {
+ int count = extra.getInt("count");
+
+ if (count > 0 && extra.has("cc")) {
+ final JSONArray cachesData = extra.getJSONArray("cc");
+ if (cachesData != null && cachesData.length() > 0) {
+ JSONObject oneCache = null;
+ for (int i = 0; i < count; i++) {
+ oneCache = cachesData.getJSONObject(i);
+ if (oneCache == null) {
+ break;
+ }
+
+ final cgCache cacheToAdd = new cgCache();
+ cacheToAdd.reliableLatLon = false;
+ cacheToAdd.geocode = oneCache.getString("gc");
+ cacheToAdd.latitude = oneCache.getDouble("lat");
+ cacheToAdd.longitude = oneCache.getDouble("lon");
+ cacheToAdd.name = oneCache.getString("nn");
+ cacheToAdd.found = oneCache.getBoolean("f");
+ cacheToAdd.own = oneCache.getBoolean("o");
+ cacheToAdd.disabled = !oneCache.getBoolean("ia");
+ int ctid = oneCache.getInt("ctid");
+ if (ctid == 2) {
+ cacheToAdd.type = "traditional";
+ } else if (ctid == 3) {
+ cacheToAdd.type = "multi";
+ } else if (ctid == 4) {
+ cacheToAdd.type = "virtual";
+ } else if (ctid == 5) {
+ cacheToAdd.type = "letterbox";
+ } else if (ctid == 6) {
+ cacheToAdd.type = "event";
+ } else if (ctid == 8) {
+ cacheToAdd.type = "mystery";
+ } else if (ctid == 11) {
+ cacheToAdd.type = "webcam";
+ } else if (ctid == 13) {
+ cacheToAdd.type = "cito";
+ } else if (ctid == 137) {
+ cacheToAdd.type = "earth";
+ } else if (ctid == 453) {
+ cacheToAdd.type = "mega";
+ } else if (ctid == 1858) {
+ cacheToAdd.type = "wherigo";
+ } else if (ctid == 3653) {
+ cacheToAdd.type = "lost";
+ }
+
+ caches.cacheList.add(cacheToAdd);
+ }
+ }
+ } else {
+ Log.w(cgSettings.tag, "There are no caches in viewport");
+ }
+ caches.totalCnt = caches.cacheList.size();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseMapJSON: " + e.toString());
+ }
+
+ return caches;
+ }
+
+ public cgCacheWrap parseCache(String page, int reason) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: No page given");
+ return null;
+ }
+
+ final Pattern patternGeocode = Pattern.compile("<meta name=\"og:url\" content=\"[^\"]+/(GC[0-9A-Z]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternCacheId = Pattern.compile("/seek/log\\.aspx\\?ID=(\\d+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternCacheGuid = Pattern.compile("<link rel=\"alternate\" href=\"[^\"]*/datastore/rss_galleryimages\\.ashx\\?guid=([0-9a-z\\-]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternType = Pattern.compile("<img src=\"[^\"]*/WptTypes/\\d+\\.gif\" alt=\"([^\"]+)\" (title=\"[^\"]*\" )?width=\"32\" height=\"32\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Pattern patternName = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_CacheName\">([^<]+)<\\/span>[^<]*<\\/h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternSize = Pattern.compile("<div class=\"CacheSize[^\"]*\">[^<]*<p[^>]*>[^S]*Size[^:]*:[^<]*<span[^>]*>[^<]*<img src=\"[^\"]*/icons/container/[a-z_]+\\.gif\" alt=\"Size: ([^\"]+)\"[^>]*>[^<]*<small>[^<]*</small>[^<]*</span>[^<]*</p>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternDifficulty = Pattern.compile("<span id=\"ctl00_ContentBody_uxLegendScale\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternTerrain = Pattern.compile("<span id=\"ctl00_ContentBody_Localize6\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternOwner = Pattern.compile("<span class=\"minorCacheDetails\">[^\\w]*An?([^\\w]*Event)?[^\\w]*cache[^\\w]*by[^<]*<a href=\"[^\"]+\">([^<]+)</a>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternOwnerReal = Pattern.compile("<a id=\"ctl00_ContentBody_uxFindLinksHiddenByThisUser\" href=\"[^\"]*/seek/nearest\\.aspx\\?u=*([^\"]+)\">[^<]+</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternHidden = Pattern.compile("<span[^>]*>[^\\w]*Hidden[^:]*:[^\\d]*((\\d+)\\/(\\d+)\\/(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternHiddenEvent = Pattern.compile("<span[^>]*>[^\\w]*Event[^\\w]*Date[^:]*:[^\\w]*[a-zA-Z]+,[^\\d]*((\\d+)[^\\w]*(\\w+)[^\\d]*(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternFavourite = Pattern.compile("<a id=\"uxFavContainerLink\"[^>]*>[^<]*<div[^<]*<span class=\"favorite-value\">[^\\d]*([0-9]+)[^\\d^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Pattern patternFound = Pattern.compile("<p>[^<]*<a id=\"ctl00_ContentBody_hlFoundItLog\"[^<]*<img src=\".*/images/stockholm/16x16/check\\.gif\"[^>]*>[^<]*</a>[^<]*</p>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLatLon = Pattern.compile("<span id=\"ctl00_ContentBody_LatLon\"[^>]*>(<b>)?([^<]*)(<\\/b>)?<\\/span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLocation = Pattern.compile("<span id=\"ctl00_ContentBody_Location\"[^>]*>In ([^<]*)", Pattern.CASE_INSENSITIVE);
+ final Pattern patternHint = Pattern.compile("<p>([^<]*<strong>)?[^\\w]*Additional Hints([^<]*<\\/strong>)?[^\\(]*\\(<a[^>]+>Encrypt</a>\\)[^<]*<\\/p>[^<]*<div id=\"div_hint\"[^>]*>(.*)</div>[^<]*<div id=[\\'|\"]dk[\\'|\"]", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDescShort = Pattern.compile("<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_ShortDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^\\w^<]*</div>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDesc = Pattern.compile("<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_LongDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^<]*</div>[^<]*<p>[^<]*</p>[^<]*<p>[^<]*<strong>[^\\w]*Additional Hints</strong>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCountLogs = Pattern.compile("<span id=\"ctl00_ContentBody_lblFindCounts\"><p>(.*)<\\/p><\\/span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternCountLog = Pattern.compile(" src=\"\\/images\\/icons\\/([^\\.]*).gif\" alt=\"[^\"]*\" title=\"[^\"]*\" />([0-9]*)[^0-9]+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternLogs = Pattern.compile("<table class=\"LogsTable[^\"]*\"[^>]*>[^<]*<tr>(.*)</tr>[^<]*</table>[^<]*<p", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternLog = Pattern.compile("<td[^>]*>[^<]*<strong>[^<]*<img src=\"[^\"]*/images/icons/([^\\.]+)\\.[a-z]{2,5}\"[^>]*>&nbsp;([a-zA-Z]+) (\\d+)(, (\\d+))? by <a href=[^>]+>([^<]+)</a>[<^]*</strong>([^\\(]*\\((\\d+) found\\))?(<br[^>]*>)+((?:(?!<small>).)*)(<br[^>]*>)+<small>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Pattern patternAttributes = Pattern.compile("<h3 class=\"WidgetHeader\">[^<]*<img[^>]+>[^\\w]*Attributes[^<]*</h3>[^<]*<div class=\"WidgetBody\">(([^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+)[^<]*<p", Pattern.CASE_INSENSITIVE);
+ final Pattern patternAttributesInside = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpoilers = Pattern.compile("<span id=\"ctl00_ContentBody_Images\">((<a href=\"[^\"]+\"[^>]*>[^<]*<img[^>]+>[^<]*<span>[^>]+</span>[^<]*</a>[^<]*<br[^>]*>([^<]*(<br[^>]*>)+)?)+)[^<]*</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpoilersInside = Pattern.compile("[^<]*<a href=\"([^\"]+)\"[^>]*>[^<]*<img[^>]+>[^<]*<span>([^>]+)</span>[^<]*</a>[^<]*<br[^>]*>(([^<]*)(<br[^<]*>)+)?", Pattern.CASE_INSENSITIVE);
+ final Pattern patternInventory = 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>)?", Pattern.CASE_INSENSITIVE);
+ final Pattern patternInventoryInside = Pattern.compile("[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>", Pattern.CASE_INSENSITIVE);
+
+ final cgCacheWrap caches = new cgCacheWrap();
+ final cgCache cache = new cgCache();
+
+ if (page.indexOf("Cache is Unpublished") > -1) {
+ caches.error = "cache was unpublished";
+ return caches;
+ }
+
+ if (page.indexOf("Sorry, the owner of this listing has made it viewable to Premium Members only.") != -1) {
+ caches.error = "requested cache is for premium members only";
+ return caches;
+ }
+
+ if (page.indexOf("has chosen to make this cache listing visible to Premium Members only.") != -1) {
+ caches.error = "requested cache is for premium members only";
+ return caches;
+ }
+
+ if (page.indexOf("<li>This cache is temporarily unavailable.") != -1) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+
+ if (page.indexOf("<li>This cache has been archived,") != -1) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+
+ if (page.indexOf("<p class=\"Warning\">This is a Premium Member Only cache.</p>") != -1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+
+ cache.reason = reason;
+
+ // cache geocode
+ try {
+ final Matcher matcherGeocode = patternGeocode.matcher(page);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ cache.geocode = (String) matcherGeocode.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache geocode
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache geocode");
+ }
+
+ // cache id
+ try {
+ final Matcher matcherCacheId = patternCacheId.matcher(page);
+ while (matcherCacheId.find()) {
+ if (matcherCacheId.groupCount() > 0) {
+ cache.cacheid = (String) matcherCacheId.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache id
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache id");
+ }
+
+ // cache guid
+ try {
+ final Matcher matcherCacheGuid = patternCacheGuid.matcher(page);
+ while (matcherCacheGuid.find()) {
+ if (matcherCacheGuid.groupCount() > 0) {
+ cache.guid = (String) matcherCacheGuid.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache guid
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache guid");
+ }
+
+ // name
+ try {
+ final Matcher matcherName = patternName.matcher(page);
+ while (matcherName.find()) {
+ if (matcherName.groupCount() > 0) {
+ cache.name = Html.fromHtml(matcherName.group(1)).toString();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache name");
+ }
+
+ // owner real name
+ try {
+ final Matcher matcherOwnerReal = patternOwnerReal.matcher(page);
+ while (matcherOwnerReal.find()) {
+ if (matcherOwnerReal.groupCount() > 0) {
+ cache.ownerReal = URLDecoder.decode(matcherOwnerReal.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse owner real name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner real name");
+ }
+
+ final String username = settings.getUsername();
+ if (cache.ownerReal != null && username != null && cache.ownerReal.equalsIgnoreCase(username)) {
+ cache.own = true;
+ }
+
+ int pos = -1;
+ String tableInside = page;
+
+ pos = tableInside.indexOf("id=\"cacheDetails\"");
+ if (pos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page");
+ return null;
+ }
+
+ tableInside = tableInside.substring(pos);
+
+ pos = tableInside.indexOf("<div class=\"CacheInformationTable\"");
+ if (pos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"CacheInformationTable\" not found on page");
+ return null;
+ }
+
+ tableInside = tableInside.substring(0, pos);
+
+ if (tableInside != null && tableInside.length() > 0) {
+ // cache terrain
+ try {
+ final Matcher matcherTerrain = patternTerrain.matcher(tableInside);
+ while (matcherTerrain.find()) {
+ if (matcherTerrain.groupCount() > 0) {
+ cache.terrain = new Float(Pattern.compile("_").matcher(matcherTerrain.group(1)).replaceAll("."));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse terrain
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache terrain");
+ }
+
+ // cache difficulty
+ try {
+ final Matcher matcherDifficulty = patternDifficulty.matcher(tableInside);
+ while (matcherDifficulty.find()) {
+ if (matcherDifficulty.groupCount() > 0) {
+ cache.difficulty = new Float(Pattern.compile("_").matcher(matcherDifficulty.group(1)).replaceAll("."));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse difficulty
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache difficulty");
+ }
+
+ // owner
+ try {
+ final Matcher matcherOwner = patternOwner.matcher(tableInside);
+ while (matcherOwner.find()) {
+ if (matcherOwner.groupCount() > 0) {
+ cache.owner = Html.fromHtml(matcherOwner.group(2)).toString();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse owner
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner");
+ }
+
+ // hidden
+ try {
+ final Matcher matcherHidden = patternHidden.matcher(tableInside);
+ while (matcherHidden.find()) {
+ if (matcherHidden.groupCount() > 0) {
+ cache.hidden = dateIn.parse(matcherHidden.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache hidden date
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hidden date");
+ }
+
+ if (cache.hidden == null) {
+ // event date
+ try {
+ final Matcher matcherHiddenEvent = patternHiddenEvent.matcher(tableInside);
+ while (matcherHiddenEvent.find()) {
+ if (matcherHiddenEvent.groupCount() > 0) {
+ cache.hidden = dateEvIn.parse(matcherHiddenEvent.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache event date
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache event date");
+ }
+ }
+
+ // favourite
+ try {
+ final Matcher matcherFavourite = patternFavourite.matcher(tableInside);
+ while (matcherFavourite.find()) {
+ if (matcherFavourite.groupCount() > 0) {
+ cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse favourite count
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse favourite count");
+ }
+
+ // cache size
+ try {
+ final Matcher matcherSize = patternSize.matcher(tableInside);
+ while (matcherSize.find()) {
+ if (matcherSize.groupCount() > 0) {
+ cache.size = matcherSize.group(1).toLowerCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse size
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache size");
+ }
+ }
+
+ // cache found
+ try {
+ final Matcher matcherFound = patternFound.matcher(page);
+ while (matcherFound.find()) {
+ if (matcherFound.group() != null && matcherFound.group().length() > 0) {
+ cache.found = true;
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse found
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse found");
+ }
+
+ // cache type
+ try {
+ final Matcher matcherType = patternType.matcher(page);
+ while (matcherType.find()) {
+ if (matcherType.groupCount() > 0) {
+ cache.type = cacheTypes.get(matcherType.group(1).toLowerCase());
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache type");
+ }
+
+ // latitude and logitude
+ try {
+ final Matcher matcherLatLon = patternLatLon.matcher(page);
+ while (matcherLatLon.find()) {
+ if (matcherLatLon.groupCount() > 0) {
+ cache.latlon = matcherLatLon.group(2); // first is <b>
+
+ HashMap<String, Object> tmp = this.parseLatlon(cache.latlon);
+ if (tmp.size() > 0) {
+ cache.latitude = (Double) tmp.get("latitude");
+ cache.longitude = (Double) tmp.get("longitude");
+ cache.latitudeString = (String) tmp.get("latitudeString");
+ cache.longitudeString = (String) tmp.get("longitudeString");
+ cache.reliableLatLon = true;
+ }
+ tmp = null;
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse latitude and/or longitude
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache coordinates");
+ }
+
+ // cache location
+ try {
+ final Matcher matcherLocation = patternLocation.matcher(page);
+ while (matcherLocation.find()) {
+ if (matcherLocation.groupCount() > 0) {
+ cache.location = matcherLocation.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse location
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache location");
+ }
+
+ // cache hint
+ try {
+ final Matcher matcherHint = patternHint.matcher(page);
+ while (matcherHint.find()) {
+ if (matcherHint.groupCount() > 2 && matcherHint.group(3) != null) {
+ // replace linebreak and paragraph tags
+ String hint = Pattern.compile("<(br|p)[^>]*>").matcher(matcherHint.group(3)).replaceAll("\n");
+ if (hint != null) {
+ cache.hint = hint.replaceAll(Pattern.quote("</p>"), "").trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse hint
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hint");
+ }
+
+ /*
+ // short info debug
+ Log.d(cgSettings.tag, "gc-code: " + cache.geocode);
+ Log.d(cgSettings.tag, "id: " + cache.cacheid);
+ Log.d(cgSettings.tag, "guid: " + cache.guid);
+ Log.d(cgSettings.tag, "name: " + cache.name);
+ Log.d(cgSettings.tag, "terrain: " + cache.terrain);
+ Log.d(cgSettings.tag, "difficulty: " + cache.difficulty);
+ Log.d(cgSettings.tag, "owner: " + cache.owner);
+ Log.d(cgSettings.tag, "owner (real): " + cache.ownerReal);
+ Log.d(cgSettings.tag, "hidden: " + dateOutShort.format(cache.hidden));
+ Log.d(cgSettings.tag, "favorite: " + cache.favouriteCnt);
+ Log.d(cgSettings.tag, "size: " + cache.size);
+ if (cache.found) {
+ Log.d(cgSettings.tag, "found!");
+ } else {
+ Log.d(cgSettings.tag, "not found");
+ }
+ Log.d(cgSettings.tag, "type: " + cache.type);
+ Log.d(cgSettings.tag, "latitude: " + String.format("%.6f", cache.latitude));
+ Log.d(cgSettings.tag, "longitude: " + String.format("%.6f", cache.longitude));
+ Log.d(cgSettings.tag, "location: " + cache.location);
+ Log.d(cgSettings.tag, "hint: " + cache.hint);
+ */
+
+ // cache short description
+ try {
+ final Matcher matcherDescShort = patternDescShort.matcher(page);
+ while (matcherDescShort.find()) {
+ if (matcherDescShort.groupCount() > 0) {
+ cache.shortdesc = matcherDescShort.group(1).trim();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse short description
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache short description");
+ }
+
+ // cache description
+ try {
+ final Matcher matcherDesc = patternDesc.matcher(page);
+ while (matcherDesc.find()) {
+ if (matcherDesc.groupCount() > 0) {
+ cache.description = matcherDesc.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse short description
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache description");
+ }
+
+ // cache attributes
+ try {
+ final Matcher matcherAttributes = patternAttributes.matcher(page);
+ while (matcherAttributes.find()) {
+ if (matcherAttributes.groupCount() > 0) {
+ final String attributesPre = matcherAttributes.group(1);
+ final Matcher matcherAttributesInside = patternAttributesInside.matcher(attributesPre);
+
+ while (matcherAttributesInside.find()) {
+ if (matcherAttributesInside.groupCount() > 1 && matcherAttributesInside.group(2).equalsIgnoreCase("blank") != true) {
+ if (cache.attributes == null) {
+ cache.attributes = new ArrayList<String>();
+ }
+ // by default, use the tooltip of the attribute
+ String attribute = matcherAttributesInside.group(2).toLowerCase();
+
+ // if the image name can be recognized, use the image name as attribute
+ String imageName = matcherAttributesInside.group(1).trim();
+ if (imageName.length() > 0) {
+ int start = imageName.lastIndexOf('/');
+ int end = imageName.lastIndexOf('.');
+ if (start >= 0 && end>= 0) {
+ attribute = imageName.substring(start + 1, end).replace('-', '_');
+ }
+ }
+ cache.attributes.add(attribute);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache attributes
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache attributes");
+ }
+
+ // cache spoilers
+ try {
+ final Matcher matcherSpoilers = patternSpoilers.matcher(page);
+ while (matcherSpoilers.find()) {
+ if (matcherSpoilers.groupCount() > 0) {
+ final String spoilersPre = matcherSpoilers.group(1);
+ final Matcher matcherSpoilersInside = patternSpoilersInside.matcher(spoilersPre);
+
+ while (matcherSpoilersInside.find()) {
+ if (matcherSpoilersInside.groupCount() > 0) {
+ final cgSpoiler spoiler = new cgSpoiler();
+ spoiler.url = matcherSpoilersInside.group(1);
+
+ if (matcherSpoilersInside.group(2) != null) {
+ spoiler.title = matcherSpoilersInside.group(2);
+ }
+ if (matcherSpoilersInside.group(4) != null) {
+ spoiler.description = matcherSpoilersInside.group(4);
+ }
+
+ if (cache.spoilers == null) {
+ cache.spoilers = new ArrayList<cgSpoiler>();
+ }
+ cache.spoilers.add(spoiler);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache spoilers
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache spoilers");
+ }
+
+ // cache inventory
+ try {
+ cache.inventoryItems = 0;
+
+ final Matcher matcherInventory = patternInventory.matcher(page);
+ while (matcherInventory.find()) {
+ if (cache.inventory == null) {
+ cache.inventory = new ArrayList<cgTrackable>();
+ }
+
+ if (matcherInventory.groupCount() > 1) {
+ final String inventoryPre = matcherInventory.group(2);
+
+ if (inventoryPre != null && inventoryPre.length() > 0) {
+ final Matcher matcherInventoryInside = patternInventoryInside.matcher(inventoryPre);
+
+ while (matcherInventoryInside.find()) {
+ if (matcherInventoryInside.groupCount() > 0) {
+ final cgTrackable inventoryItem = new cgTrackable();
+ inventoryItem.guid = matcherInventoryInside.group(1);
+ inventoryItem.name = matcherInventoryInside.group(2);
+
+ cache.inventory.add(inventoryItem);
+ cache.inventoryItems++;
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache inventory
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache inventory (2)");
+ }
+
+ // cache logs counts
+ try {
+ final Matcher matcherLogCounts = patternCountLogs.matcher(page);
+ while (matcherLogCounts.find()) {
+ if (matcherLogCounts.groupCount() > 0) {
+ final String[] logs = matcherLogCounts.group(1).split("<img");
+ final int logsCnt = logs.length;
+
+ for (int k = 1; k < logsCnt; k++) {
+ Integer type = null;
+ Integer count = null;
+ final Matcher matcherLog = patternCountLog.matcher(logs[k]);
+
+ if (matcherLog.find()) {
+ String typeStr = matcherLog.group(1);
+ String countStr = matcherLog.group(2);
+ if (typeStr != null && typeStr.length() > 0) {
+ if (logTypes.containsKey(typeStr.toLowerCase()) == true) {
+ type = logTypes.get(typeStr.toLowerCase());
+ }
+ }
+ if (countStr != null && countStr.length() > 0) {
+ count = Integer.parseInt(countStr);
+ }
+ if (type != null && count != null) {
+ cache.logCounts.put(type, count);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache log count");
+ }
+
+ // cache logs
+ try {
+ final Matcher matcherLogs = patternLogs.matcher(page);
+ while (matcherLogs.find()) {
+ if (matcherLogs.groupCount() > 0) {
+ final String[] logs = matcherLogs.group(1).split("</tr><tr>");
+ final int logsCnt = logs.length;
+
+ for (int k = 0; k < logsCnt; k++) {
+ final Matcher matcherLog = patternLog.matcher(logs[k]);
+
+ if (matcherLog.find()) {
+ final cgLog logDone = new cgLog();
+
+ String logTmp = matcherLog.group(10);
+
+ int day = -1;
+ try {
+ day = Integer.parseInt(matcherLog.group(3));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString());
+ }
+
+ int month = -1;
+ // January | February | March | April | May | June | July | August | September | October | November | December
+ if (matcherLog.group(2).equalsIgnoreCase("January")) {
+ month = 0;
+ } else if (matcherLog.group(2).equalsIgnoreCase("February")) {
+ month = 1;
+ } else if (matcherLog.group(2).equalsIgnoreCase("March")) {
+ month = 2;
+ } else if (matcherLog.group(2).equalsIgnoreCase("April")) {
+ month = 3;
+ } else if (matcherLog.group(2).equalsIgnoreCase("May")) {
+ month = 4;
+ } else if (matcherLog.group(2).equalsIgnoreCase("June")) {
+ month = 5;
+ } else if (matcherLog.group(2).equalsIgnoreCase("July")) {
+ month = 6;
+ } else if (matcherLog.group(2).equalsIgnoreCase("August")) {
+ month = 7;
+ } else if (matcherLog.group(2).equalsIgnoreCase("September")) {
+ month = 8;
+ } else if (matcherLog.group(2).equalsIgnoreCase("October")) {
+ month = 9;
+ } else if (matcherLog.group(2).equalsIgnoreCase("November")) {
+ month = 10;
+ } else if (matcherLog.group(2).equalsIgnoreCase("December")) {
+ month = 11;
+ } else {
+ Log.w(cgSettings.tag, "Failed to parse logs date (month).");
+ }
+
+
+ int year = -1;
+ final String yearPre = matcherLog.group(5);
+
+ if (yearPre == null) {
+ Calendar date = Calendar.getInstance();
+ year = date.get(Calendar.YEAR);
+ } else {
+ try {
+ year = Integer.parseInt(matcherLog.group(5));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString());
+ }
+ }
+
+ long logDate;
+ if (year > 0 && month >= 0 && day > 0) {
+ Calendar date = Calendar.getInstance();
+ date.set(year, month, day, 12, 0, 0);
+ logDate = date.getTimeInMillis();
+ logDate = (long) (Math.ceil(logDate / 1000)) * 1000;
+ } else {
+ logDate = 0;
+ }
+
+ if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) {
+ logDone.type = logTypes.get(matcherLog.group(1).toLowerCase());
+ } else {
+ logDone.type = logTypes.get("icon_note");
+ }
+
+ logDone.author = Html.fromHtml(matcherLog.group(6)).toString();
+ logDone.date = logDate;
+ if (matcherLog.group(8) != null) {
+ logDone.found = new Integer(matcherLog.group(8));
+ }
+ logDone.log = logTmp;
+
+ if (cache.logs == null) {
+ cache.logs = new ArrayList<cgLog>();
+ }
+ cache.logs.add(logDone);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs");
+ }
+
+ int wpBegin = 0;
+ int wpEnd = 0;
+
+ wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">");
+ if (wpBegin != -1) { // parse waypoints
+ final Pattern patternWpType = Pattern.compile("\\/wpttypes\\/sm\\/(.+)\\.jpg", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpPrefixOrLookupOrLatlon = Pattern.compile(">([^<]*<[^>]+>)?([^<]+)(<[^>]+>[^<]*)?<\\/td>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpName = Pattern.compile(">[^<]*<a[^>]+>([^<]*)<\\/a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternWpNote = Pattern.compile("colspan=\"6\">(.*)<\\/td>", Pattern.CASE_INSENSITIVE);
+
+ String wpList = page.substring(wpBegin);
+
+ wpEnd = wpList.indexOf("</p>");
+ if (wpEnd > -1 && wpEnd <= wpList.length()) {
+ wpList = wpList.substring(0, wpEnd);
+ }
+
+ if (wpList.indexOf("No additional waypoints to display.") == -1) {
+ wpEnd = wpList.indexOf("</table>");
+ wpList = wpList.substring(0, wpEnd);
+
+ wpBegin = wpList.indexOf("<tbody>");
+ wpEnd = wpList.indexOf("</tbody>");
+ if (wpBegin >= 0 && wpEnd >= 0 && wpEnd <= wpList.length()) {
+ wpList = wpList.substring(wpBegin + 7, wpEnd);
+ }
+
+ final String[] wpItems = wpList.split("<tr");
+
+ String[] wp;
+ for (int j = 1; j < wpItems.length; j++) {
+ final cgWaypoint waypoint = new cgWaypoint();
+
+ wp = wpItems[j].split("<td");
+
+ // waypoint type
+ try {
+ final Matcher matcherWpType = patternWpType.matcher(wp[3]);
+ while (matcherWpType.find()) {
+ if (matcherWpType.groupCount() > 0) {
+ waypoint.type = matcherWpType.group(1);
+ if (waypoint.type != null) {
+ waypoint.type = waypoint.type.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse type
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint type");
+ }
+
+ // waypoint prefix
+ try {
+ final Matcher matcherWpPrefix = patternWpPrefixOrLookupOrLatlon.matcher(wp[4]);
+ while (matcherWpPrefix.find()) {
+ if (matcherWpPrefix.groupCount() > 1) {
+ waypoint.prefix = matcherWpPrefix.group(2);
+ if (waypoint.prefix != null) {
+ waypoint.prefix = waypoint.prefix.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse prefix
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint prefix");
+ }
+
+ // waypoint lookup
+ try {
+ final Matcher matcherWpLookup = patternWpPrefixOrLookupOrLatlon.matcher(wp[5]);
+ while (matcherWpLookup.find()) {
+ if (matcherWpLookup.groupCount() > 1) {
+ waypoint.lookup = matcherWpLookup.group(2);
+ if (waypoint.lookup != null) {
+ waypoint.lookup = waypoint.lookup.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse lookup
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint lookup");
+ }
+
+ // waypoint name
+ try {
+ final Matcher matcherWpName = patternWpName.matcher(wp[6]);
+ while (matcherWpName.find()) {
+ if (matcherWpName.groupCount() > 0) {
+ waypoint.name = matcherWpName.group(1);
+ if (waypoint.name != null) {
+ waypoint.name = waypoint.name.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse name
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint name");
+ }
+
+ // waypoint latitude and logitude
+ try {
+ final Matcher matcherWpLatLon = patternWpPrefixOrLookupOrLatlon.matcher(wp[7]);
+ while (matcherWpLatLon.find()) {
+ if (matcherWpLatLon.groupCount() > 1) {
+ waypoint.latlon = Html.fromHtml(matcherWpLatLon.group(2)).toString();
+
+ final HashMap<String, Object> tmp = this.parseLatlon(waypoint.latlon);
+ if (tmp.size() > 0) {
+ waypoint.latitude = (Double) tmp.get("latitude");
+ waypoint.longitude = (Double) tmp.get("longitude");
+ waypoint.latitudeString = (String) tmp.get("latitudeString");
+ waypoint.longitudeString = (String) tmp.get("longitudeString");
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse latitude and/or longitude
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint coordinates");
+ }
+
+ j++;
+ if (wpItems.length > j) {
+ wp = wpItems[j].split("<td");
+ }
+
+ // waypoint note
+ try {
+ final Matcher matcherWpNote = patternWpNote.matcher(wp[3]);
+ while (matcherWpNote.find()) {
+ if (matcherWpNote.groupCount() > 0) {
+ waypoint.note = matcherWpNote.group(1);
+ if (waypoint.note != null) {
+ waypoint.note = waypoint.note.trim();
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse note
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint note");
+ }
+
+ if (cache.waypoints == null)
+ cache.waypoints = new ArrayList<cgWaypoint>();
+ cache.waypoints.add(waypoint);
+ }
+ }
+ }
+
+ if (cache.latitude != null && cache.longitude != null) {
+ cache.elevation = getElevation(cache.latitude, cache.longitude);
+ }
+
+ final cgRating rating = getRating(cache.guid, cache.geocode);
+ if (rating != null) {
+ cache.rating = rating.rating;
+ cache.votes = rating.votes;
+ cache.myVote = rating.myVote;
+ }
+
+ cache.updated = System.currentTimeMillis();
+ cache.detailedUpdate = System.currentTimeMillis();
+ cache.detailed = true;
+ caches.cacheList.add(cache);
+
+ return caches;
+ }
+
+ public cgRating getRating(String guid, String geocode) {
+ ArrayList<String> guids = null;
+ ArrayList<String> geocodes = null;
+
+ if (guid != null && guid.length() > 0) {
+ guids = new ArrayList<String>();
+ guids.add(guid);
+ } else if (geocode != null && geocode.length() > 0) {
+ geocodes = new ArrayList<String>();
+ geocodes.add(geocode);
+ } else {
+ return null;
+ }
+
+ final HashMap<String, cgRating> ratings = getRating(guids, geocodes);
+ if(ratings != null){
+ final Set<String> ratingKeys = ratings.keySet();
+ for (String ratingKey : ratingKeys) {
+ return ratings.get(ratingKey);
+ }
+ }
+
+ return null;
+ }
+
+ public HashMap<String, cgRating> getRating(ArrayList<String> guids, ArrayList<String> geocodes) {
+ if (guids == null && geocodes == null) {
+ return null;
+ }
+
+ final HashMap<String, cgRating> ratings = new HashMap<String, cgRating>();
+
+ try {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (settings.isLogin() == true) {
+ final HashMap<String, String> login = settings.getGCvoteLogin();
+ if (login != null) {
+ params.put("userName", login.get("username"));
+ params.put("password", login.get("password"));
+ }
+ }
+ if (guids != null && guids.size() > 0) {
+ params.put("cacheIds", implode(",", guids.toArray()));
+ } else {
+ params.put("waypoints", implode(",", geocodes.toArray()));
+ }
+ params.put("version", "cgeo");
+ final String votes = request(false, "gcvote.com", "/getVotes.php", "GET", params, false, false, false).getData();
+ if (votes == null) {
+ return null;
+ }
+
+ final Pattern patternLogIn = Pattern.compile("loggedIn='([^']+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGuid = Pattern.compile("cacheId='([^']+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternRating = Pattern.compile("voteAvg='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternVotes = Pattern.compile("voteCnt='([0-9]+)'", Pattern.CASE_INSENSITIVE);
+ final Pattern patternVote = Pattern.compile("voteUser='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE);
+
+ String voteData = null;
+ final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherVoteElement = patternVoteElement.matcher(votes);
+ while (matcherVoteElement.find()) {
+ if (matcherVoteElement.groupCount() > 0) {
+ voteData = matcherVoteElement.group(1);
+ }
+
+ if (voteData == null) {
+ continue;
+ }
+
+ String guid = null;
+ cgRating rating = new cgRating();
+ boolean loggedIn = false;
+
+ try {
+ final Matcher matcherGuid = patternGuid.matcher(voteData);
+ if (matcherGuid.find()) {
+ if (matcherGuid.groupCount() > 0) {
+ guid = (String) matcherGuid.group(1);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse guid");
+ }
+
+ try {
+ final Matcher matcherLoggedIn = patternLogIn.matcher(votes);
+ if (matcherLoggedIn.find()) {
+ if (matcherLoggedIn.groupCount() > 0) {
+ if (matcherLoggedIn.group(1).equalsIgnoreCase("true") == true) {
+ loggedIn = true;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse loggedIn");
+ }
+
+ try {
+ final Matcher matcherRating = patternRating.matcher(voteData);
+ if (matcherRating.find()) {
+ if (matcherRating.groupCount() > 0) {
+ rating.rating = Float.parseFloat(matcherRating.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse rating");
+ }
+
+ try {
+ final Matcher matcherVotes = patternVotes.matcher(voteData);
+ if (matcherVotes.find()) {
+ if (matcherVotes.groupCount() > 0) {
+ rating.votes = Integer.parseInt(matcherVotes.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse vote count");
+ }
+
+ if (loggedIn == true) {
+ try {
+ final Matcher matcherVote = patternVote.matcher(voteData);
+ if (matcherVote.find()) {
+ if (matcherVote.groupCount() > 0) {
+ rating.myVote = Float.parseFloat(matcherVote.group(1));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse user's vote");
+ }
+ }
+
+ if (guid != null) {
+ ratings.put(guid, rating);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.getRating: " + e.toString());
+ }
+
+ return ratings;
+ }
+
+ public boolean setRating(String guid, int vote) {
+ if (guid == null || guid.length() == 0) {
+ return false;
+ }
+ if (vote < 0 || vote > 5) {
+ return false;
+ }
+
+ final HashMap<String, String> login = settings.getGCvoteLogin();
+ if (login == null) {
+ return false;
+ }
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("userName", login.get("username"));
+ params.put("password", login.get("password"));
+ params.put("cacheId", guid);
+ params.put("voteUser", Integer.toString(vote));
+ params.put("version", "cgeo");
+
+ final String result = request(false, "gcvote.com", "/setVote.php", "GET", params, false, false, false).getData();
+
+ if (result.trim().equalsIgnoreCase("ok") == true) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public Long parseGPX(cgeoapplication app, File file, int listId, Handler handler) {
+ cgSearch search = new cgSearch();
+ long searchId = 0l;
+
+ try {
+ cgGPXParser GPXparser = new cgGPXParser(app, this, listId, search);
+
+ searchId = GPXparser.parse(file, 10, handler);
+ if (searchId == 0l) {
+ searchId = GPXparser.parse(file, 11, handler);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.parseGPX: " + e.toString());
+ }
+
+ Log.i(cgSettings.tag, "Caches found in .gpx file: " + app.getCount(searchId));
+
+ return search.getCurrentId();
+ }
+
+ public cgTrackable parseTrackable(String page) {
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackable: No page given");
+ return null;
+ }
+
+ final Pattern patternTrackableId = Pattern.compile("<a id=\"ctl00_ContentBody_LogLink\" title=\"[^\"]*\" href=\".*log\\.aspx\\?wid=([a-z0-9\\-]+)\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGeocode = Pattern.compile("<span id=\"ctl00_ContentBody_BugDetails_BugTBNum\" String=\"[^\"]*\">Use[^<]*<strong>(TB[0-9a-z]+)[^<]*</strong> to reference this item.[^<]*</span>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternName = Pattern.compile("<h2>([^<]*<img[^>]*>)?[^<]*<span id=\"ctl00_ContentBody_lbHeading\">([^<]+)</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternOwner = Pattern.compile("<dt>[^\\w]*Owner:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugOwner\" title=\"[^\"]*\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">([^<]+)<\\/a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternReleased = Pattern.compile("<dt>[^\\w]*Released:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugReleaseDate\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternOrigin = Pattern.compile("<dt>[^\\w]*Origin:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugOrigin\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedCache = 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>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedUser = 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>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedUnknown = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">Unknown Location[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternSpottedOwner = Pattern.compile("<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">In the hands of the owner[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternGoal = Pattern.compile("<h3>[^\\w]*Current GOAL[^<]*</h3>[^<]*<p[^>]*>(.*)</p>[^<]*<h3>[^\\w]*About This Item[^<]*</h3>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDetailsImage = Pattern.compile("<h3>[^\\w]*About This Item[^<]*</h3>([^<]*<p>([^<]*<img id=\"ctl00_ContentBody_BugDetails_BugImage\" class=\"[^\"]+\" src=\"([^\"]+)\"[^>]*>)?[^<]*</p>)?[^<]*<p[^>]*>(.*)</p>[^<]*<div id=\"ctl00_ContentBody_BugDetails_uxAbuseReport\">", Pattern.CASE_INSENSITIVE);
+ final Pattern patternLogs = Pattern.compile("<table class=\"TrackableItemLogTable Table\">(.*)<\\/table>[^<]*<ul", Pattern.CASE_INSENSITIVE);
+ final Pattern patternIcon = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternType = Pattern.compile("<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE);
+ final Pattern patternDistance = Pattern.compile("<h4[^>]*[^\\w]*Tracking History \\(([0-9\\.,]+(km|mi))[^\\)]*\\)", Pattern.CASE_INSENSITIVE);
+
+ final cgTrackable trackable = new cgTrackable();
+
+ // trackable geocode
+ try {
+ final Matcher matcherGeocode = patternGeocode.matcher(page);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ trackable.geocode = matcherGeocode.group(1).toUpperCase();
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable geocode
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable geocode");
+ }
+
+ // trackable id
+ try {
+ final Matcher matcherTrackableId = patternTrackableId.matcher(page);
+ while (matcherTrackableId.find()) {
+ if (matcherTrackableId.groupCount() > 0) {
+ trackable.guid = matcherTrackableId.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable id
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable id");
+ }
+
+ // trackable icon
+ try {
+ final Matcher matcherTrackableIcon = patternIcon.matcher(page);
+ while (matcherTrackableIcon.find()) {
+ if (matcherTrackableIcon.groupCount() > 0) {
+ trackable.iconUrl = matcherTrackableIcon.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable icon
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable icon");
+ }
+
+ // trackable name
+ try {
+ final Matcher matcherName = patternName.matcher(page);
+ while (matcherName.find()) {
+ if (matcherName.groupCount() > 1) {
+ trackable.name = matcherName.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable name
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable name");
+ }
+
+ // trackable type
+ if (trackable.name != null && trackable.name.length() > 0) {
+ try {
+ final Matcher matcherType = patternType.matcher(page);
+ while (matcherType.find()) {
+ if (matcherType.groupCount() > 0) {
+ trackable.type = matcherType.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable type
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable type");
+ }
+ }
+
+ // trackable owner name
+ try {
+ final Matcher matcherOwner = patternOwner.matcher(page);
+ while (matcherOwner.find()) {
+ if (matcherOwner.groupCount() > 0) {
+ trackable.ownerGuid = matcherOwner.group(1);
+ trackable.owner = matcherOwner.group(2);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable owner name
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable owner name");
+ }
+
+ // trackable origin
+ try {
+ final Matcher matcherOrigin = patternOrigin.matcher(page);
+ while (matcherOrigin.find()) {
+ if (matcherOrigin.groupCount() > 0) {
+ trackable.origin = matcherOrigin.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable origin
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable origin");
+ }
+
+ // trackable spotted
+ try {
+ final Matcher matcherSpottedCache = patternSpottedCache.matcher(page);
+ while (matcherSpottedCache.find()) {
+ if (matcherSpottedCache.groupCount() > 0) {
+ trackable.spottedGuid = matcherSpottedCache.group(1);
+ trackable.spottedName = matcherSpottedCache.group(2);
+ trackable.spottedType = cgTrackable.SPOTTED_CACHE;
+ }
+ }
+
+ final Matcher matcherSpottedUser = patternSpottedUser.matcher(page);
+ while (matcherSpottedUser.find()) {
+ if (matcherSpottedUser.groupCount() > 0) {
+ trackable.spottedGuid = matcherSpottedUser.group(1);
+ trackable.spottedName = matcherSpottedUser.group(2);
+ trackable.spottedType = cgTrackable.SPOTTED_USER;
+ }
+ }
+
+ final Matcher matcherSpottedUnknown = patternSpottedUnknown.matcher(page);
+ if (matcherSpottedUnknown.find()) {
+ trackable.spottedType = cgTrackable.SPOTTED_UNKNOWN;
+ }
+
+ final Matcher matcherSpottedOwner = patternSpottedOwner.matcher(page);
+ if (matcherSpottedOwner.find()) {
+ trackable.spottedType = cgTrackable.SPOTTED_OWNER;
+ }
+ } catch (Exception e) {
+ // failed to parse trackable last known place
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable last known place");
+ }
+
+ // released
+ try {
+ final Matcher matcherReleased = patternReleased.matcher(page);
+ while (matcherReleased.find()) {
+ if (matcherReleased.groupCount() > 0 && matcherReleased.group(1) != null) {
+ try {
+ if (trackable.released == null) {
+ trackable.released = dateTbIn1.parse(matcherReleased.group(1));
+ }
+ } catch (Exception e) {
+ //
+ }
+
+ try {
+ if (trackable.released == null) {
+ trackable.released = dateTbIn2.parse(matcherReleased.group(1));
+ }
+ } catch (Exception e) {
+ //
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable released date
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable released date");
+ }
+
+ // trackable distance
+ try {
+ final Matcher matcherDistance = patternDistance.matcher(page);
+ while (matcherDistance.find()) {
+ if (matcherDistance.groupCount() > 0) {
+ trackable.distance = parseDistance(matcherDistance.group(1));
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable distance
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable distance");
+ }
+
+ // trackable goal
+ try {
+ final Matcher matcherGoal = patternGoal.matcher(page);
+ while (matcherGoal.find()) {
+ if (matcherGoal.groupCount() > 0) {
+ trackable.goal = matcherGoal.group(1);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable goal
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable goal");
+ }
+
+ // trackable details & image
+ try {
+ final Matcher matcherDetailsImage = patternDetailsImage.matcher(page);
+ while (matcherDetailsImage.find()) {
+ if (matcherDetailsImage.groupCount() > 0) {
+ final String image = matcherDetailsImage.group(3);
+ final String details = matcherDetailsImage.group(4);
+
+ if (image != null) {
+ trackable.image = image;
+ }
+ if (details != null) {
+ trackable.details = details;
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable details & image
+ Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable details & image");
+ }
+
+ // trackable logs
+ try {
+ final Matcher matcherLogs = patternLogs.matcher(page);
+ while (matcherLogs.find()) {
+ if (matcherLogs.groupCount() > 0) {
+ final Pattern patternLog = Pattern.compile("[^>]*>" +
+ "[^<]*<td[^<]*<img src=[\"|'].*\\/icons\\/([^\\.]+)\\.[a-z]{2,5}[\"|'][^>]*>&nbsp;(\\d+).(\\d+).(\\d+)[^<]*</td>" +
+ "[^<]*<td>[^<]*<a href=[^>]+>([^<]+)<.a>([^<]*|[^<]*<a href=[\"|'].*guid=([^\"]*)\">([^<]*)</a>[^<]*)</td>" +
+ "[^<]*<td>[^<]*</td>" +
+ "[^<]*<td[^<]*<a href=[^>]+>[^<]+</a>[^<]*</td>[^<]*</tr>" +
+ "[^<]*<tr[^>]*>[^<]*<td[^>]*>(.*?)</td>[^<]*</tr>.*" +
+ "");
+ // 1 filename == type
+ // 2 month
+ // 3 date
+ // 4 year
+ // 5 user
+ // 6 action dependent
+ // 7 cache guid
+ // 8 cache name
+ // 9 text
+ final String[] logs = matcherLogs.group(1).split("<tr class=\"Data BorderTop");
+ final int logsCnt = logs.length;
+
+ for (int k = 1; k < logsCnt; k++) {
+ final Matcher matcherLog = patternLog.matcher(logs[k]);
+ if (matcherLog.find()) {
+ final cgLog logDone = new cgLog();
+
+ String logTmp = matcherLog.group(9);
+ logTmp = Pattern.compile("<p>").matcher(logTmp).replaceAll("\n");
+ logTmp = Pattern.compile("<br[^>]*>").matcher(logTmp).replaceAll("\n");
+ logTmp = Pattern.compile("<\\/p>").matcher(logTmp).replaceAll("");
+ logTmp = Pattern.compile("\r+").matcher(logTmp).replaceAll("\n");
+
+ int day = -1;
+ try {
+ day = Integer.parseInt(matcherLog.group(3));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString());
+ }
+
+ int month = -1;
+ try {
+ month = Integer.parseInt(matcherLog.group(2));
+ month -= 1;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (month): " + e.toString());
+ }
+
+ int year = -1;
+ try {
+ year = Integer.parseInt(matcherLog.group(4));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString());
+ }
+
+ long logDate;
+ if (year > 0 && month >= 0 && day > 0) {
+ Calendar date = Calendar.getInstance();
+ date.set(year, month, day, 12, 0, 0);
+ logDate = date.getTimeInMillis();
+ logDate = (long) (Math.ceil(logDate / 1000)) * 1000;
+ } else {
+ logDate = 0;
+ }
+
+ if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) {
+ logDone.type = logTypes.get(matcherLog.group(1).toLowerCase());
+ } else {
+ logDone.type = logTypes.get("icon_note");
+ }
+
+ logDone.author = Html.fromHtml(matcherLog.group(5)).toString();
+ logDone.date = logDate;
+ logDone.log = logTmp;
+ if (matcherLog.group(7) != null && matcherLog.group(8) != null) {
+ logDone.cacheGuid = matcherLog.group(7);
+ logDone.cacheName = matcherLog.group(8);
+ }
+
+ trackable.logs.add(logDone);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs");
+ }
+
+ app.saveTrackable(trackable);
+
+ return trackable;
+ }
+
+ public ArrayList<Integer> parseTypes(String page) {
+ if (page == null || page.length() == 0) {
+ return null;
+ }
+
+ final ArrayList<Integer> types = new ArrayList<Integer>();
+
+ final Pattern typeBoxPattern = Pattern.compile("<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$ddLogType\" id=\"ctl00_ContentBody_LogBookPanel1_ddLogType\"[^>]*>"
+ + "(([^<]*<option[^>]*>[^<]+</option>)+)[^<]*</select>", Pattern.CASE_INSENSITIVE);
+ final Matcher typeBoxMatcher = typeBoxPattern.matcher(page);
+ String typesText = null;
+ if (typeBoxMatcher.find()) {
+ if (typeBoxMatcher.groupCount() > 0) {
+ typesText = typeBoxMatcher.group(1);
+ }
+ }
+
+ if (typesText != null) {
+ final Pattern typePattern = Pattern.compile("<option( selected=\"selected\")? value=\"(\\d+)\">[^<]+</option>", Pattern.CASE_INSENSITIVE);
+ final Matcher typeMatcher = typePattern.matcher(typesText);
+ while (typeMatcher.find()) {
+ if (typeMatcher.groupCount() > 1) {
+ final int type = Integer.parseInt(typeMatcher.group(2));
+
+ if (type > 0) {
+ types.add(type);
+ }
+ }
+ }
+ }
+
+ return types;
+ }
+
+ public ArrayList<cgTrackableLog> parseTrackableLog(String page) {
+ if (page == null || page.length() == 0) {
+ return null;
+ }
+
+ final ArrayList<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>();
+
+ int startPos = -1;
+ int endPos = -1;
+
+ startPos = page.indexOf("<table id=\"tblTravelBugs\"");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: ID \"tblTravelBugs\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <table
+
+ endPos = page.indexOf("</table>");
+ if (endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of ID \"tblTravelBugs\" not found on page");
+ return null;
+ }
+
+ page = page.substring(0, endPos); // cut on </table>
+
+ startPos = page.indexOf("<tbody>");
+ if (startPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: tbody not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <tbody>
+
+ endPos = page.indexOf("</tbody>");
+ if (endPos == -1) {
+ Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of tbody not found on page");
+ return null;
+ }
+
+ page = page.substring(0, endPos); // cut on </tbody>
+
+ final Pattern trackablePattern = 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);
+ final Matcher trackableMatcher = trackablePattern.matcher(page);
+ while (trackableMatcher.find()) {
+ if (trackableMatcher.groupCount() > 0) {
+ final cgTrackableLog trackable = new cgTrackableLog();
+
+ if (trackableMatcher.group(1) != null) {
+ trackable.trackCode = trackableMatcher.group(1);
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(2) != null) {
+ trackable.name = Html.fromHtml(trackableMatcher.group(2)).toString();
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(3) != null) {
+ trackable.ctl = new Integer(trackableMatcher.group(3));
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(5) != null) {
+ trackable.id = new Integer(trackableMatcher.group(5));
+ } else {
+ continue;
+ }
+
+ Log.i(cgSettings.tag, "Trackable in inventory (#" + trackable.ctl + "/" + trackable.id + "): " + trackable.trackCode + " - " + trackable.name);
+
+ trackables.add(trackable);
+ }
+ }
+
+ return trackables;
+ }
+
+ public int parseFindCount(String page) {
+ if (page == null || page.length() == 0) {
+ return -1;
+ }
+
+ int findCount = -1;
+
+ try {
+ final Pattern findPattern = Pattern.compile("<strong>Caches Found:<\\/strong>([^<]+)<br", Pattern.CASE_INSENSITIVE);
+ final Matcher findMatcher = findPattern.matcher(page);
+ if (findMatcher.find() == true) {
+ if (findMatcher.groupCount() > 0) {
+ String count = findMatcher.group(1);
+
+ if (count != null) {
+ count = count.trim();
+
+ if (count.length() == 0) {
+ findCount = 0;
+ } else {
+ findCount = Integer.parseInt(count);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.parseFindCount: " + e.toString());
+ }
+
+ return findCount;
+ }
+
+
+ public static String stripParagraphs(String text) {
+ if (text == null) {
+ return "";
+ }
+
+ final Pattern patternP = Pattern.compile("(<p>|</p>|<br \\/>|<br>)", Pattern.CASE_INSENSITIVE);
+ final Pattern patternP2 = Pattern.compile("([ ]+)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherP = patternP.matcher(text);
+ final Matcher matcherP2 = patternP2.matcher(text);
+
+ matcherP.replaceAll(" ");
+ matcherP2.replaceAll(" ");
+
+ return text.trim();
+ }
+
+ public static String stripTags(String text) {
+ if (text == null) {
+ return "";
+ }
+
+ final Pattern patternP = Pattern.compile("(<[^>]+>)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherP = patternP.matcher(text);
+
+ matcherP.replaceAll(" ");
+
+ return text.trim();
+ }
+
+ public static String capitalizeSentence(String sentence) {
+ if (sentence == null) {
+ return "";
+ }
+
+ final String[] word = sentence.split(" ");
+
+ for (int i = 0; i < word.length; i++) {
+ word[i] = capitalizeWord(word[i]);
+ }
+
+ return implode(" ", word);
+ }
+
+ public static String capitalizeWord(String word) {
+ if (word.length() == 0) {
+ return word;
+ }
+
+ return (word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase());
+ }
+
+ public static Double parseDistance(String dst) {
+ Double distance = null;
+
+ final Pattern pattern = Pattern.compile("([0-9\\.,]+)[ ]*(km|mi)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcher = pattern.matcher(dst);
+ while (matcher.find()) {
+ if (matcher.groupCount() > 1) {
+ if (matcher.group(2).equalsIgnoreCase("km") == true) {
+ distance = new Double(matcher.group(1));
+ } else {
+ distance = new Double(matcher.group(1)) / kmInMiles;
+ }
+ }
+ }
+
+ return distance;
+ }
+
+ public static double getDistance(Double lat1, Double lon1, Double lat2, Double lon2) {
+ if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
+ return 0d;
+ }
+
+ lat1 *= deg2rad;
+ lon1 *= deg2rad;
+ lat2 *= deg2rad;
+ lon2 *= deg2rad;
+
+ final double d = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2);
+ final double distance = erad * Math.acos(d); // distance in km
+
+ if (Double.isNaN(distance) == false && distance > 0) {
+ return distance;
+ } else {
+ return 0d;
+ }
+ }
+
+ public static Double getHeading(Double lat1, Double lon1, Double lat2, Double lon2) {
+ Double result = new Double(0);
+
+ int ilat1 = (int) Math.round(0.5 + lat1 * 360000);
+ int ilon1 = (int) Math.round(0.5 + lon1 * 360000);
+ int ilat2 = (int) Math.round(0.5 + lat2 * 360000);
+ int ilon2 = (int) Math.round(0.5 + lon2 * 360000);
+
+ lat1 *= deg2rad;
+ lon1 *= deg2rad;
+ lat2 *= deg2rad;
+ lon2 *= deg2rad;
+
+ if (ilat1 == ilat2 && ilon1 == ilon2) {
+ return new Double(result);
+ } else if (ilat1 == ilat2) {
+ if (ilon1 > ilon2) {
+ result = new Double(270);
+ } else {
+ result = new Double(90);
+ }
+ } else if (ilon1 == ilon2) {
+ if (ilat1 > ilat2) {
+ result = new Double(180);
+ }
+ } else {
+ Double c = Math.acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos(lon2 - lon1));
+ Double A = Math.asin(Math.cos(lat2) * Math.sin(lon2 - lon1) / Math.sin(c));
+ result = new Double(A * rad2deg);
+ if (ilat2 > ilat1 && ilon2 > ilon1) {
+ // result don't need change
+ } else if (ilat2 < ilat1 && ilon2 < ilon1) {
+ result = 180f - result;
+ } else if (ilat2 < ilat1 && ilon2 > ilon1) {
+ result = 180f - result;
+ } else if (ilat2 > ilat1 && ilon2 < ilon1) {
+ result += 360f;
+ }
+ }
+
+ return result;
+ }
+
+ public HashMap<String, Double> getRadialDistance(Double latitude, Double longitude, Double bearing, Double distance) {
+ final Double rlat1 = latitude * deg2rad;
+ final Double rlon1 = longitude * deg2rad;
+ final Double rbearing = bearing * deg2rad;
+ final Double rdistance = distance / erad;
+
+ final Double rlat = Math.asin(Math.sin(rlat1) * Math.cos(rdistance) + Math.cos(rlat1) * Math.sin(rdistance) * Math.cos(rbearing));
+ final Double rlon = rlon1 + Math.atan2(Math.sin(rbearing) * Math.sin(rdistance) * Math.cos(rlat1), Math.cos(rdistance) - Math.sin(rlat1) * Math.sin(rlat));
+
+ HashMap<String, Double> result = new HashMap<String, Double>();
+ result.put("latitude", rlat * rad2deg);
+ result.put("longitude", rlon * rad2deg);
+
+ return result;
+ }
+
+ public String getHumanDistance(Float distance) {
+ if (distance == null) {
+ return "?";
+ }
+
+ return getHumanDistance(new Double(distance));
+ }
+
+ public String getHumanDistance(Double distance) {
+ if (distance == null) {
+ return "?";
+ }
+
+ if (settings.units == cgSettings.unitsImperial) {
+ distance *= kmInMiles;
+ if (distance > 100) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " mi";
+ } else if (distance > 0.5) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " mi";
+ } else if (distance > 0.1) {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " mi";
+ } else if (distance > 0.05) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 5280.0))) + " ft";
+ } else if (distance > 0.01) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 5280 * 10.0) / 10.0)) + " ft";
+ } else {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 5280 * 100.0) / 100.0)) + " ft";
+ }
+ } else {
+ if (distance > 100) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " km";
+ } else if (distance > 10) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " km";
+ } else if (distance > 1) {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " km";
+ } else if (distance > 0.1) {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 1000.0))) + " m";
+ } else if (distance > 0.01) {
+ return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 1000.0 * 10.0) / 10.0)) + " m";
+ } else {
+ return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 1000.0 * 100.0) / 100.0)) + " m";
+ }
+ }
+ }
+
+ public String getHumanSpeed(float speed) {
+ double kph = speed * 3.6;
+ String unit = "kmh";
+
+ if (this.settings.units == cgSettings.unitsImperial) {
+ kph *= kmInMiles;
+ unit = "mph";
+ }
+
+ if (kph < 10) {
+ return String.format(Locale.getDefault(), "%.1f", new Double((Math.round(kph * 10) / 10))) + " " + unit;
+ } else {
+ return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(kph))) + " " + unit;
+ }
+ }
+
+ public HashMap<String, Object> parseLatlon(String latlon) {
+ final HashMap<String, Object> result = new HashMap<String, Object>();
+ final Pattern patternLatlon = Pattern.compile("([NS])[^\\d]*(\\d+)[^°]*° (\\d+)\\.(\\d+) ([WE])[^\\d]*(\\d+)[^°]*° (\\d+)\\.(\\d+)", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherLatlon = patternLatlon.matcher(latlon);
+
+ while (matcherLatlon.find()) {
+ if (matcherLatlon.groupCount() > 0) {
+ result.put("latitudeString", (String) (matcherLatlon.group(1) + " " + matcherLatlon.group(2) + "° " + matcherLatlon.group(3) + "." + matcherLatlon.group(4)));
+ result.put("longitudeString", (String) (matcherLatlon.group(5) + " " + matcherLatlon.group(6) + "° " + matcherLatlon.group(7) + "." + matcherLatlon.group(8)));
+ int latNegative = -1;
+ int lonNegative = -1;
+ if (matcherLatlon.group(1).equalsIgnoreCase("N")) {
+ latNegative = 1;
+ }
+ if (matcherLatlon.group(5).equalsIgnoreCase("E")) {
+ lonNegative = 1;
+ }
+ result.put("latitude", new Double(latNegative * (new Float(matcherLatlon.group(2)) + new Float(matcherLatlon.group(3) + "." + matcherLatlon.group(4)) / 60)));
+ result.put("longitude", new Double(lonNegative * (new Float(matcherLatlon.group(6)) + new Float(matcherLatlon.group(7) + "." + matcherLatlon.group(8)) / 60)));
+ } else {
+ Log.w(cgSettings.tag, "cgBase.parseLatlon: Failed to parse coordinates.");
+ }
+ }
+
+ return result;
+ }
+
+ public String formatCoordinate(Double coord, String latlon, boolean degrees) {
+ String formatted = "";
+
+ if (coord == null) {
+ return formatted;
+ }
+
+ String worldSide = "";
+ if (latlon.equalsIgnoreCase("lat") == true) {
+ if (coord >= 0) {
+ // have the blanks here at the direction to avoid one String concatenation
+ worldSide = "N ";
+ } else {
+ worldSide = "S ";
+ }
+ } else if (latlon.equalsIgnoreCase("lon") == true) {
+ if (coord >= 0) {
+ worldSide = "E ";
+ } else {
+ worldSide = "W ";
+ }
+ }
+
+ coord = Math.abs(coord);
+
+ if (latlon.equalsIgnoreCase("lat") == true) {
+ if (degrees == true) {
+ formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + "° " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ } else {
+ formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ }
+ } else {
+ if (degrees == true) {
+ formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + "° " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ } else {
+ formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60));
+ }
+ }
+
+ return formatted;
+ }
+
+ public HashMap<String, Object> parseCoordinate(String coord, String latlon) {
+ final HashMap<String, Object> coords = new HashMap<String, Object>();
+
+ final Pattern patternA = Pattern.compile("^([NSWE])[^\\d]*(\\d+)°? +(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternB = Pattern.compile("^([NSWE])[^\\d]*(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternC = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternD = Pattern.compile("^([NSWE])[^\\d]*(\\d+)°?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternE = Pattern.compile("^(-?\\d+)°?$", Pattern.CASE_INSENSITIVE);
+ final Pattern patternF = Pattern.compile("^([NSWE])[^\\d]*(\\d+)$", Pattern.CASE_INSENSITIVE);
+ final Pattern pattern0 = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE);
+
+ coord = coord.trim().toUpperCase();
+
+ final Matcher matcherA = patternA.matcher(coord);
+ final Matcher matcherB = patternB.matcher(coord);
+ final Matcher matcherC = patternC.matcher(coord);
+ final Matcher matcherD = patternD.matcher(coord);
+ final Matcher matcherE = patternE.matcher(coord);
+ final Matcher matcherF = patternF.matcher(coord);
+ final Matcher matcher0 = pattern0.matcher(coord);
+
+ int latlonNegative;
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ if (matcherA.group(1).equalsIgnoreCase("N") || matcherA.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ if (matcherA.groupCount() < 5 || matcherA.group(5) == null) {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + ".0") / 60)));
+ coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + "° " + matcherA.group(3) + ".000");
+ } else {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + "." + matcherA.group(5)) / 60)));
+ coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + "° " + matcherA.group(3) + "." + matcherA.group(5));
+ }
+
+ return coords;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ if (matcherB.group(1).equalsIgnoreCase("N") || matcherB.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ if (matcherB.groupCount() < 4 || matcherB.group(4) == null) {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + ".0"))));
+ } else {
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + "." + matcherB.group(4)))));
+ }
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ if (matcherC.groupCount() < 3 || matcherC.group(3) == null) {
+ coords.put("coordinate", new Double(new Float(matcherC.group(1) + ".0")));
+ } else {
+ coords.put("coordinate", new Double(new Float(matcherC.group(1) + "." + matcherC.group(3))));
+ }
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ if (matcherD.group(1).equalsIgnoreCase("N") || matcherD.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2)))));
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ coords.put("coordinate", new Double(matcherE.group(1)));
+ } else if (matcherF.find() == true && matcherF.groupCount() > 0) {
+ if (matcherF.group(1).equalsIgnoreCase("N") || matcherF.group(1).equalsIgnoreCase("E")) {
+ latlonNegative = 1;
+ } else {
+ latlonNegative = -1;
+ }
+
+ coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2)))));
+ } else {
+ return null;
+ }
+
+ if (matcher0.find() == true && matcher0.groupCount() > 0) {
+ String tmpDir = null;
+ Float tmpCoord;
+ if (matcher0.groupCount() < 3 || matcher0.group(3) == null) {
+ tmpCoord = new Float("0.0");
+ } else {
+ tmpCoord = new Float("0." + matcher0.group(3));
+ }
+
+ if (latlon.equalsIgnoreCase("lat")) {
+ if (matcher0.group(1).equals("+")) {
+ tmpDir = "N";
+ }
+ if (matcher0.group(1).equals("-")) {
+ tmpDir = "S";
+ }
+ } else if (latlon.equalsIgnoreCase("lon")) {
+ if (matcher0.group(1).equals("+")) {
+ tmpDir = "E";
+ }
+ if (matcher0.group(1).equals("-")) {
+ tmpDir = "W";
+ }
+ }
+
+ coords.put("string", tmpDir + " " + matcher0.group(1) + "° " + (Math.round(tmpCoord / (1 / 60) * 1000) * 1000));
+
+ return coords;
+ } else {
+ return new HashMap<String, Object>();
+ }
+ }
+
+ public Long searchByNextPage(cgSearchThread thread, Long searchId, int reason, boolean showCaptcha) {
+ final String viewstate = app.getViewstate(searchId);
+ final String viewstate1 = app.getViewstate1(searchId);
+ cgCacheWrap caches = new cgCacheWrap();
+ String url = app.getUrl(searchId);
+
+ if (url == null || url.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No url found");
+ return searchId;
+ }
+
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No viewstate given");
+ return searchId;
+ }
+
+ String host = "www.geocaching.com";
+ String path = "/";
+ final String method = "POST";
+
+ int dash = -1;
+ if (url.indexOf("http://") > -1) {
+ url = url.substring(7);
+ }
+
+ dash = url.indexOf("/");
+ if (dash > -1) {
+ host = url.substring(0, dash);
+ url = url.substring(dash);
+ } else {
+ host = url;
+ url = "";
+ }
+
+ dash = url.indexOf("?");
+ if (dash > -1) {
+ path = url.substring(0, dash);
+ } else {
+ path = url;
+ }
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08");
+ params.put("__EVENTARGUMENT", "");
+
+ String page = request(false, host, path, method, params, false, false, true).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, true).getData();
+ } else if (loginState == -3) {
+ Log.i(cgSettings.tag, "Working as guest.");
+ } else {
+ app.setError(searchId, errorRetrieve.get(loginState));
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching");
+ return searchId;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No data from server");
+ return searchId;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No cache parsed");
+ return searchId;
+ }
+
+ // save to application
+ app.setError(searchId, caches.error);
+ app.setViewstate(searchId, caches.viewstate);
+ app.setViewstate1(searchId, caches.viewstate1);
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ for (cgCache cache : caches.cacheList) {
+ app.addGeocode(searchId, cache.geocode);
+ cacheList.add(cache);
+ }
+
+ app.addSearch(searchId, cacheList, true, reason);
+
+ return searchId;
+ }
+
+ public Long searchByGeocode(HashMap<String, String> parameters, int reason, boolean forceReload) {
+ final cgSearch search = new cgSearch();
+ String geocode = parameters.get("geocode");
+ String guid = parameters.get("guid");
+
+ if ((geocode == null || geocode.length() == 0) && ((guid == null || guid.length() == 0))) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No geocode nor guid given");
+ return null;
+ }
+
+ if (forceReload == false && reason == 0 && (app.isOffline(geocode, guid) == true || app.isThere(geocode, guid, true, true) == true)) {
+ if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) {
+ geocode = app.getGeocode(guid);
+ }
+
+ ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ cacheList.add(app.getCacheByGeocode(geocode, true, true, true, true, true, true));
+ search.addGeocode(geocode);
+
+ app.addSearch(search, cacheList, false, reason);
+
+ cacheList.clear();
+ cacheList = null;
+
+ return search.getCurrentId();
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/cache_details.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("wp", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ }
+ params.put("decrypt", "y");
+ params.put("log", "y"); // download logs (more than 5
+ params.put("numlogs", "35"); // 35 logs
+
+ String page = requestLogged(false, host, path, method, params, false, false, false);
+
+ if (page == null || page.length() == 0) {
+ if (app.isThere(geocode, guid, true, false) == true) {
+ if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) {
+ Log.i(cgSettings.tag, "Loading old cache from cache.");
+
+ geocode = app.getGeocode(guid);
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ cacheList.add(app.getCacheByGeocode(geocode));
+ search.addGeocode(geocode);
+ search.error = null;
+ search.errorRetrieve = 0; // reset errors from previous failed request
+
+ app.addSearch(search, cacheList, false, reason);
+
+ cacheList.clear();
+
+ return search.getCurrentId();
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No data from server");
+ return null;
+ }
+
+ final cgCacheWrap caches = parseCache(page, reason);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ if (caches != null && caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches != null && caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+
+ app.addSearch(search, null, true, reason);
+
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No cache parsed");
+ return null;
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ page = null;
+ cacheList.clear();
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByOffline(HashMap<String, Object> parameters) {
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOffline: No application found");
+ return null;
+ }
+
+ Double latitude = null;
+ Double longitude = null;
+ String cachetype = null;
+ Integer list = 1;
+
+ if (parameters.containsKey("latitude") == true && parameters.containsKey("longitude") == true) {
+ latitude = (Double) parameters.get("latitude");
+ longitude = (Double) parameters.get("longitude");
+ }
+
+ if (parameters.containsKey("cachetype") == true) {
+ cachetype = (String) parameters.get("cachetype");
+ }
+
+ if (parameters.containsKey("list") == true) {
+ list = (Integer) parameters.get("list");
+ }
+
+ final cgSearch search = app.getBatchOfStoredCaches(true, latitude, longitude, cachetype, list);
+ search.totalCnt = app.getAllStoredCachesCount(true, cachetype, list);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByHistory(HashMap<String, Object> parameters) {
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByHistory: No application found");
+ return null;
+ }
+
+ String cachetype = null;
+
+ if (parameters.containsKey("cachetype") == true) {
+ cachetype = (String) parameters.get("cachetype");
+ }
+
+ final cgSearch search = app.getHistoryOfCaches(true, cachetype);
+ search.totalCnt = app.getAllHistoricCachesCount(true, cachetype);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByCoords(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String latitude = parameters.get("latitude");
+ final String longitude = parameters.get("longitude");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (latitude == null || latitude.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No latitude given");
+ return null;
+ }
+
+ if (longitude == null || longitude.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No longitude given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("lat", latitude);
+ params.put("lng", longitude);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByKeyword(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String keyword = parameters.get("keyword");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (keyword == null || keyword.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No keyword given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("key", keyword);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByUsername(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String userName = parameters.get("username");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (userName == null || userName.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No user name given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("ul", userName);
+
+ boolean my = false;
+ if (userName.equalsIgnoreCase(settings.getLogin().get("username")) == true) {
+ my = true;
+ Log.i(cgSettings.tag, "cgBase.searchByUsername: Overriding users choice, downloading all caches.");
+ }
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, my, true);
+ String page = requestLogged(false, host, path, method, params, false, my, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByOwner(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) {
+ final cgSearch search = new cgSearch();
+ final String userName = parameters.get("username");
+ cgCacheWrap caches = new cgCacheWrap();
+ String cacheType = parameters.get("cachetype");
+
+ if (userName == null || userName.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No user name given");
+ return null;
+ }
+
+ if (cacheType != null && cacheType.length() == 0) {
+ cacheType = null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/nearest.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (cacheType != null && cacheIDs.containsKey(cacheType) == true) {
+ params.put("tx", cacheIDs.get(cacheType));
+ } else {
+ params.put("tx", cacheIDs.get("all"));
+ }
+ params.put("u", userName);
+
+ final String url = "http://" + host + path + "?" + prepareParameters(params, false, true);
+ String page = requestLogged(false, host, path, method, params, false, false, true);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No data from server");
+ return null;
+ }
+
+ caches = parseSearch(thread, url, page, showCaptcha);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ for (cgCache cache : caches.cacheList) {
+ if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public Long searchByViewport(HashMap<String, String> parameters, int reason) {
+ final cgSearch search = new cgSearch();
+ final String latMin = parameters.get("latitude-min");
+ final String latMax = parameters.get("latitude-max");
+ final String lonMin = parameters.get("longitude-min");
+ final String lonMax = parameters.get("longitude-max");
+
+ String usertoken = null;
+ if (parameters.get("usertoken") != null) {
+ usertoken = parameters.get("usertoken");
+ } else {
+ usertoken = "";
+ }
+ cgCacheWrap caches = new cgCacheWrap();
+
+ String page = null;
+
+ if (latMin == null || latMin.length() == 0 || latMax == null || latMax.length() == 0 || lonMin == null || lonMin.length() == 0 || lonMax == null || lonMax.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: Not enough parameters to recognize viewport");
+ return null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/map/default.aspx/MapAction";
+
+ String params = "{\"dto\":{\"data\":{\"c\":1,\"m\":\"\",\"d\":\"" + latMax + "|" + latMin + "|" + lonMax + "|" + lonMin + "\"},\"ut\":\"" + usertoken + "\"}}";
+
+ final String url = "http://" + host + path + "?" + params;
+ page = requestJSONgc(host, path, params);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No data from server");
+ return null;
+ }
+
+ caches = parseMapJSON(url, page);
+ if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No cache parsed");
+ }
+
+ if (app == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No application found");
+ return null;
+ }
+
+ final ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ if (caches != null) {
+ if (caches.error != null && caches.error.length() > 0) {
+ search.error = caches.error;
+ }
+ if (caches.url != null && caches.url.length() > 0) {
+ search.url = caches.url;
+ }
+ if (caches.viewstate != null && caches.viewstate.length() > 0) {
+ search.viewstate = caches.viewstate;
+ }
+ if (caches.viewstate1 != null && caches.viewstate1.length() > 0) {
+ search.viewstate1 = caches.viewstate1;
+ }
+ search.totalCnt = caches.totalCnt;
+
+ if (caches.cacheList != null && caches.cacheList.size() > 0) {
+ for (cgCache cache : caches.cacheList) {
+ if ((settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false))
+ && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.own == false))
+ && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.found == false))
+ && (settings.cacheType == null || (settings.cacheType.equals(cache.type) == true))) {
+ search.addGeocode(cache.geocode);
+ cacheList.add(cache);
+ }
+ }
+ }
+ }
+
+ app.addSearch(search, cacheList, true, reason);
+
+ return search.getCurrentId();
+ }
+
+ public ArrayList<cgUser> getGeocachersInViewport(String username, Double latMin, Double latMax, Double lonMin, Double lonMax) {
+ final ArrayList<cgUser> users = new ArrayList<cgUser>();
+
+ if (username == null) {
+ return users;
+ }
+ if (latMin == null || latMax == null || lonMin == null || lonMax == null) {
+ return users;
+ }
+
+ final String host = "api.go4cache.com";
+ final String path = "/get.php";
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("u", username);
+ params.put("ltm", String.format((Locale) null, "%.6f", latMin));
+ params.put("ltx", String.format((Locale) null, "%.6f", latMax));
+ params.put("lnm", String.format((Locale) null, "%.6f", lonMin));
+ params.put("lnx", String.format((Locale) null, "%.6f", lonMax));
+
+ final String data = request(false, host, path, method, params, false, false, false).getData();
+
+ if (data == null || data.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.getGeocachersInViewport: No data from server");
+ return null;
+ }
+
+ try {
+ final JSONObject dataJSON = new JSONObject(data);
+
+ final JSONArray usersData = dataJSON.getJSONArray("users");
+ if (usersData != null && usersData.length() > 0) {
+ int count = usersData.length();
+ JSONObject oneUser = null;
+ for (int i = 0; i < count; i++) {
+ final cgUser user = new cgUser();
+ oneUser = usersData.getJSONObject(i);
+ if (oneUser != null) {
+ final String located = oneUser.getString("located");
+ if (located != null) {
+ user.located = dateSqlIn.parse(located);
+ } else {
+ user.located = new Date();
+ }
+ user.username = oneUser.getString("user");
+ user.latitude = oneUser.getDouble("latitude");
+ user.longitude = oneUser.getDouble("longitude");
+ user.action = oneUser.getString("action");
+ user.client = oneUser.getString("client");
+
+ if (user.latitude != null && user.longitude != null) {
+ users.add(user);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.getGeocachersInViewport: " + e.toString());
+ }
+
+ return users;
+ }
+
+ public cgTrackable searchTrackable(HashMap<String, String> parameters) {
+ final String geocode = parameters.get("geocode");
+ final String guid = parameters.get("guid");
+ final String id = parameters.get("id");
+ cgTrackable trackable = new cgTrackable();
+
+ if ((geocode == null || geocode.length() == 0) && (guid == null || guid.length() == 0) && (id == null || id.length() == 0)) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given");
+ return null;
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/track/details.aspx";
+ final String method = "GET";
+ final HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("tracker", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else if (id != null && id.length() > 0) {
+ params.put("id", id);
+ }
+
+ String page = requestLogged(false, host, path, method, params, false, false, false);
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No data from server");
+ return trackable;
+ }
+
+ trackable = parseTrackable(page);
+ if (trackable == null) {
+ Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No trackable parsed");
+ return trackable;
+ }
+
+ return trackable;
+ }
+
+ public int postLog(cgeoapplication app, String geocode, String cacheid, String viewstate, String viewstate1, int logType, int year, int month, int day, String log, ArrayList<cgTrackableLog> trackables) {
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate given");
+ return 1000;
+ }
+
+ if (logTypes2.containsKey(logType) == false) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Unknown logtype");
+ return 1000;
+ }
+
+ if (log == null || log.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No log text given");
+ return 1001;
+ }
+
+ // fix log (non-Latin characters converted to HTML entities)
+ final int logLen = log.length();
+ final StringBuilder logUpdated = new StringBuilder();
+
+ for (int i = 0; i < logLen; i++) {
+ char c = log.charAt(i);
+
+ if (c > 300) {
+ logUpdated.append("&#");
+ logUpdated.append(Integer.toString((int) c));
+ logUpdated.append(";");
+ } else {
+ logUpdated.append(c);
+ }
+ }
+ log = logUpdated.toString();
+
+ log = log.replace("\n", "\r\n"); // windows' eol
+
+ if (trackables != null) {
+ Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: " + trackables.size());
+ } else {
+ Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: 0");
+ }
+
+ final String host = "www.geocaching.com";
+ final String path = "/seek/log.aspx?ID=" + cacheid;
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", String.format("%02d", month) + "/" + String.format("%02d", day) + "/" + String.format("%04d", year));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry");
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+ if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed
+ final StringBuilder hdnSelected = new StringBuilder();
+
+ for (cgTrackableLog tb : trackables) {
+ final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action);
+
+ if (tb.action > 0) {
+ hdnSelected.append(action);
+ hdnSelected.append(",");
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ String page = request(false, host, path, method, params, false, false, false).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, false).getData();
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No data from server");
+ return 1002;
+ }
+
+ // maintenance, archived needs to be confirmed
+ final Pattern pattern = Pattern.compile("<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcher = pattern.matcher(page);
+
+ try {
+ if (matcher.find() == true && matcher.groupCount() > 0) {
+ final String viewstateConfirm = findViewstate(page, 0);
+ final String viewstate1Confirm = findViewstate(page, 1);
+
+ if (viewstateConfirm == null || viewstateConfirm.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate for confirm log");
+ return 1000;
+ }
+
+ params.clear();
+ params.put("__VIEWSTATE", viewstateConfirm);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1Confirm);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$btnConfirm", "Yes");
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+ if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed
+ final StringBuilder hdnSelected = new StringBuilder();
+
+ for (cgTrackableLog tb : trackables) {
+ String ctl = null;
+ final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action);
+
+ if (tb.ctl < 10) {
+ ctl = "0" + Integer.toString(tb.ctl);
+ } else {
+ ctl = Integer.toString(tb.ctl);
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$repTravelBugs$ctl" + ctl + "$ddlAction", action);
+ if (tb.action > 0) {
+ hdnSelected.append(action);
+ hdnSelected.append(",");
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ page = request(false, host, path, method, params, false, false, false).getData();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog.confim: " + e.toString());
+ }
+
+ try {
+ final Pattern patternOk = Pattern.compile("<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+ final Matcher matcherOk = patternOk.matcher(page);
+ if (matcherOk.find() == true) {
+ Log.i(cgSettings.tag, "Log successfully posted to cache #" + cacheid);
+
+ if (app != null && geocode != null) {
+ app.saveVisitDate(geocode);
+ }
+
+ return 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLog.check: " + e.toString());
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.postLog: Failed to post log because of unknown error");
+ return 1000;
+ }
+
+ public int postLogTrackable(String tbid, String trackingCode, String viewstate, String viewstate1, int logType, int year, int month, int day, String log) {
+ if (viewstate == null || viewstate.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No viewstate given");
+ return 1000;
+ }
+
+ if (logTypes2.containsKey(logType) == false) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Unknown logtype");
+ return 1000;
+ }
+
+ if (log == null || log.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No log text given");
+ return 1001;
+ }
+
+ Log.i(cgSettings.tag, "Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log);
+
+ log = log.replace("\n", "\r\n"); // windows' eol
+
+ final Calendar currentDate = Calendar.getInstance();
+ final String host = "www.geocaching.com";
+ final String path = "/track/log.aspx?wid=" + tbid;
+ final String method = "POST";
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ params.put("__VIEWSTATE", viewstate);
+ if (viewstate1 != null) {
+ params.put("__VIEWSTATE1", viewstate1);
+ params.put("__VIEWSTATEFIELDCOUNT", "2");
+ }
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType));
+ params.put("ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode);
+ if (currentDate.get(Calendar.YEAR) == year && (currentDate.get(Calendar.MONTH) + 1) == month && currentDate.get(Calendar.DATE) == day) {
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", "");
+ } else {
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", Integer.toString(month) + "/" + Integer.toString(day) + "/" + Integer.toString(year));
+ }
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month));
+ params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year));
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log);
+ params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry");
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+
+ String page = request(false, host, path, method, params, false, false, false).getData();
+ if (checkLogin(page) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ page = request(false, host, path, method, params, false, false, false).getData();
+ } else {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (page == null || page.length() == 0) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No data from server");
+ return 1002;
+ }
+
+ try {
+ final Pattern patternOk = Pattern.compile("<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE);
+ final Matcher matcherOk = patternOk.matcher(page);
+ if (matcherOk.find() == true) {
+ Log.i(cgSettings.tag, "Log successfully posted to trackable #" + trackingCode);
+ return 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable.check: " + e.toString());
+ }
+
+ Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Failed to post log because of unknown error");
+ return 1000;
+ }
+
+ final public static HostnameVerifier doNotVerify = new HostnameVerifier() {
+
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+
+ public static void trustAllHosts() {
+ TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+ }
+ };
+
+ try {
+ SSLContext sc = SSLContext.getInstance("TLS");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.trustAllHosts: " + e.toString());
+ }
+ }
+
+ public void postTweetCache(cgeoapplication app, cgSettings settings, String geocode) {
+ final cgCache cache = app.getCacheByGeocode(geocode);
+ String name = cache.name;
+ if (name.length() > 84) {
+ name = name.substring(0, 81) + "...";
+ }
+ final String status = "I found " + name + " (http://coord.info/" + cache.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 56 chars + cache name
+
+ postTweet(app, settings, status, null, null);
+ }
+
+ public void postTweetTrackable(cgeoapplication app, cgSettings settings, String geocode) {
+ final cgTrackable trackable = app.getTrackableByGeocode(geocode);
+ String name = trackable.name;
+ if (name.length() > 82) {
+ name = name.substring(0, 79) + "...";
+ }
+ final String status = "I touched " + name + " (http://coord.info/" + trackable.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 58 chars + trackable name
+
+ postTweet(app, settings, status, null, null);
+ }
+
+ public void postTweet(cgeoapplication app, cgSettings settings, String status, Double latitude, Double longitude) {
+ if (app == null) {
+ return;
+ }
+ if (settings == null || settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0) {
+ return;
+ }
+
+ try {
+ HashMap<String, String> parameters = new HashMap<String, String>();
+
+ parameters.put("status", status);
+ if (latitude != null && longitude != null) {
+ parameters.put("lat", String.format("%.6f", latitude));
+ parameters.put("long", String.format("%.6f", longitude));
+ parameters.put("display_coordinates", "true");
+ }
+
+ final String paramsDone = cgOAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, settings.tokenPublic, settings.tokenSecret);
+
+ HttpURLConnection connection = null;
+ try {
+ final StringBuffer buffer = new StringBuffer();
+ final URL u = new URL("http://api.twitter.com/1/statuses/update.json");
+ final URLConnection uc = u.openConnection();
+
+ uc.setRequestProperty("Host", "api.twitter.com");
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod("POST");
+ HttpURLConnection.setFollowRedirects(true);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(paramsDone);
+ wr.flush();
+ wr.close();
+
+ Log.i(cgSettings.tag, "Twitter.com: " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ InputStream ins;
+ final String encoding = connection.getContentEncoding();
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ br.close();
+ ins.close();
+ inr.close();
+ connection.disconnect();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet.IO: " + connection.getResponseCode() + ": " + connection.getResponseMessage() + " ~ " + e.toString());
+
+ final InputStream ins = connection.getErrorStream();
+ final StringBuffer buffer = new StringBuffer();
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet.inner: " + e.toString());
+ }
+
+ connection.disconnect();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.postTweet: " + e.toString());
+ }
+ }
+
+ private void readIntoBuffer(BufferedReader br, StringBuffer buffer) throws IOException {
+ int bufferSize = 1024*16;
+ char[] bytes = new char[bufferSize];
+ int bytesRead;
+ while ((bytesRead = br.read(bytes)) > 0) {
+ if (bytesRead == bufferSize) {
+ buffer.append(bytes);
+ }
+ else {
+ buffer.append(bytes, 0, bytesRead);
+ }
+ }
+ }
+
+ /*
+ public ArrayList<String> translate(ArrayList<String> text, String target) {
+ if (settings.translate == false) {
+ return text;
+ }
+
+ String[] languages = null;
+ if (settings.languages != null) {
+ languages = settings.languages.split(" ");
+ }
+
+ ArrayList<String> translated = new ArrayList<String>();
+ String language = null;
+
+ if (text == null || text.isEmpty()) {
+ return text;
+ }
+
+ // cut to 5000 characters (limitation of Google Translation API)
+ for (String textOne : text) {
+ int len = urlencode_rfc3986(textOne).length();
+ if (len > 5000) {
+ textOne = Html.fromHtml(textOne).toString();
+ len = urlencode_rfc3986(textOne).length();
+
+ if (len > 5000) {
+ int cut = 2000;
+ if (textOne.length() > cut) {
+ cut = 1000;
+ }
+
+ textOne = textOne.substring(0, cut) + "...";
+ }
+ }
+ }
+
+ try {
+ if (target == null) {
+ final Locale locale = Locale.getDefault();
+ target = locale.getLanguage();
+ }
+
+ final String scheme = "https://";
+ final String host = "www.googleapis.com";
+ final String path = "/language/translate/v2";
+
+ final ArrayList<String> params = new ArrayList<String>();
+ params.add("key=" + urlencode_rfc3986("AIzaSyAJH8x5etFHUbFifmgChlWoCVmwBFSwShQ"));
+ params.add("target=" + urlencode_rfc3986(target));
+ for (String textOne : text) {
+ params.add("q=" + urlencode_rfc3986(textOne));
+ }
+ params.add("format=" + urlencode_rfc3986("html"));
+
+ String page = requestJSON(scheme, host, path, "POST", implode("&", params.toArray()));
+
+ if (page == null || page.length() == 0) {
+ return text;
+ }
+
+ JSONObject json = new JSONObject(page);
+ JSONObject jsonData = json.getJSONObject("data");
+ JSONArray jsonTranslations = jsonData.getJSONArray("translations");
+ int translationCnt = jsonTranslations.length();
+
+ for (int i = 0; i < translationCnt; i ++) {
+ JSONObject jsonTranslation = jsonTranslations.getJSONObject(i);
+ language = jsonTranslation.getString("detectedSourceLanguage");
+
+ boolean toTranslate = true;
+ if (languages != null) {
+ for (String lng : languages) {
+ if (lng.equalsIgnoreCase(language)) {
+ toTranslate = false;
+ }
+ }
+ }
+
+ if (toTranslate == false) {
+ translated.add(text.get(i));
+ } else {
+ Log.i(cgSettings.tag, "Translating #" + i + ": " + language + ">" + target);
+ translated.add(jsonTranslation.getString("translatedText"));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.translate: " + e.toString());
+ }
+
+ return translated;
+ }
+ */
+
+ public String getLocalIpAddress() {
+ try {
+ for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
+ NetworkInterface intf = en.nextElement();
+ for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
+ InetAddress inetAddress = enumIpAddr.nextElement();
+ if (!inetAddress.isLoopbackAddress()) {
+ return inetAddress.getHostAddress().toString();
+ }
+ }
+ }
+ } catch (SocketException e) {
+ // nothing
+ }
+
+ return null;
+ }
+
+ public static String implode(String delim, Object[] array) {
+ String out = "";
+
+ try {
+ for (int i = 0; i < array.length; i++) {
+ if (i != 0) {
+ out += delim;
+ }
+ out += array[i].toString();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.implode: " + e.toString());
+ }
+ return out;
+ }
+
+ public static String urlencode_rfc3986(String text) {
+ final String encoded = URLEncoder.encode(text).replace("+", "%20").replaceAll("%7E", "~");
+
+ return encoded;
+ }
+
+ public String prepareParameters(HashMap<String, String> params, boolean my, boolean addF) {
+ String paramsDone = null;
+
+ if (my != true && settings.excludeMine > 0) {
+ if (params == null) {
+ params = new HashMap<String, String>();
+ }
+ if (addF == true) {
+ params.put("f", "1");
+ }
+
+ Log.i(cgSettings.tag, "Skipping caches found or hidden by user.");
+ }
+
+ if (params != null) {
+ Object[] keys = params.keySet().toArray();
+ ArrayList<String> paramsEncoded = new ArrayList<String>();
+ String key;
+ String value;
+
+ for (int i = 0; i < keys.length; i++) {
+ key = (String) keys[i];
+ value = (String) params.get(key);
+
+ if (key.charAt(0) == '^') {
+ key = "";
+ }
+ if (value == null) {
+ value = "";
+ }
+
+ paramsEncoded.add(key + "=" + urlencode_rfc3986(value));
+ }
+
+ paramsDone = implode("&", paramsEncoded.toArray());
+ } else {
+ paramsDone = "";
+ }
+
+ return paramsDone;
+ }
+
+ public String requestViewstate(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) {
+ final cgResponse response = request(secure, host, path, method, params, xContentType, my, false);
+
+ return findViewstate(response.getData(), 0);
+ }
+
+ public String requestViewstate1(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) {
+ final cgResponse response = request(secure, host, path, method, params, xContentType, my, false);
+
+ return findViewstate(response.getData(), 1);
+ }
+
+ public String requestLogged(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) {
+ cgResponse response = request(secure, host, path, method, params, xContentType, my, addF);
+ String data = response.getData();
+
+ if (checkLogin(data) == false) {
+ int loginState = login();
+ if (loginState == 1) {
+ response = request(secure, host, path, method, params, xContentType, my, addF);
+ data = response.getData();
+ } else {
+ Log.i(cgSettings.tag, "Working as guest.");
+ }
+ }
+
+ return data;
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) {
+ // prepare parameters
+ final String paramsDone = prepareParameters(params, my, addF);
+
+ return request(secure, host, path, method, paramsDone, 0, xContentType);
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, int requestId, boolean xContentType, boolean my, boolean addF) {
+ // prepare parameters
+ final String paramsDone = prepareParameters(params, my, addF);
+
+ return request(secure, host, path, method, paramsDone, requestId, xContentType);
+ }
+
+ public cgResponse request(boolean secure, String host, String path, String method, String params, int requestId, Boolean xContentType) {
+ URL u = null;
+ int httpCode = -1;
+ String httpMessage = null;
+ String httpLocation = null;
+
+ if (requestId == 0) {
+ requestId = (int) (Math.random() * 1000);
+ }
+
+ if (method == null || (method.equalsIgnoreCase("GET") == false && method.equalsIgnoreCase("POST") == false)) {
+ method = "POST";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ // https
+ String scheme = "http://";
+ if (secure) {
+ scheme = "https://";
+ }
+
+ // prepare cookies
+ String cookiesDone = null;
+ if (cookies == null || cookies.isEmpty() == true) {
+ if (cookies == null) {
+ cookies = new HashMap<String, String>();
+ }
+
+ final Map<String, ?> prefsAll = prefs.getAll();
+ final Set<String> prefsKeys = prefsAll.keySet();
+
+ for (String key : prefsKeys) {
+ if (key.matches("cookie_.+") == true) {
+ final String cookieKey = key.substring(7);
+ final String cookieValue = (String) prefsAll.get(key);
+
+ cookies.put(cookieKey, cookieValue);
+ }
+ }
+ }
+
+ if (cookies != null && !cookies.isEmpty() && cookies.keySet().size() > 0) {
+ final Object[] keys = cookies.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+
+ for (int i = 0; i < keys.length; i++) {
+ String value = cookies.get(keys[i].toString());
+ cookiesEncoded.add(keys[i] + "=" + value);
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+
+ if (cookiesDone == null) {
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0 && prefsValues.keySet().size() > 0) {
+ final Object[] keys = prefsValues.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+ final int length = keys.length;
+
+ for (int i = 0; i < length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ cookiesEncoded.add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString()));
+ }
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+ }
+
+ if (cookiesDone == null) {
+ cookiesDone = "";
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ StringBuffer buffer = null;
+
+ for (int i = 0; i < 5; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer = new StringBuffer();
+ timeout = 30000 + (i * 10000);
+
+ try {
+ if (method.equals("GET")) {
+ // GET
+ u = new URL(scheme + host + path + "?" + params);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ if (xContentType == true) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ }
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
+ // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false);
+ connection.setDoInput(true);
+ connection.setDoOutput(false);
+ } else {
+ // POST
+ u = new URL(scheme + host + path);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ if (xContentType == true) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ }
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
+ // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false);
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ }
+
+ String headerName = null;
+ final SharedPreferences.Editor prefsEditor = prefs.edit();
+ for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) {
+ if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) {
+ int index;
+ String cookie = uc.getHeaderField(j);
+
+ index = cookie.indexOf(";");
+ if (index > -1) {
+ cookie = cookie.substring(0, cookie.indexOf(";"));
+ }
+
+ index = cookie.indexOf("=");
+ if (index > - 1 && cookie.length() > (index + 1)) {
+ String name = cookie.substring(0, cookie.indexOf("="));
+ String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
+
+ cookies.put(name, value);
+ prefsEditor.putString("cookie_" + name, value);
+ }
+ }
+ }
+ prefsEditor.commit();
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+ httpMessage = connection.getResponseMessage();
+ httpLocation = uc.getHeaderField("Location");
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ if (buffer != null && connection != null) {
+ Log.i(cgSettings.tag + "|" + requestId, "[" + method + " " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + scheme + host + path + "?" + paramsLog);
+ } else {
+ Log.i(cgSettings.tag + "|" + requestId, "[" + method + " | " + httpCode + "] Failed to download " + scheme + host + path + "?" + paramsLog);
+ }
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgeoBase.request.IOException: " + e.toString());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.request: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+ }
+
+ cgResponse response = new cgResponse();
+ String data = null;
+
+ try {
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ response = request(secure, host, path, "GET", new HashMap<String, String>(), requestId, false, false, false);
+ } else {
+ boolean secureRedir = false;
+ if (newLocation.getScheme().equals("https")) {
+ secureRedir = true;
+ }
+ response = request(secureRedir, newLocation.getHost(), newLocation.getPath(), "GET", new HashMap<String, String>(), requestId, false, false, false);
+ }
+ } else {
+ if (buffer != null && buffer.length() > 0) {
+ data = replaceWhitespace(buffer);
+ buffer = null;
+
+ if (data != null) {
+ response.setData(data);
+ } else {
+ response.setData("");
+ }
+ response.setStatusCode(httpCode);
+ response.setStatusMessage(httpMessage);
+ response.setUrl(u.toString());
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.page: " + e.toString());
+ }
+
+ return response;
+ }
+
+ private String replaceWhitespace(final StringBuffer buffer) {
+ final int length = buffer.length();
+ final char[] bytes = new char[length];
+ buffer.getChars(0, length, bytes, 0);
+ int resultSize = 0;
+ boolean lastWasWhitespace = false;
+ for (int i = 0; i < length; i++) {
+ char c = bytes[i];
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
+ if (!lastWasWhitespace) {
+ bytes[resultSize++] =' ';
+ }
+ lastWasWhitespace = true;
+ } else {
+ bytes[resultSize++] = c;
+ lastWasWhitespace = false;
+ }
+ }
+
+ return new String(bytes, 0, resultSize);
+ }
+
+ public String requestJSONgc(String host, String path, String params) {
+ int httpCode = -1;
+ String httpLocation = null;
+
+ // prepare cookies
+ String cookiesDone = null;
+ if (cookies == null || cookies.isEmpty() == true) {
+ if (cookies == null) {
+ cookies = new HashMap<String, String>();
+ }
+
+ final Map<String, ?> prefsAll = prefs.getAll();
+ final Set<String> prefsKeys = prefsAll.keySet();
+
+ for (String key : prefsKeys) {
+ if (key.matches("cookie_.+") == true) {
+ final String cookieKey = key.substring(7);
+ final String cookieValue = (String) prefsAll.get(key);
+
+ cookies.put(cookieKey, cookieValue);
+ }
+ }
+ }
+
+ if (cookies != null) {
+ final Object[] keys = cookies.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+
+ for (int i = 0; i < keys.length; i++) {
+ String value = cookies.get(keys[i].toString());
+ cookiesEncoded.add(keys[i] + "=" + value);
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+
+ if (cookiesDone == null) {
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0) {
+ final Object[] keys = prefsValues.keySet().toArray();
+ final ArrayList<String> cookiesEncoded = new ArrayList<String>();
+ final int length = keys.length;
+
+ for (int i = 0; i < length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ cookiesEncoded.add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString()));
+ }
+ }
+
+ if (cookiesEncoded.size() > 0) {
+ cookiesDone = implode("; ", cookiesEncoded.toArray());
+ }
+ }
+ }
+
+ if (cookiesDone == null) {
+ cookiesDone = "";
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ final StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < 3; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer.delete(0, buffer.length());
+ timeout = 30000 + (i * 15000);
+
+ try {
+ // POST
+ final URL u = new URL("http://" + host + path);
+ uc = u.openConnection();
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Cookie", cookiesDone);
+ uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ uc.setRequestProperty("X-Requested-With", "XMLHttpRequest");
+ uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01");
+ uc.setRequestProperty("Referer", host + "/" + path);
+
+ if (settings.asBrowser == 1) {
+ uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7");
+ uc.setRequestProperty("Accept-Language", "en-US");
+ uc.setRequestProperty("User-Agent", idBrowser);
+ uc.setRequestProperty("Connection", "keep-alive");
+ uc.setRequestProperty("Keep-Alive", "300");
+ }
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod("POST");
+ HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab)
+ connection.setDoInput(true);
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+
+ String headerName = null;
+ final SharedPreferences.Editor prefsEditor = prefs.edit();
+ for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) {
+ if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) {
+ int index;
+ String cookie = uc.getHeaderField(j);
+
+ index = cookie.indexOf(";");
+ if (index > -1) {
+ cookie = cookie.substring(0, cookie.indexOf(";"));
+ }
+
+ index = cookie.indexOf("=");
+ if (index > - 1 && cookie.length() > (index + 1)) {
+ String name = cookie.substring(0, cookie.indexOf("="));
+ String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length());
+
+ cookies.put(name, value);
+ prefsEditor.putString("cookie_" + name, value);
+ }
+ }
+ }
+ prefsEditor.commit();
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+ httpLocation = uc.getHeaderField("Location");
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ Log.i(cgSettings.tag + " | JSON", "[POST " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog);
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSONgc.IOException: " + e.toString());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSONgc: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+ }
+
+ String page = null;
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ page = requestJSONgc(host, path, params);
+ } else {
+ page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params);
+ }
+ } else {
+ page = replaceWhitespace(buffer);
+ }
+
+ if (page != null) {
+ return page;
+ } else {
+ return "";
+ }
+ }
+
+ public String requestJSON(String host, String path, String params) {
+ return requestJSON("http://", host, path, "GET", params);
+ }
+
+ public String requestJSON(String scheme, String host, String path, String method, String params) {
+ int httpCode = -1;
+ String httpLocation = null;
+
+ if (method == null) {
+ method = "GET";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ boolean methodPost = false;
+ if (method.equalsIgnoreCase("POST")) {
+ methodPost = true;
+ }
+
+ URLConnection uc = null;
+ HttpURLConnection connection = null;
+ Integer timeout = 30000;
+ final StringBuffer buffer = new StringBuffer();
+
+ for (int i = 0; i < 3; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ buffer.delete(0, buffer.length());
+ timeout = 30000 + (i * 15000);
+
+ try {
+ try {
+ URL u = null;
+ if (methodPost) {
+ u = new URL(scheme + host + path);
+ } else {
+ u = new URL(scheme + host + path + "?" + params);
+ }
+
+ if (u.getProtocol().toLowerCase().equals("https")) {
+ trustAllHosts();
+ HttpsURLConnection https = (HttpsURLConnection) u.openConnection();
+ https.setHostnameVerifier(doNotVerify);
+ uc = https;
+ } else {
+ uc = (HttpURLConnection) u.openConnection();
+ }
+
+ uc.setRequestProperty("Host", host);
+ uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01");
+ if (methodPost) {
+ uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+ uc.setRequestProperty("Content-Length", Integer.toString(params.length()));
+ uc.setRequestProperty("X-HTTP-Method-Override", "GET");
+ } else {
+ uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+ }
+ uc.setRequestProperty("X-Requested-With", "XMLHttpRequest");
+
+ connection = (HttpURLConnection) uc;
+ connection.setReadTimeout(timeout);
+ connection.setRequestMethod(method);
+ HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab)
+ connection.setDoInput(true);
+ if (methodPost) {
+ connection.setDoOutput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ } else {
+ connection.setDoOutput(false);
+ }
+
+
+ final String encoding = connection.getContentEncoding();
+ InputStream ins;
+
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ ins = new GZIPInputStream(connection.getInputStream());
+ } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
+ ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
+ } else {
+ ins = connection.getInputStream();
+ }
+ final InputStreamReader inr = new InputStreamReader(ins);
+ final BufferedReader br = new BufferedReader(inr);
+
+ readIntoBuffer(br, buffer);
+
+ httpCode = connection.getResponseCode();
+
+ final String paramsLog = params.replaceAll(passMatch, "password=***");
+ Log.i(cgSettings.tag + " | JSON", "[POST " + (int)(params.length() / 1024) + "k | " + httpCode + " | " + (int)(buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog);
+
+ connection.disconnect();
+ br.close();
+ ins.close();
+ inr.close();
+ } catch (IOException e) {
+ httpCode = connection.getResponseCode();
+
+ Log.e(cgSettings.tag, "cgeoBase.requestJSON.IOException: " + httpCode + ": " + connection.getResponseMessage() + " ~ " + e.toString());
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoBase.requestJSON: " + e.toString());
+ }
+
+ if (buffer != null && buffer.length() > 0) {
+ break;
+ }
+
+ if (httpCode == 403) {
+ // we're not allowed to download content, so let's move
+ break;
+ }
+ }
+
+ String page = null;
+ if (httpCode == 302 && httpLocation != null) {
+ final Uri newLocation = Uri.parse(httpLocation);
+ if (newLocation.isRelative() == true) {
+ page = requestJSONgc(host, path, params);
+ } else {
+ page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params);
+ }
+ } else {
+ page = replaceWhitespace(buffer);
+ }
+
+ if (page != null) {
+ return page;
+ } else {
+ return "";
+ }
+ }
+
+ public static String rot13(String text) {
+ final StringBuilder result = new StringBuilder();
+ // plaintext flag (do not convert)
+ boolean plaintext = false;
+
+ int length = text.length();
+ for (int index = 0; index < length; index++) {
+ int c = text.charAt(index);
+ if (c == '[') {
+ plaintext = true;
+ } else if (c == ']') {
+ plaintext = false;
+ } else if (!plaintext) {
+ int capitalized = c & 32;
+ c &= ~capitalized;
+ c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
+ | capitalized;
+ }
+ result.append((char) c);
+ }
+ return result.toString();
+ }
+
+ public static String md5(String text) {
+ String hashed = "";
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ digest.update(text.getBytes(), 0, text.length());
+ hashed = new BigInteger(1, digest.digest()).toString(16);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.md5: " + e.toString());
+ }
+
+ return hashed;
+ }
+
+ public static String sha1(String text) {
+ String hashed = "";
+
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-1");
+ digest.update(text.getBytes(), 0, text.length());
+ hashed = new BigInteger(1, digest.digest()).toString(16);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.sha1: " + e.toString());
+ }
+
+ return hashed;
+ }
+
+ public static byte[] hashHmac(String text, String salt) {
+ byte[] macBytes = {};
+
+ try {
+ SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(), "HmacSHA1");
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(secretKeySpec);
+ macBytes = mac.doFinal(text.getBytes());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.hashHmac: " + e.toString());
+ }
+
+ return macBytes;
+ }
+
+ public static boolean deleteDirectory(File path) {
+ if (path.exists()) {
+ File[] files = path.listFiles();
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ deleteDirectory(files[i]);
+ } else {
+ files[i].delete();
+ }
+ }
+ }
+
+ return (path.delete());
+ }
+
+ public static boolean isIntentAvailable(Context context, String action) {
+ final Intent intent = new Intent(action);
+
+ return isIntentAvailable(context, intent);
+ }
+
+ public static boolean isIntentAvailable(Context context, Intent intent) {
+ final PackageManager packageManager = context.getPackageManager();
+ final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ return (list.size() > 0);
+ }
+
+ public void storeCache(cgeoapplication app, Activity activity, cgCache cache, String geocode, int listId, Handler handler) {
+ try {
+ // cache details
+ if (cache != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", cache.geocode);
+ final Long searchId = searchByGeocode(params, listId, false);
+ cache = app.getCache(searchId);
+ } else if (geocode != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", geocode);
+ final Long searchId = searchByGeocode(params, listId, false);
+ cache = app.getCache(searchId);
+ }
+
+ if (cache == null) {
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+
+ return;
+ }
+
+ final cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, cache.geocode, false, listId, true);
+
+ // store images from description
+ if (cache.description != null) {
+ Html.fromHtml(cache.description, imgGetter, null);
+ }
+
+ // store spoilers
+ if (cache.spoilers != null && cache.spoilers.isEmpty() == false) {
+ for (cgSpoiler oneSpoiler : cache.spoilers) {
+ imgGetter.getDrawable(oneSpoiler.url);
+ }
+ }
+
+ // store map previews
+ if (settings.storeOfflineMaps == 1 && cache.latitude != null && cache.longitude != null) {
+ final String latlonMap = String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude);
+ final Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ final int maxWidth = display.getWidth() - 25;
+ final int maxHeight = display.getHeight() - 25;
+ int edge = 0;
+ if (maxWidth > maxHeight) {
+ edge = maxWidth;
+ } else {
+ edge = maxHeight;
+ }
+
+ String type = "mystery";
+ if (cache.found == true) {
+ type = cache.type + "_found";
+ } else if (cache.disabled == true) {
+ type = cache.type + "_disabled";
+ } else {
+ type = cache.type;
+ }
+
+ final String markerUrl = urlencode_rfc3986("http://cgeo.carnero.cc/_markers/marker_cache_" + type + ".png");
+ final StringBuilder waypoints = new StringBuilder();
+ if (cache.waypoints != null && cache.waypoints.size() > 0) {
+ for (cgWaypoint waypoint : cache.waypoints) {
+ if (waypoint.latitude == null && waypoint.longitude == null) {
+ continue;
+ }
+
+ waypoints.append("&markers=icon%3Ahttp://cgeo.carnero.cc/_markers/marker_waypoint_");
+ waypoints.append(waypoint.type);
+ waypoints.append(".png%7C");
+ waypoints.append(String.format((Locale) null, "%.6f", waypoint.latitude));
+ waypoints.append(",");
+ waypoints.append(String.format((Locale) null, "%.6f", waypoint.longitude));
+ }
+ }
+
+ // download map images in separate background thread for higher performance
+ final String code = cache.geocode;
+ final int finalEdge = edge;
+ Thread staticMapsThread = new Thread("getting static map") {@Override
+ public void run() {
+ cgMapImg mapGetter = new cgMapImg(settings, code);
+
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=20&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 1);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=18&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 2);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=16&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 3);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=14&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 4);
+ mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=11&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 5);
+ }};
+ staticMapsThread.setPriority(Thread.MIN_PRIORITY);
+ staticMapsThread.start();
+ }
+
+ app.markStored(cache.geocode, listId);
+ app.removeCacheFromCache(cache.geocode);
+
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.storeCache: " + e.toString());
+ }
+ }
+
+ public void dropCache(cgeoapplication app, Activity activity, cgCache cache, Handler handler) {
+ try {
+ app.markDropped(cache.geocode);
+ app.removeCacheFromCache(cache.geocode);
+
+ handler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.dropCache: " + e.toString());
+ }
+ }
+
+ public boolean isInViewPort(int centerLat1, int centerLon1, int centerLat2, int centerLon2, int spanLat1, int spanLon1, int spanLat2, int spanLon2) {
+ try {
+ // expects coordinates in E6 format
+ final int left1 = centerLat1 - (spanLat1 / 2);
+ final int right1 = centerLat1 + (spanLat1 / 2);
+ final int top1 = centerLon1 + (spanLon1 / 2);
+ final int bottom1 = centerLon1 - (spanLon1 / 2);
+
+ final int left2 = centerLat2 - (spanLat2 / 2);
+ final int right2 = centerLat2 + (spanLat2 / 2);
+ final int top2 = centerLon2 + (spanLon2 / 2);
+ final int bottom2 = centerLon2 - (spanLon2 / 2);
+
+ if (left2 <= left1) {
+ return false;
+ }
+ if (right2 >= right1) {
+ return false;
+ }
+ if (top2 >= top1) {
+ return false;
+ }
+ if (bottom2 <= bottom1) {
+ return false;
+ }
+
+ return true;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgBase.isInViewPort: " + e.toString());
+ return false;
+ }
+ }
+
+ public boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, Double cacheLat, Double cacheLon) {
+ if (cacheLat == null || cacheLon == null) {
+ return false;
+ }
+
+ // viewport is defined by center, span and some (10%) reserve on every side
+ int minLat = centerLat - (spanLat / 2) - (spanLat / 10);
+ int maxLat = centerLat + (spanLat / 2) + (spanLat / 10);
+ int minLon = centerLon - (spanLon / 2) - (spanLon / 10);
+ int maxLon = centerLon + (spanLon / 2) + (spanLon / 10);
+ int cLat = (int) Math.round(cacheLat * 1e6);
+ int cLon = (int) Math.round(cacheLon * 1e6);
+ int mid = 0;
+
+ if (maxLat < minLat) {
+ mid = minLat;
+ minLat = maxLat;
+ maxLat = mid;
+ }
+
+ if (maxLon < minLon) {
+ mid = minLon;
+ minLon = maxLon;
+ maxLon = mid;
+ }
+
+ boolean latOk = false;
+ boolean lonOk = false;
+
+ if (cLat >= minLat && cLat <= maxLat) {
+ latOk = true;
+ }
+ if (cLon >= minLon && cLon <= maxLon) {
+ lonOk = true;
+ }
+
+ if (latOk == true && lonOk == true) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ private static char[] base64map1 = new char[64];
+
+ static {
+ int i = 0;
+ for (char c = 'A'; c <= 'Z'; c++) {
+ base64map1[i++] = c;
+ }
+ for (char c = 'a'; c <= 'z'; c++) {
+ base64map1[i++] = c;
+ }
+ for (char c = '0'; c <= '9'; c++) {
+ base64map1[i++] = c;
+ }
+ base64map1[i++] = '+';
+ base64map1[i++] = '/';
+ }
+ private static byte[] base64map2 = new byte[128];
+
+ static {
+ for (int i = 0; i < base64map2.length; i++) {
+ base64map2[i] = -1;
+ }
+ for (int i = 0; i < 64; i++) {
+ base64map2[base64map1[i]] = (byte) i;
+ }
+ }
+
+ 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];
+ 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] : '=';
+ op++;
+ out[op] = op < oDataLen ? base64map1[o3] : '=';
+ op++;
+ }
+
+ return new String(out);
+ }
+
+ public static byte[] base64Decode(String text) {
+ char[] in = text.toCharArray();
+
+ int iLen = in.length;
+ if (iLen % 4 != 0) {
+ throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4.");
+ }
+ while (iLen > 0 && in[iLen - 1] == '=') {
+ iLen--;
+ }
+ int oLen = (iLen * 3) / 4;
+ byte[] out = new byte[oLen];
+ int ip = 0;
+ int op = 0;
+ while (ip < iLen) {
+ int i0 = in[ip++];
+ int i1 = in[ip++];
+ int i2 = ip < iLen ? in[ip++] : 'A';
+ int i3 = ip < iLen ? in[ip++] : 'A';
+ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) {
+ throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
+ }
+ int b0 = base64map2[i0];
+ int b1 = base64map2[i1];
+ int b2 = base64map2[i2];
+ int b3 = base64map2[i3];
+ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) {
+ throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
+ }
+ int o0 = (b0 << 2) | (b1 >>> 4);
+ int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
+ int o2 = ((b2 & 3) << 6) | b3;
+ out[op++] = (byte) o0;
+ if (op < oLen) {
+ out[op++] = (byte) o1;
+ }
+ if (op < oLen) {
+ out[op++] = (byte) o2;
+ }
+ }
+ return out;
+ }
+
+ public int getIcon(boolean cache, String type, boolean own, boolean found, boolean disabled) {
+ if (gcIcons.isEmpty()) {
+ // default markers
+ gcIcons.put("ape", R.drawable.marker_cache_ape);
+ gcIcons.put("cito", R.drawable.marker_cache_cito);
+ gcIcons.put("earth", R.drawable.marker_cache_earth);
+ gcIcons.put("event", R.drawable.marker_cache_event);
+ gcIcons.put("letterbox", R.drawable.marker_cache_letterbox);
+ gcIcons.put("locationless", R.drawable.marker_cache_locationless);
+ gcIcons.put("mega", R.drawable.marker_cache_mega);
+ gcIcons.put("multi", R.drawable.marker_cache_multi);
+ gcIcons.put("traditional", R.drawable.marker_cache_traditional);
+ gcIcons.put("virtual", R.drawable.marker_cache_virtual);
+ gcIcons.put("webcam", R.drawable.marker_cache_webcam);
+ gcIcons.put("wherigo", R.drawable.marker_cache_wherigo);
+ gcIcons.put("mystery", R.drawable.marker_cache_mystery);
+ gcIcons.put("gchq", R.drawable.marker_cache_gchq);
+ // own cache markers
+ gcIcons.put("ape-own", R.drawable.marker_cache_ape_own);
+ gcIcons.put("cito-own", R.drawable.marker_cache_cito_own);
+ gcIcons.put("earth-own", R.drawable.marker_cache_earth_own);
+ gcIcons.put("event-own", R.drawable.marker_cache_event_own);
+ gcIcons.put("letterbox-own", R.drawable.marker_cache_letterbox_own);
+ gcIcons.put("locationless-own", R.drawable.marker_cache_locationless_own);
+ gcIcons.put("mega-own", R.drawable.marker_cache_mega_own);
+ gcIcons.put("multi-own", R.drawable.marker_cache_multi_own);
+ gcIcons.put("traditional-own", R.drawable.marker_cache_traditional_own);
+ gcIcons.put("virtual-own", R.drawable.marker_cache_virtual_own);
+ gcIcons.put("webcam-own", R.drawable.marker_cache_webcam_own);
+ gcIcons.put("wherigo-own", R.drawable.marker_cache_wherigo_own);
+ gcIcons.put("mystery-own", R.drawable.marker_cache_mystery_own);
+ gcIcons.put("gchq-own", R.drawable.marker_cache_gchq_own);
+ // found cache markers
+ gcIcons.put("ape-found", R.drawable.marker_cache_ape_found);
+ gcIcons.put("cito-found", R.drawable.marker_cache_cito_found);
+ gcIcons.put("earth-found", R.drawable.marker_cache_earth_found);
+ gcIcons.put("event-found", R.drawable.marker_cache_event_found);
+ gcIcons.put("letterbox-found", R.drawable.marker_cache_letterbox_found);
+ gcIcons.put("locationless-found", R.drawable.marker_cache_locationless_found);
+ gcIcons.put("mega-found", R.drawable.marker_cache_mega_found);
+ gcIcons.put("multi-found", R.drawable.marker_cache_multi_found);
+ gcIcons.put("traditional-found", R.drawable.marker_cache_traditional_found);
+ gcIcons.put("virtual-found", R.drawable.marker_cache_virtual_found);
+ gcIcons.put("webcam-found", R.drawable.marker_cache_webcam_found);
+ gcIcons.put("wherigo-found", R.drawable.marker_cache_wherigo_found);
+ gcIcons.put("mystery-found", R.drawable.marker_cache_mystery_found);
+ gcIcons.put("gchq-found", R.drawable.marker_cache_gchq_found);
+ // disabled cache markers
+ gcIcons.put("ape-disabled", R.drawable.marker_cache_ape_disabled);
+ gcIcons.put("cito-disabled", R.drawable.marker_cache_cito_disabled);
+ gcIcons.put("earth-disabled", R.drawable.marker_cache_earth_disabled);
+ gcIcons.put("event-disabled", R.drawable.marker_cache_event_disabled);
+ gcIcons.put("letterbox-disabled", R.drawable.marker_cache_letterbox_disabled);
+ gcIcons.put("locationless-disabled", R.drawable.marker_cache_locationless_disabled);
+ gcIcons.put("mega-disabled", R.drawable.marker_cache_mega_disabled);
+ gcIcons.put("multi-disabled", R.drawable.marker_cache_multi_disabled);
+ gcIcons.put("traditional-disabled", R.drawable.marker_cache_traditional_disabled);
+ gcIcons.put("virtual-disabled", R.drawable.marker_cache_virtual_disabled);
+ gcIcons.put("webcam-disabled", R.drawable.marker_cache_webcam_disabled);
+ gcIcons.put("wherigo-disabled", R.drawable.marker_cache_wherigo_disabled);
+ gcIcons.put("mystery-disabled", R.drawable.marker_cache_mystery_disabled);
+ gcIcons.put("gchq-disabled", R.drawable.marker_cache_gchq_disabled);
+ }
+
+ if (wpIcons.isEmpty()) {
+ wpIcons.put("waypoint", R.drawable.marker_waypoint_waypoint);
+ wpIcons.put("flag", R.drawable.marker_waypoint_flag);
+ wpIcons.put("pkg", R.drawable.marker_waypoint_pkg);
+ wpIcons.put("puzzle", R.drawable.marker_waypoint_puzzle);
+ wpIcons.put("stage", R.drawable.marker_waypoint_stage);
+ wpIcons.put("trailhead", R.drawable.marker_waypoint_trailhead);
+ }
+
+ int icon = -1;
+ String iconTxt = null;
+
+ if (cache == true) {
+ if (type != null && type.length() > 0) {
+ if (own == true) {
+ iconTxt = type + "-own";
+ } else if (found == true) {
+ iconTxt = type + "-found";
+ } else if (disabled == true) {
+ iconTxt = type + "-disabled";
+ } else {
+ iconTxt = type;
+ }
+ } else {
+ iconTxt = "traditional";
+ }
+
+ if (gcIcons.containsKey(iconTxt) == true) {
+ icon = gcIcons.get(iconTxt);
+ } else {
+ icon = gcIcons.get("traditional");
+ }
+ } else {
+ if (type != null && type.length() > 0) {
+ iconTxt = type;
+ } else {
+ iconTxt = "waypoint";
+ }
+
+ if (wpIcons.containsKey(iconTxt) == true) {
+ icon = wpIcons.get(iconTxt);
+ } else {
+ icon = wpIcons.get("waypoint");
+ }
+ }
+
+ return icon;
+ }
+
+ public boolean isLocus(Context context) {
+ boolean locus = false;
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+ if (isIntentAvailable(context, intentTest) == true) {
+ locus = true;
+ }
+
+ return locus;
+ }
+
+ public boolean isRmaps(Context context) {
+ boolean rmaps = false;
+ final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS");
+ if (isIntentAvailable(context, intent) == true) {
+ rmaps = true;
+ }
+
+ return rmaps;
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) {
+ // waypoint
+ return runExternalMap(application, activity, res, warning, tracker, null, null, latitude, longitude);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgWaypoint waypoint) {
+ // waypoint
+ return runExternalMap(application, activity, res, warning, tracker, null, waypoint, null, null);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache) {
+ // cache
+ return runExternalMap(application, activity, res, warning, tracker, cache, null, null, null);
+ }
+
+ public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache, cgWaypoint waypoint, Double latitude, Double longitude) {
+ if (cache == null && waypoint == null && latitude == null && longitude == null) {
+ return false;
+ }
+
+ if (application == mapAppLocus) {
+ // locus
+ try {
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+
+ if (isIntentAvailable(activity, intentTest) == true) {
+ final ArrayList<cgWaypoint> waypoints = new ArrayList<cgWaypoint>();
+ // get only waypoints with coordinates
+ if (cache != null && cache.waypoints != null && cache.waypoints.isEmpty() == false) {
+ for (cgWaypoint wp : cache.waypoints) {
+ if (wp.latitude != null && wp.longitude != null) {
+ waypoints.add(wp);
+ }
+ }
+ }
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(baos);
+
+ dos.writeInt(1); // not used
+ if (cache != null) {
+ if (waypoints == null || waypoints.isEmpty() == true) {
+ dos.writeInt(1); // cache only
+ } else {
+ dos.writeInt((1 + waypoints.size())); // cache and waypoints
+ }
+ } else {
+ dos.writeInt(1); // one waypoint
+ }
+
+ int icon = -1;
+ if (cache != null) {
+ icon = getIcon(true, cache.type, cache.own, cache.found, cache.disabled || cache.archived);
+ } else if (waypoint != null) {
+ icon = getIcon(false, waypoint.type, false, false, false);
+ } else {
+ icon = getIcon(false, "waypoint", false, false, false);
+ }
+
+ if (icon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, icon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (cache != null && cache.name != null && cache.name.length() > 0) {
+ dos.writeUTF(cache.name);
+ } else if (waypoint != null && waypoint.name != null && waypoint.name.length() > 0) {
+ dos.writeUTF(waypoint.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF(cache.geocode.toUpperCase());
+ } else if (waypoint != null && waypoint.lookup != null && waypoint.lookup.length() > 0) {
+ dos.writeUTF(waypoint.lookup.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeodetail;geocode;" + cache.geocode);
+ } else if (waypoint != null && waypoint.id != null && waypoint.id > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeowaypoint;id;" + waypoint.id);
+ } else {
+ dos.writeUTF("");
+ }
+
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ dos.writeDouble(cache.latitude); // latitude
+ dos.writeDouble(cache.longitude); // longitude
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ dos.writeDouble(waypoint.latitude); // latitude
+ dos.writeDouble(waypoint.longitude); // longitude
+ } else {
+ dos.writeDouble(latitude); // latitude
+ dos.writeDouble(longitude); // longitude
+ }
+
+ // cache waypoints
+ if (waypoints != null && waypoints.isEmpty() == false) {
+ for (cgWaypoint wp : waypoints) {
+ if (wp == null || wp.latitude == null || wp.longitude == null) {
+ continue;
+ }
+
+ final int wpIcon = getIcon(false, wp.type, false, false, false);
+
+ if (wpIcon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, wpIcon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (wp.lookup != null && wp.lookup.length() > 0) {
+ dos.writeUTF(wp.lookup.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (wp.name != null && wp.name.length() > 0) {
+ dos.writeUTF(wp.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (wp.id != null && wp.id > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeowaypoint;id;" + wp.id);
+ } else {
+ dos.writeUTF("");
+ }
+
+ dos.writeDouble(wp.latitude); // latitude
+ dos.writeDouble(wp.longitude); // longitude
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("menion.points:data"));
+ intent.putExtra("data", baos.toByteArray());
+
+ activity.startActivity(intent);
+
+ sendAnal(activity, tracker, "/external/locus");
+
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (application == mapAppRmaps) {
+ // rmaps
+ try {
+ final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS");
+
+ if (isIntentAvailable(activity, intent) == true) {
+ final ArrayList<String> locations = new ArrayList<String>();
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ locations.add(String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude) + ";" + cache.geocode + ";" + cache.name);
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ locations.add(String.format((Locale) null, "%.6f", waypoint.latitude) + "," + String.format((Locale) null, "%.6f", waypoint.longitude) + ";" + waypoint.lookup + ";" + waypoint.name);
+ }
+
+ intent.putStringArrayListExtra("locations", locations);
+
+ activity.startActivity(intent);
+
+ sendAnal(activity, tracker, "/external/rmaps");
+
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (application == mapAppAny) {
+ // fallback
+ try {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + cache.latitude + "," + cache.longitude)));
+ // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps
+ } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + waypoint.latitude + "," + waypoint.longitude)));
+ // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps
+ }
+
+ sendAnal(activity, tracker, "/external/native/maps");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ Log.i(cgSettings.tag, "cgBase.runExternalMap: No maps application available.");
+
+ if (warning != null && res != null) {
+ warning.showToast(res.getString(R.string.err_application_no));
+ }
+
+ return false;
+ }
+
+ public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) {
+ return runNavigation(activity, res, settings, warning, tracker, latitude, longitude, null, null);
+ }
+
+ public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude, Double latitudeNow, Double longitudeNow) {
+ if (activity == null) {
+ return false;
+ }
+ if (settings == null) {
+ return false;
+ }
+
+ // Google Navigation
+ if (settings.useGNavigation == 1) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:ll=" + latitude + "," + longitude)));
+
+ sendAnal(activity, tracker, "/external/native/navigation");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ // Google Maps Directions
+ try {
+ if (latitudeNow != null && longitudeNow != null) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&saddr=" + latitudeNow + "," + longitudeNow + "&daddr=" + latitude + "," + longitude)));
+ } else {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&daddr=" + latitude + "," + longitude)));
+ }
+
+ sendAnal(activity, tracker, "/external/native/maps");
+
+ return true;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ Log.i(cgSettings.tag, "cgBase.runNavigation: No navigation application available.");
+
+ if (warning != null && res != null) {
+ warning.showToast(res.getString(R.string.err_navigation_no));
+ }
+
+ return false;
+ }
+
+ public String getMapUserToken(Handler noTokenHandler) {
+ final cgResponse response = request(false, "www.geocaching.com", "/map/default.aspx", "GET", "", 0, false);
+ final String data = response.getData();
+ String usertoken = null;
+
+ if (data != null && data.length() > 0) {
+ final Pattern pattern = Pattern.compile("var userToken[^=]*=[^']*'([^']+)';", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
+
+ final Matcher matcher = pattern.matcher(data);
+ while (matcher.find()) {
+ if (matcher.groupCount() > 0) {
+ usertoken = matcher.group(1);
+ }
+ }
+ }
+
+ if (noTokenHandler != null && (usertoken == null || usertoken.length() == 0)) {
+ noTokenHandler.sendEmptyMessage(0);
+ }
+
+ return usertoken;
+ }
+
+ public void sendAnal(Context context, String page) {
+ (new sendAnalThread(context, null, page)).start();
+ }
+
+ public void sendAnal(Context context, GoogleAnalyticsTracker tracker, String page) {
+ (new sendAnalThread(context, tracker, page)).start();
+ }
+
+ private class sendAnalThread extends Thread {
+
+ Context context = null;
+ GoogleAnalyticsTracker tracker = null;
+ String page = null;
+ boolean startedHere = false;
+
+ public sendAnalThread(Context contextIn, GoogleAnalyticsTracker trackerIn, String pageIn) {
+ context = contextIn;
+ tracker = trackerIn;
+ page = pageIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ if (page == null || page.length() == 0) {
+ page = "/";
+ }
+
+ if (tracker == null && context != null) {
+ startedHere = true;
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, context);
+ }
+
+ tracker.trackPageView(page);
+ tracker.dispatch();
+
+ Log.i(cgSettings.tag, "Logged use of " + page);
+
+ if (startedHere == true) {
+ tracker.stop();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ public Double getElevation(Double latitude, Double longitude) {
+ Double elv = null;
+
+ try {
+ final String host = "maps.googleapis.com";
+ final String path = "/maps/api/elevation/json";
+ final String params = "sensor=false&locations=" + String.format((Locale) null, "%.6f", latitude) + "," + String.format((Locale) null, "%.6f", longitude);
+
+ final String data = requestJSON(host, path, params);
+
+ if (data == null || data.length() == 0) {
+ return elv;
+ }
+
+ JSONObject response = new JSONObject(data);
+ String status = response.getString("status");
+
+ if (status == null || status.equalsIgnoreCase("OK") == false) {
+ return elv;
+ }
+
+ if (response.has("results") == true) {
+ JSONArray results = response.getJSONArray("results");
+ JSONObject result = results.getJSONObject(0);
+ elv = result.getDouble("elevation");
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgBase.getElevation: " + e.toString());
+ }
+
+ return elv;
+ }
+
+ public void showProgress(Activity activity, boolean status) {
+ if (activity == null) {
+ return;
+ }
+
+ final ProgressBar progress = (ProgressBar) activity.findViewById(R.id.actionbar_progress);
+ if (status == true) {
+ progress.setVisibility(View.VISIBLE);
+ } else {
+ progress.setVisibility(View.GONE);
+ }
+ }
+
+ public void goHome(Activity activity) {
+ final Intent intent = new Intent(activity, cgeo.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ activity.startActivity(intent);
+ activity.finish();
+ }
+
+ public void setTitle(Activity activity, String text) {
+ if (activity == null || text == null) {
+ return;
+ }
+
+ final TextView title = (TextView) activity.findViewById(R.id.actionbar_title);
+ if (title != null) {
+ title.setText(text);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgCache.java b/src/cgeo/geocaching/cgCache.java
new file mode 100644
index 0000000..5bf42f2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCache.java
@@ -0,0 +1,218 @@
+package cgeo.geocaching;
+
+import android.text.Spannable;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class cgCache {
+
+ public Long updated = null;
+ public Long detailedUpdate = null;
+ public Long visitedDate = null;
+ public Integer reason = 0;
+ public Boolean detailed = false;
+ public String geocode = "";
+ public String cacheid = "";
+ public String guid = "";
+ public String type = "";
+ public String name = "";
+ public Spannable nameSp = null;
+ public String owner = "";
+ public String ownerReal = "";
+ public Date hidden = null;
+ public String hint = "";
+ public String size = "";
+ public Float difficulty = new Float(0);
+ public Float terrain = new Float(0);
+ public Double direction = null;
+ public Double distance = null;
+ public String latlon = "";
+ public String latitudeString = "";
+ public String longitudeString = "";
+ public String location = "";
+ public Double latitude = null;
+ public Double longitude = null;
+ public boolean reliableLatLon = false;
+ public Double elevation = null;
+ public String shortdesc = "";
+ public String description = "";
+ public boolean disabled = false;
+ public boolean archived = false;
+ public boolean members = false;
+ public boolean found = false;
+ public boolean favourite = false;
+ public boolean own = false;
+ public Integer favouriteCnt = null;
+ public Float rating = null;
+ public Integer votes = null;
+ public Float myVote = null;
+ public int inventoryItems = 0;
+ public ArrayList<String> attributes = null;
+ public ArrayList<cgWaypoint> waypoints = null;
+ public ArrayList<cgSpoiler> spoilers = null;
+ public ArrayList<cgLog> logs = null;
+ public ArrayList<cgTrackable> inventory = null;
+ public HashMap<Integer, Integer> logCounts = new HashMap<Integer, Integer>();
+ public boolean logOffline = false;
+ // temporary values
+ public boolean statusChecked = false;
+ public boolean statusCheckedView = false;
+ public String directionImg = null;
+
+ public cgCache merge(cgData storage) {
+ //LeeB - loading cache from db is slow
+ if(false){
+ return this;
+ }
+
+ boolean loadA = true;
+ boolean loadW = true;
+ boolean loadS = true;
+ boolean loadL = true;
+ boolean loadI = true;
+
+ if (attributes == null || attributes.isEmpty() == true) {
+ loadA = false;
+ }
+ if (waypoints == null || waypoints.isEmpty() == true) {
+ loadW = false;
+ }
+ if (spoilers == null || spoilers.isEmpty() == true) {
+ loadS = false;
+ }
+ if (logs == null || logs.isEmpty() == true) {
+ loadL = false;
+ }
+ if (inventory == null || inventory.isEmpty() == true) {
+ loadI = false;
+ }
+
+ final cgCache oldCache = storage.loadCache(geocode, guid, loadA, loadW, loadS, loadL, loadI, false);
+
+ if (oldCache == null) {
+ return this;
+ }
+
+ updated = System.currentTimeMillis();
+ if (detailed == false && oldCache.detailed == true) {
+ detailed = true;
+ detailedUpdate = System.currentTimeMillis();
+ }
+
+ if (visitedDate == null || visitedDate == 0) {
+ visitedDate = oldCache.visitedDate;
+ }
+ if (reason == null || reason == 0) {
+ reason = oldCache.reason;
+ }
+ if (geocode == null || geocode.length() == 0) {
+ geocode = oldCache.geocode;
+ }
+ if (cacheid == null || cacheid.length() == 0) {
+ cacheid = oldCache.cacheid;
+ }
+ if (guid == null || guid.length() == 0) {
+ guid = oldCache.guid;
+ }
+ if (type == null || type.length() == 0) {
+ type = oldCache.type;
+ }
+ if (name == null || name.length() == 0) {
+ name = oldCache.name;
+ }
+ if (nameSp == null || nameSp.length() == 0) {
+ nameSp = oldCache.nameSp;
+ }
+ if (owner == null || owner.length() == 0) {
+ owner = oldCache.owner;
+ }
+ if (ownerReal == null || ownerReal.length() == 0) {
+ ownerReal = oldCache.ownerReal;
+ }
+ if (hidden == null) {
+ hidden = oldCache.hidden;
+ }
+ if (hint == null || hint.length() == 0) {
+ hint = oldCache.hint;
+ }
+ if (size == null || size.length() == 0) {
+ size = oldCache.size;
+ }
+ if (difficulty == null || difficulty == 0) {
+ difficulty = oldCache.difficulty;
+ }
+ if (terrain == null || terrain == 0) {
+ terrain = oldCache.terrain;
+ }
+ if (direction == null) {
+ direction = oldCache.direction;
+ }
+ if (distance == null) {
+ distance = oldCache.distance;
+ }
+ if (latlon == null || latlon.length() == 0) {
+ latlon = oldCache.latlon;
+ }
+ if (latitudeString == null || latitudeString.length() == 0) {
+ latitudeString = oldCache.latitudeString;
+ }
+ if (longitudeString == null || longitudeString.length() == 0) {
+ longitudeString = oldCache.longitudeString;
+ }
+ if (location == null || location.length() == 0) {
+ location = oldCache.location;
+ }
+ if (latitude == null) {
+ latitude = oldCache.latitude;
+ }
+ if (longitude == null) {
+ longitude = oldCache.longitude;
+ }
+ if (elevation == null) {
+ elevation = oldCache.elevation;
+ }
+ if (shortdesc == null || shortdesc.length() == 0) {
+ shortdesc = oldCache.shortdesc;
+ }
+ if (description == null || description.length() == 0) {
+ description = oldCache.description;
+ }
+ if (favouriteCnt == null) {
+ favouriteCnt = oldCache.favouriteCnt;
+ }
+ if (rating == null) {
+ rating = oldCache.rating;
+ }
+ if (votes == null) {
+ votes = oldCache.votes;
+ }
+ if (myVote == null) {
+ myVote = oldCache.myVote;
+ }
+ if (inventoryItems == 0) {
+ inventoryItems = oldCache.inventoryItems;
+ }
+ if (attributes == null) {
+ attributes = oldCache.attributes;
+ }
+ if (waypoints == null) {
+ waypoints = oldCache.waypoints;
+ }
+ if (spoilers == null) {
+ spoilers = oldCache.spoilers;
+ }
+ if (inventory == null) {
+ inventory = oldCache.inventory;
+ }
+ if (logs == null || logs.isEmpty()) { // keep last known logs if none
+ logs = oldCache.logs;
+ }
+
+ return this;
+ }
+
+ public boolean hasTrackables(){
+ return inventoryItems > 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheDifficultyComparator.java b/src/cgeo/geocaching/cgCacheDifficultyComparator.java
new file mode 100644
index 0000000..69971a4
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheDifficultyComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheDifficultyComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.difficulty == null || cache2.difficulty == null) {
+ return 0;
+ }
+
+ if (cache1.difficulty > cache2.difficulty) {
+ return 1;
+ } else if (cache2.difficulty > cache1.difficulty) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheDifficultyComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheDistanceComparator.java b/src/cgeo/geocaching/cgCacheDistanceComparator.java
new file mode 100644
index 0000000..2fbdd64
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheDistanceComparator.java
@@ -0,0 +1,51 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheDistanceComparator implements Comparator<cgCache> {
+ private Double latitude = null;
+ private Double longitude = null;
+
+ public cgCacheDistanceComparator() {
+ // nothing
+ }
+
+ public cgCacheDistanceComparator(Double latitudeIn, Double longitudeIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ }
+
+ public void setCoords(Double latitudeIn, Double longitudeIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ }
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ int result = 0;
+ try {
+ if (
+ (cache1.latitude == null || cache1.longitude == null || cache2.latitude == null || cache2.longitude == null) &&
+ cache1.distance != null && cache2.distance != null
+ ) {
+ if (cache1.distance < cache2.distance) return -1;
+ else if (cache1.distance > cache2.distance) return 1;
+ else return 0;
+ } else {
+ if (cache1.latitude == null || cache1.longitude == null) return 1;
+ if (cache2.latitude == null || cache2.longitude == null) return -1;
+
+ Double distance1 = cgBase.getDistance(latitude, longitude, cache1.latitude, cache1.longitude);
+ Double distance2 = cgBase.getDistance(latitude, longitude, cache2.latitude, cache2.longitude);
+
+ if (distance1 < distance2) result = -1;
+ else if (distance1 > distance2) result = 1;
+ else result = 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheDistanceComparator.compare: " + e.toString());
+ }
+
+ return result;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheGeocodeComparator.java b/src/cgeo/geocaching/cgCacheGeocodeComparator.java
new file mode 100644
index 0000000..e06d9f3
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheGeocodeComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheGeocodeComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.geocode == null || cache1.geocode.length() <= 0 || cache2.geocode == null || cache2.geocode.length() <= 0) {
+ return 0;
+ }
+
+ if (cache1.geocode.length() > cache2.geocode.length()) {
+ return 1;
+ } else if (cache2.geocode.length() > cache1.geocode.length()) {
+ return -1;
+ } else {
+ return cache1.geocode.compareToIgnoreCase(cache2.geocode);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheGeocodeComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheInventoryComparator.java b/src/cgeo/geocaching/cgCacheInventoryComparator.java
new file mode 100644
index 0000000..e58eb43
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheInventoryComparator.java
@@ -0,0 +1,36 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+/**
+ * compares by number of items in inventory
+ * @author bananeweizen
+ *
+ */
+public class cgCacheInventoryComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ int itemCount1 = 0;
+ int itemCount2 = 0;
+ if (cache1.difficulty != null) {
+ itemCount1 = cache1.inventoryItems;
+ }
+ if (cache2.difficulty != null) {
+ itemCount2 = cache2.inventoryItems;
+ }
+
+ if (itemCount1 < itemCount2) {
+ return 1;
+ } else if (itemCount2 < itemCount1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheInventoryComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheListAdapter.java b/src/cgeo/geocaching/cgCacheListAdapter.java
new file mode 100644
index 0000000..b1eded2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheListAdapter.java
@@ -0,0 +1,909 @@
+package cgeo.geocaching;
+
+import java.util.List;
+import java.util.HashMap;
+import android.app.Activity;
+import android.text.Spannable;
+import android.text.style.StrikethroughSpan;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.TranslateAnimation;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Locale;
+
+import cgeo.geocaching.filter.cgFilter;
+
+public class cgCacheListAdapter extends ArrayAdapter<cgCache> {
+
+ private Resources res = null;
+ private List<cgCache> list = null;
+ private cgSettings settings = null;
+ private cgCacheView holder = null;
+ private LayoutInflater inflater = null;
+ private Activity activity = null;
+ private cgBase base = null;
+ private cgCacheDistanceComparator dstComparator = null;
+ private Comparator statComparator = null;
+ private boolean historic = false;
+ private Double latitude = null;
+ private Double longitude = null;
+ private Double azimuth = new Double(0);
+ private long lastSort = 0l;
+ private boolean sort = true;
+ private int checked = 0;
+ private boolean selectMode = false;
+ private HashMap<String, Drawable> gcIcons = new HashMap<String, Drawable>();
+ private ArrayList<cgCompassMini> compasses = new ArrayList<cgCompassMini>();
+ private ArrayList<cgDistanceView> distances = new ArrayList<cgDistanceView>();
+ private int[] ratingBcgs = new int[3];
+ private float pixelDensity = 1f;
+ private static final int SWIPE_MIN_DISTANCE = 60;
+ private static final int SWIPE_MAX_OFF_PATH = 100;
+ private static final int SWIPE_DISTANCE = 80;
+ private static final float SWIPE_OPACITY = 0.5f;
+ private cgFilter currentFilter = null;
+ private List<cgCache> originalList = null;
+
+ public cgCacheListAdapter(Activity activityIn, cgSettings settingsIn, List<cgCache> listIn, cgBase baseIn) {
+ super(activityIn, 0, listIn);
+
+ res = activityIn.getResources();
+ activity = activityIn;
+ settings = settingsIn;
+ list = listIn;
+ base = baseIn;
+ dstComparator = new cgCacheDistanceComparator();
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", (Drawable) activity.getResources().getDrawable(R.drawable.type_ape));
+ gcIcons.put("cito", (Drawable) activity.getResources().getDrawable(R.drawable.type_cito));
+ gcIcons.put("earth", (Drawable) activity.getResources().getDrawable(R.drawable.type_earth));
+ gcIcons.put("event", (Drawable) activity.getResources().getDrawable(R.drawable.type_event));
+ gcIcons.put("letterbox", (Drawable) activity.getResources().getDrawable(R.drawable.type_letterbox));
+ gcIcons.put("locationless", (Drawable) activity.getResources().getDrawable(R.drawable.type_locationless));
+ gcIcons.put("mega", (Drawable) activity.getResources().getDrawable(R.drawable.type_mega));
+ gcIcons.put("multi", (Drawable) activity.getResources().getDrawable(R.drawable.type_multi));
+ gcIcons.put("traditional", (Drawable) activity.getResources().getDrawable(R.drawable.type_traditional));
+ gcIcons.put("virtual", (Drawable) activity.getResources().getDrawable(R.drawable.type_virtual));
+ gcIcons.put("webcam", (Drawable) activity.getResources().getDrawable(R.drawable.type_webcam));
+ gcIcons.put("wherigo", (Drawable) activity.getResources().getDrawable(R.drawable.type_wherigo));
+ gcIcons.put("mystery", (Drawable) activity.getResources().getDrawable(R.drawable.type_mystery));
+ gcIcons.put("gchq", (Drawable) activity.getResources().getDrawable(R.drawable.type_hq));
+ }
+
+ if (settings.skin == 0) {
+ ratingBcgs[0] = R.drawable.favourite_background_red_dark;
+ ratingBcgs[1] = R.drawable.favourite_background_orange_dark;
+ ratingBcgs[2] = R.drawable.favourite_background_green_dark;
+ } else {
+ ratingBcgs[0] = R.drawable.favourite_background_red_light;
+ ratingBcgs[1] = R.drawable.favourite_background_orange_light;
+ ratingBcgs[2] = R.drawable.favourite_background_green_light;
+ }
+ }
+
+ public void setComparator(Comparator comparator) {
+ statComparator = comparator;
+
+ forceSort(latitude, longitude);
+ }
+
+ /**
+ * Called when a new page of caches was loaded.
+ */
+ public void reFilter(){
+ if(currentFilter != null){
+ // Back up the list again
+ originalList = new ArrayList<cgCache>(list);
+
+ currentFilter.filter(list);
+ }
+ }
+
+ /**
+ * Called after a user action on the filter menu.
+ */
+ public void setFilter(cgFilter filter){
+ // Backup current caches list if it isn't backed up yet
+ if (originalList == null) {
+ originalList = new ArrayList<cgCache>(list);
+ }
+
+ // If there is already a filter in place, this is a request to change or clear the filter, so we have to
+ // replace the original cache list
+ if (currentFilter != null) {
+ list.clear();
+ list.addAll(originalList);
+ }
+
+ // Do the filtering or clear it
+ if (filter != null) {
+ filter.filter(list);
+ }
+ currentFilter = filter;
+
+ notifyDataSetChanged();
+ }
+
+ public void clearFilter() {
+ if (originalList != null) {
+ list.clear();
+ list.addAll(originalList);
+
+ currentFilter = null;
+ }
+
+ notifyDataSetChanged();
+ }
+
+ public boolean isFilter() {
+ if (currentFilter != null) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void setHistoric(boolean historicIn) {
+ historic = historicIn;
+
+ if (historic == true) {
+ statComparator = new cgCacheVisitComparator();
+ } else {
+ statComparator = null;
+ }
+ }
+
+ public int getChecked() {
+ return checked;
+ }
+
+ public boolean setSelectMode(boolean status, boolean clear) {
+ selectMode = status;
+
+ if (selectMode == false && clear == true) {
+ for (cgCache cache : list) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ }
+ checked = 0;
+ } else if (selectMode == true) {
+ for (cgCache cache : list) {
+ cache.statusCheckedView = false;
+ }
+ }
+ checkChecked(0);
+
+ notifyDataSetChanged();
+
+ return selectMode;
+ }
+
+ public boolean getSelectMode() {
+ return selectMode;
+ }
+
+ public void switchSelectMode() {
+ selectMode = !selectMode;
+
+ if (selectMode == false) {
+ for (cgCache cache : list) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ }
+ checked = 0;
+ } else if (selectMode == true) {
+ for (cgCache cache : list) {
+ cache.statusCheckedView = false;
+ }
+ }
+ checkChecked(0);
+
+ notifyDataSetChanged();
+ }
+
+ public void invertSelection() {
+ int check = 0;
+
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ cache.statusChecked = false;
+ cache.statusCheckedView = false;
+ } else {
+ cache.statusChecked = true;
+ cache.statusCheckedView = true;
+
+ check++;
+ }
+ }
+ checkChecked(check);
+
+ notifyDataSetChanged();
+ }
+
+ public void forceSort(Double latitudeIn, Double longitudeIn) {
+ if (list == null || list.isEmpty() == true) {
+ return;
+ }
+ if (sort == false) {
+ return;
+ }
+
+ try {
+ if (statComparator != null) {
+ Collections.sort((List<cgCache>) list, statComparator);
+ } else {
+ if (latitudeIn == null || longitudeIn == null) {
+ return;
+ }
+
+ dstComparator.setCoords(latitudeIn, longitudeIn);
+ Collections.sort((List<cgCache>) list, dstComparator);
+ }
+ notifyDataSetChanged();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.setActualCoordinates: failed to sort caches in list");
+ }
+ }
+
+ public void setActualCoordinates(Double latitudeIn, Double longitudeIn) {
+ if (latitudeIn == null || longitudeIn == null) {
+ return;
+ }
+
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+
+ if (list != null && list.isEmpty() == false && (System.currentTimeMillis() - lastSort) > 1000 && sort == true) {
+ try {
+ if (statComparator != null) {
+ Collections.sort((List<cgCache>) list, statComparator);
+ } else {
+ dstComparator.setCoords(latitudeIn, longitudeIn);
+ Collections.sort((List<cgCache>) list, dstComparator);
+ }
+ notifyDataSetChanged();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.setActualCoordinates: failed to sort caches in list");
+ }
+
+ lastSort = System.currentTimeMillis();
+ }
+
+ if (distances != null && distances.size() > 0) {
+ for (cgDistanceView distance : distances) {
+ distance.update(latitudeIn, longitudeIn);
+ }
+ }
+
+ if (compasses != null && compasses.size() > 0) {
+ for (cgCompassMini compass : compasses) {
+ compass.updateCoords(latitudeIn, longitudeIn);
+ }
+ }
+ }
+
+ public void setActualHeading(Double azimuthIn) {
+ if (azimuthIn == null) {
+ return;
+ }
+
+ azimuth = azimuthIn;
+
+ if (compasses != null && compasses.size() > 0) {
+ for (cgCompassMini compass : compasses) {
+ compass.updateAzimuth(azimuth);
+ }
+ }
+ }
+
+ public boolean resetChecks() {
+ if (list.isEmpty() == true) {
+ return false;
+ }
+ if (checked <= 0) {
+ return false;
+ }
+
+ boolean status = getSelectMode();
+ int cleared = 0;
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ cache.statusChecked = false;
+
+ checkChecked(-1);
+ cleared++;
+ }
+ }
+ setSelectMode(false, false);
+ notifyDataSetChanged();
+
+ if (cleared > 0 || status == true) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public View getView(int position, View rowView, ViewGroup parent) {
+ if (inflater == null) {
+ inflater = ((Activity) getContext()).getLayoutInflater();
+ }
+
+ if (position > getCount()) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.getView: Attempt to access missing item #" + position);
+ return null;
+ }
+
+ cgCache cache = getItem(position);
+
+ if (rowView == null) {
+ rowView = (View) inflater.inflate(R.layout.cache, null);
+
+ holder = new cgCacheView();
+ holder.oneCache = (RelativeLayout) rowView.findViewById(R.id.one_cache);
+ holder.checkbox = (CheckBox) rowView.findViewById(R.id.checkbox);
+ holder.oneInfo = (RelativeLayout) rowView.findViewById(R.id.one_info);
+ holder.oneCheckbox = (RelativeLayout) rowView.findViewById(R.id.one_checkbox);
+ holder.foundMark = (ImageView) rowView.findViewById(R.id.found_mark);
+ holder.offlineMark = (ImageView) rowView.findViewById(R.id.offline_mark);
+ holder.oneCache = (RelativeLayout) rowView.findViewById(R.id.one_cache);
+ holder.text = (TextView) rowView.findViewById(R.id.text);
+ holder.directionLayout = (RelativeLayout) rowView.findViewById(R.id.direction_layout);
+ holder.distance = (cgDistanceView) rowView.findViewById(R.id.distance);
+ holder.direction = (cgCompassMini) rowView.findViewById(R.id.direction);
+ holder.dirImgLayout = (RelativeLayout) rowView.findViewById(R.id.dirimg_layout);
+ holder.dirImg = (ImageView) rowView.findViewById(R.id.dirimg);
+ holder.inventory = (RelativeLayout) rowView.findViewById(R.id.inventory);
+ holder.favourite = (TextView) rowView.findViewById(R.id.favourite);
+ holder.info = (TextView) rowView.findViewById(R.id.info);
+
+ rowView.setTag(holder);
+ } else {
+ holder = (cgCacheView) rowView.getTag();
+ }
+
+ if (cache.own == true) {
+ if (settings.skin == 1) {
+ holder.oneInfo.setBackgroundResource(R.color.owncache_background_light);
+ holder.oneCheckbox.setBackgroundResource(R.color.owncache_background_light);
+ } else {
+ holder.oneInfo.setBackgroundResource(R.color.owncache_background_dark);
+ holder.oneCheckbox.setBackgroundResource(R.color.owncache_background_dark);
+ }
+ } else {
+ if (settings.skin == 1) {
+ holder.oneInfo.setBackgroundResource(R.color.background_light);
+ holder.oneCheckbox.setBackgroundResource(R.color.background_light);
+ } else {
+ holder.oneInfo.setBackgroundResource(R.color.background_dark);
+ holder.oneCheckbox.setBackgroundResource(R.color.background_dark);
+ }
+ }
+
+ final touchListener touchLst = new touchListener(cache.geocode, cache.name, cache);
+ rowView.setOnClickListener(touchLst);
+ rowView.setOnLongClickListener(touchLst);
+ rowView.setOnTouchListener(touchLst);
+ rowView.setLongClickable(true);
+
+ if (selectMode == true) {
+ if (cache.statusCheckedView == true) {
+ moveRight(holder, cache, true); // move fast when already slided
+ } else {
+ moveRight(holder, cache, false);
+ }
+ } else if (cache.statusChecked == true) {
+ holder.checkbox.setChecked(true);
+ if (cache.statusCheckedView == true) {
+ moveRight(holder, cache, true); // move fast when already slided
+ } else {
+ moveRight(holder, cache, false);
+ }
+ } else {
+ holder.checkbox.setChecked(false);
+ if (cache.statusCheckedView == false) {
+ holder.oneInfo.clearAnimation();
+ } else {
+ moveLeft(holder, cache, false);
+ }
+ }
+
+ holder.checkbox.setOnClickListener(new checkBoxListener(cache));
+
+ if (distances.contains(holder.distance) == false) {
+ distances.add(holder.distance);
+ }
+ holder.distance.setContent(base, cache.latitude, cache.longitude);
+ if (compasses.contains(holder.direction) == false) {
+ compasses.add(holder.direction);
+ }
+ holder.direction.setContent(base, cache.latitude, cache.longitude);
+
+ if (cache.logOffline == true) {
+ holder.offlineMark.setVisibility(View.VISIBLE);
+ holder.foundMark.setVisibility(View.GONE);
+ } else if (cache.found == true) {
+ holder.offlineMark.setVisibility(View.GONE);
+ holder.foundMark.setVisibility(View.VISIBLE);
+ } else {
+ holder.offlineMark.setVisibility(View.GONE);
+ holder.foundMark.setVisibility(View.GONE);
+ }
+
+ if (cache.nameSp == null) {
+ cache.nameSp = (new Spannable.Factory()).newSpannable(cache.name);
+ if (cache.disabled == true || cache.archived == true) { // strike
+ cache.nameSp.setSpan(new StrikethroughSpan(), 0, cache.nameSp.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ holder.text.setText(cache.nameSp, TextView.BufferType.SPANNABLE);
+ if (gcIcons.containsKey(cache.type) == true) { // cache icon
+ holder.text.setCompoundDrawablesWithIntrinsicBounds(gcIcons.get(cache.type), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ holder.text.setCompoundDrawablesWithIntrinsicBounds(gcIcons.get("mystery"), null, null, null);
+ }
+
+ if (holder.inventory.getChildCount() > 0) {
+ holder.inventory.removeAllViews();
+ }
+
+ ImageView tbIcon = null;
+ if (cache.inventoryItems > 0) {
+ tbIcon = (ImageView) inflater.inflate(R.layout.trackable_icon, null);
+ tbIcon.setImageResource(R.drawable.trackable_all);
+
+ holder.inventory.addView(tbIcon);
+ holder.inventory.setVisibility(View.VISIBLE);
+ } else {
+ holder.inventory.setVisibility(View.GONE);
+ }
+
+ boolean setDiDi = false;
+ if (cache.latitude != null && cache.longitude != null) {
+ holder.direction.setVisibility(View.VISIBLE);
+ holder.direction.updateAzimuth(azimuth);
+ if (latitude != null && longitude != null) {
+ holder.distance.update(latitude, longitude);
+ holder.direction.updateCoords(latitude, longitude);
+ }
+ setDiDi = true;
+ } else {
+ if (cache.distance != null) {
+ holder.distance.setDistance(cache.distance);
+ setDiDi = true;
+ }
+ if (cache.direction != null) {
+ holder.direction.setVisibility(View.VISIBLE);
+ holder.direction.updateAzimuth(azimuth);
+ holder.direction.updateHeading(cache.direction);
+ setDiDi = true;
+ }
+ }
+
+ if (setDiDi == true) {
+ holder.directionLayout.setVisibility(View.VISIBLE);
+ holder.dirImgLayout.setVisibility(View.GONE);
+ } else {
+ holder.directionLayout.setVisibility(View.GONE);
+ holder.distance.clear();
+
+ Bitmap dirImgPre = null;
+ Bitmap dirImg = null;
+ try {
+ dirImgPre = BitmapFactory.decodeFile(settings.getStorage() + cache.geocode + "/direction.png");
+ dirImg = dirImgPre.copy(Bitmap.Config.ARGB_8888, true);
+
+ dirImgPre.recycle();
+ dirImgPre = null;
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (dirImg != null) {
+ if (settings.skin == 0) {
+ int length = dirImg.getWidth() * dirImg.getHeight();
+ int[] pixels = new int[length];
+ dirImg.getPixels(pixels, 0, dirImg.getWidth(), 0, 0, dirImg.getWidth(), dirImg.getHeight());
+ for (int i = 0; i < length; i++) {
+ if (pixels[i] == 0xff000000) { // replace black with white
+ pixels[i] = 0xffffffff;
+ }
+ }
+ dirImg.setPixels(pixels, 0, dirImg.getWidth(), 0, 0, dirImg.getWidth(), dirImg.getHeight());
+ }
+
+ holder.dirImg.setImageBitmap(dirImg);
+ holder.dirImgLayout.setVisibility(View.VISIBLE);
+ } else {
+ holder.dirImg.setImageBitmap(null);
+ holder.dirImgLayout.setVisibility(View.GONE);
+ }
+ }
+
+ if (cache.favouriteCnt != null) {
+ holder.favourite.setText(String.format("%d", cache.favouriteCnt));
+ } else {
+ holder.favourite.setText("---");
+ }
+
+ int favoriteBack;
+ // set default background, neither vote nor rating may be available
+ if (settings.skin == 1) {
+ favoriteBack = R.drawable.favourite_background_light;
+ } else {
+ favoriteBack = R.drawable.favourite_background_dark;
+ }
+ if (cache.myVote != null && cache.myVote > 0) {
+ if (cache.myVote >= 4) {
+ favoriteBack = ratingBcgs[2];
+ } else if (cache.myVote >= 3) {
+ favoriteBack = ratingBcgs[1];
+ } else if (cache.myVote > 0) {
+ favoriteBack = ratingBcgs[0];
+ }
+ } else if (cache.rating != null && cache.rating > 0) {
+ if (cache.rating >= 3.5) {
+ favoriteBack = ratingBcgs[2];
+ } else if (cache.rating >= 2.1) {
+ favoriteBack = ratingBcgs[1];
+ } else if (cache.rating > 0.0) {
+ favoriteBack = ratingBcgs[0];
+ }
+ }
+ holder.favourite.setBackgroundResource(favoriteBack);
+
+ StringBuilder cacheInfo = new StringBuilder();
+ if (historic == true && cache.visitedDate != null) {
+ cacheInfo.append(cgBase.timeOut.format(cache.visitedDate));
+ cacheInfo.append("; ");
+ cacheInfo.append(cgBase.dateOut.format(cache.visitedDate));
+ } else {
+ if (cache.geocode != null && cache.geocode.length() > 0) {
+ cacheInfo.append(cache.geocode);
+ }
+ if (cache.size != null && cache.size.length() > 0) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(cache.size);
+ }
+ if ((cache.difficulty != null && cache.difficulty > 0f) || (cache.terrain != null && cache.terrain > 0f) || (cache.rating != null && cache.rating > 0f)) {
+ if (cacheInfo.length() > 0 && ((cache.difficulty != null && cache.difficulty > 0f) || (cache.terrain != null && cache.terrain > 0f))) {
+ cacheInfo.append(" |");
+ }
+
+ if (cache.difficulty != null && cache.difficulty > 0f) {
+ cacheInfo.append(" D:");
+ cacheInfo.append(String.format(Locale.getDefault(), "%.1f", cache.difficulty));
+ }
+ if (cache.terrain != null && cache.terrain > 0f) {
+ cacheInfo.append(" T:");
+ cacheInfo.append(String.format(Locale.getDefault(), "%.1f", cache.terrain));
+ }
+ }
+ if (cache.members == true) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(res.getString(R.string.cache_premium));
+ }
+ if (cache.reason != null && cache.reason == 1) {
+ if (cacheInfo.length() > 0) {
+ cacheInfo.append(" | ");
+ }
+ cacheInfo.append(res.getString(R.string.cache_offline));
+ }
+ }
+ holder.info.setText(cacheInfo.toString());
+
+ return rowView;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+
+ checked = 0;
+ for (cgCache cache : list) {
+ if (cache.statusChecked == true) {
+ checked++;
+ }
+ }
+
+ distances.clear();
+ compasses.clear();
+ }
+
+ private class checkBoxListener implements View.OnClickListener {
+
+ private cgCache cache = null;
+
+ public checkBoxListener(cgCache cacheIn) {
+ cache = cacheIn;
+ }
+
+ public void onClick(View view) {
+ final boolean checkNow = ((CheckBox) view).isChecked();
+
+ if (checkNow == true) {
+ cache.statusChecked = true;
+ checked++;
+ } else {
+ cache.statusChecked = false;
+ checked--;
+ }
+ }
+ }
+
+ private class touchListener implements View.OnLongClickListener, View.OnClickListener, View.OnTouchListener {
+
+ private String geocode = null;
+ private String name = null;
+ private cgCache cache = null;
+ private boolean touch = true;
+ private GestureDetector gestureDetector = null;
+
+ public touchListener(String geocodeIn, String nameIn, cgCache cacheIn) {
+ geocode = geocodeIn;
+ name = nameIn;
+ cache = cacheIn;
+
+ final detectGesture dGesture = new detectGesture(holder, cache);
+ gestureDetector = new GestureDetector(dGesture);
+ }
+
+ // tap on item
+ public void onClick(View view) {
+ if (touch == false) {
+ touch = true;
+
+ return;
+ }
+
+ if (getSelectMode() == true || getChecked() > 0) {
+ return;
+ }
+
+ // load cache details
+ Intent cachesIntent = new Intent(getContext(), cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocode);
+ cachesIntent.putExtra("name", name);
+ getContext().startActivity(cachesIntent);
+ }
+
+ // long tap on item
+ public boolean onLongClick(View view) {
+ if (touch == false) {
+ touch = true;
+
+ return true;
+ }
+
+ return view.showContextMenu();
+ }
+
+ // swipe on item
+ public boolean onTouch(View view, MotionEvent event) {
+ if (gestureDetector.onTouchEvent(event) == true) {
+ touch = false;
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ class detectGesture extends GestureDetector.SimpleOnGestureListener {
+
+ private cgCacheView holder = null;
+ private cgCache cache = null;
+
+ public detectGesture(cgCacheView holderIn, cgCache cacheIn) {
+ holder = holderIn;
+ cache = cacheIn;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ try {
+ if (getSelectMode() == true) {
+ return false;
+ }
+
+ if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
+ return false;
+ }
+
+ if ((e2.getX() - e1.getX()) > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)) {
+ // left to right swipe
+ if (cache.statusChecked == true) {
+ return true;
+ }
+
+ if (holder != null && holder.oneInfo != null) {
+ checkChecked(+1);
+ holder.checkbox.setChecked(true);
+ cache.statusChecked = true;
+ moveRight(holder, cache, false);
+ }
+
+ return true;
+ } else if ((e1.getX() - e2.getX()) > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)) {
+ // right to left swipe
+ if (cache.statusChecked == false) {
+ return true;
+ }
+
+ if (holder != null && holder.oneInfo != null) {
+ if (getSelectMode() == true) {
+ setSelectMode(false, false);
+ }
+
+ checkChecked(-1);
+ holder.checkbox.setChecked(false);
+ cache.statusChecked = false;
+ moveLeft(holder, cache, false);
+ }
+
+ return true;
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgCacheListAdapter.detectGesture.onFling: " + e.toString());
+ }
+
+ return false;
+ }
+ }
+
+ private void checkChecked(int cnt) {
+ // check how many caches are selected, if any block sorting of list
+ boolean statusChecked = false;
+ boolean statusSort = false;
+ checked += cnt;
+
+ if (checked > 0) {
+ statusChecked = false;
+ } else {
+ statusChecked = true;
+ }
+
+ if (getSelectMode() == true) {
+ statusSort = false;
+ } else {
+ statusSort = true;
+ }
+
+ if (statusChecked == false || statusSort == false) {
+ sort = false;
+ } else {
+ sort = true;
+ }
+
+ if (sort == true) {
+ forceSort(latitude, longitude);
+ }
+ }
+
+ private void moveRight(cgCacheView holder, cgCache cache, boolean force) {
+ if (cache == null) {
+ return;
+ }
+
+ try {
+ holder.checkbox.setChecked(cache.statusChecked);
+
+ // slide cache info
+ Animation showCheckbox = new TranslateAnimation(0, (int) (SWIPE_DISTANCE * pixelDensity), 0, 0);
+ showCheckbox.setRepeatCount(0);
+ if (force == true) {
+ showCheckbox.setDuration(0);
+ } else {
+ showCheckbox.setDuration(400);
+ }
+ showCheckbox.setFillEnabled(true);
+ showCheckbox.setFillAfter(true);
+ showCheckbox.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // dim cache info
+ Animation dimInfo = new AlphaAnimation(1.0f, SWIPE_OPACITY);
+ dimInfo.setRepeatCount(0);
+ if (force == true) {
+ dimInfo.setDuration(0);
+ } else {
+ dimInfo.setDuration(400);
+ }
+ dimInfo.setFillEnabled(true);
+ dimInfo.setFillAfter(true);
+ dimInfo.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // animation set (container)
+ AnimationSet selectAnimation = new AnimationSet(true);
+ selectAnimation.setFillEnabled(true);
+ selectAnimation.setFillAfter(true);
+
+ selectAnimation.addAnimation(showCheckbox);
+ selectAnimation.addAnimation(dimInfo);
+
+ holder.oneInfo.startAnimation(selectAnimation);
+ cache.statusCheckedView = true;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private void moveLeft(cgCacheView holder, cgCache cache, boolean force) {
+ if (cache == null) {
+ return;
+ }
+
+ try {
+ holder.checkbox.setChecked(cache.statusChecked);
+
+ // slide cache info
+ Animation hideCheckbox = new TranslateAnimation((int) (SWIPE_DISTANCE * pixelDensity), 0, 0, 0);
+ hideCheckbox.setRepeatCount(0);
+ if (force == true) {
+ hideCheckbox.setDuration(0);
+ } else {
+ hideCheckbox.setDuration(400);
+ }
+ hideCheckbox.setFillEnabled(true);
+ hideCheckbox.setFillAfter(true);
+ hideCheckbox.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // brighten cache info
+ Animation brightenInfo = new AlphaAnimation(SWIPE_OPACITY, 1.0f);
+ brightenInfo.setRepeatCount(0);
+ if (force == true) {
+ brightenInfo.setDuration(0);
+ } else {
+ brightenInfo.setDuration(400);
+ }
+ brightenInfo.setFillEnabled(true);
+ brightenInfo.setFillAfter(true);
+ brightenInfo.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // animation set (container)
+ AnimationSet selectAnimation = new AnimationSet(true);
+ selectAnimation.setFillEnabled(true);
+ selectAnimation.setFillAfter(true);
+
+ selectAnimation.addAnimation(hideCheckbox);
+ selectAnimation.addAnimation(brightenInfo);
+
+ holder.oneInfo.startAnimation(selectAnimation);
+ cache.statusCheckedView = false;
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheNameComparator.java b/src/cgeo/geocaching/cgCacheNameComparator.java
new file mode 100644
index 0000000..fa247fa
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheNameComparator.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheNameComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.name == null || cache2.name == null) {
+ return 0;
+ }
+
+ return cache1.name.compareToIgnoreCase(cache2.name);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheNameComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCachePopularityComparator.java b/src/cgeo/geocaching/cgCachePopularityComparator.java
new file mode 100644
index 0000000..10500f9
--- /dev/null
+++ b/src/cgeo/geocaching/cgCachePopularityComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCachePopularityComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.favouriteCnt == null || cache2.favouriteCnt == null) {
+ return 0;
+ }
+
+ if (cache1.favouriteCnt < cache2.favouriteCnt) {
+ return 1;
+ } else if (cache2.favouriteCnt < cache1.favouriteCnt) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCachePopularityComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheRatingComparator.java b/src/cgeo/geocaching/cgCacheRatingComparator.java
new file mode 100644
index 0000000..b7b9720
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheRatingComparator.java
@@ -0,0 +1,36 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheRatingComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ Float rating1 = cache1.rating;
+ Float rating2 = cache2.rating;
+ if (rating1 == null || rating2 == null) {
+ return 0;
+ }
+
+ // voting can be disabled for caches, then assume an average rating instead
+ if (rating1 == 0.0) {
+ rating1 = 2.5f;
+ }
+ if (rating2 == 0.0) {
+ rating2 = 2.5f;
+ }
+
+ if (rating1 < rating2) {
+ return 1;
+ } else if (rating2 < rating1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheRatingComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheSizeComparator.java b/src/cgeo/geocaching/cgCacheSizeComparator.java
new file mode 100644
index 0000000..a5d0298
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheSizeComparator.java
@@ -0,0 +1,47 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+import java.util.ArrayList;
+
+public class cgCacheSizeComparator implements Comparator<cgCache> {
+ public static ArrayList<String> cacheSizes = new ArrayList<String>();
+
+ public cgCacheSizeComparator() {
+ // list sizes
+ cacheSizes.add("micro");
+ cacheSizes.add("small");
+ cacheSizes.add("regular");
+ cacheSizes.add("large");
+ }
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.size == null || cache1.size.length() == 0 || cache2.size == null || cache2.size.length() == 0) {
+ return 0;
+ }
+
+ int size1 = 0;
+ int size2 = 0;
+
+ int cnt = 1;
+ for (String size : cacheSizes) {
+ if (size.equalsIgnoreCase(cache1.size)) size1 = cnt;
+ if (size.equalsIgnoreCase(cache2.size)) size2 = cnt;
+
+ cnt ++;
+ }
+
+ if (size1 < size2) {
+ return 1;
+ } else if (size2 < size1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheSizeComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheTerrainComparator.java b/src/cgeo/geocaching/cgCacheTerrainComparator.java
new file mode 100644
index 0000000..3d31a37
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheTerrainComparator.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheTerrainComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.terrain == null || cache2.terrain == null) {
+ return 0;
+ }
+
+ if (cache1.terrain > cache2.terrain) {
+ return 1;
+ } else if (cache2.terrain > cache1.terrain) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheTerrainComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheView.java b/src/cgeo/geocaching/cgCacheView.java
new file mode 100644
index 0000000..6705729
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheView.java
@@ -0,0 +1,29 @@
+package cgeo.geocaching;
+
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+public class cgCacheView {
+ // layouts & views
+ public RelativeLayout oneCache;
+ public RelativeLayout oneInfo;
+ public RelativeLayout oneCheckbox;
+ public CheckBox checkbox;
+ public ImageView foundMark;
+ public ImageView offlineMark;
+ public TextView text;
+ public TextView favourite;
+ public TextView info;
+ public RelativeLayout inventory;
+ public RelativeLayout directionLayout;
+ public cgDistanceView distance;
+ public cgCompassMini direction;
+ public RelativeLayout dirImgLayout;
+ public ImageView dirImg;
+
+ // status
+ public float startX = -1;
+ public float prevX = -1;
+}
diff --git a/src/cgeo/geocaching/cgCacheVisitComparator.java b/src/cgeo/geocaching/cgCacheVisitComparator.java
new file mode 100644
index 0000000..19a4b52
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheVisitComparator.java
@@ -0,0 +1,27 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+public class cgCacheVisitComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ if (cache1.visitedDate == null || cache1.visitedDate <= 0 || cache2.visitedDate == null || cache2.visitedDate <= 0) {
+ return 0;
+ }
+
+ if (cache1.visitedDate > cache2.visitedDate) {
+ return -1;
+ } else if (cache1.visitedDate < cache2.visitedDate) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheVisitComparator.compare: " + e.toString());
+ }
+
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheVoteComparator.java b/src/cgeo/geocaching/cgCacheVoteComparator.java
new file mode 100644
index 0000000..581656c
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheVoteComparator.java
@@ -0,0 +1,38 @@
+package cgeo.geocaching;
+
+import java.util.Comparator;
+import android.util.Log;
+
+/**
+ * sorts caches by the users own voting (if available at all)
+ * @author bananeweizen
+ *
+ */
+public class cgCacheVoteComparator implements Comparator<cgCache> {
+
+ public int compare(cgCache cache1, cgCache cache2) {
+ try {
+ // if there is no vote available, put that cache at the end of the list
+ float vote1 = 0;
+ if (cache1.myVote != null) {
+ vote1 = cache1.myVote;
+ }
+
+ float vote2 = 0;
+ if (cache2.myVote != null) {
+ vote2 = cache2.myVote;
+ }
+
+ if (vote1 < vote2) {
+ return 1;
+ } else if (vote2 < vote1) {
+ return -1;
+ } else {
+ return 0;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCacheVoteComparator.compare: " + e.toString());
+ }
+ return 0;
+ }
+}
diff --git a/src/cgeo/geocaching/cgCacheWrap.java b/src/cgeo/geocaching/cgCacheWrap.java
new file mode 100644
index 0000000..23d77f5
--- /dev/null
+++ b/src/cgeo/geocaching/cgCacheWrap.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+public class cgCacheWrap {
+ public String error = null;
+ public String url = "";
+ public String viewstate = "";
+ public String viewstate1 = "";
+ public int totalCnt = 0;
+ public ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCompass.java b/src/cgeo/geocaching/cgCompass.java
new file mode 100644
index 0000000..9d4473e
--- /dev/null
+++ b/src/cgeo/geocaching/cgCompass.java
@@ -0,0 +1,322 @@
+package cgeo.geocaching;
+
+import android.util.AttributeSet;
+import android.view.View;
+import android.content.Context;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Canvas;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class cgCompass extends View {
+
+ private changeThread watchdog = null;
+ private boolean wantStop = false;
+ private boolean lock = false;
+ private boolean drawing = false;
+ private Context context = null;
+ private Bitmap compassUnderlay = null;
+ private Bitmap compassRose = null;
+ private Bitmap compassArrow = null;
+ private Bitmap compassOverlay = null;
+ private Double azimuth = new Double(0);
+ private Double heading = new Double(0);
+ private Double cacheHeading = new Double(0);
+ private Double northHeading = new Double(0);
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private int compassUnderlayWidth = 0;
+ private int compassUnderlayHeight = 0;
+ private int compassRoseWidth = 0;
+ private int compassRoseHeight = 0;
+ private int compassArrowWidth = 0;
+ private int compassArrowHeight = 0;
+ private int compassOverlayWidth = 0;
+ private int compassOverlayHeight = 0;
+ private Handler changeHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message message) {
+ try {
+ invalidate();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgCompass.changeHandler: " + e.toString());
+ }
+ }
+ };
+
+ public cgCompass(Context contextIn) {
+ super(contextIn);
+ context = contextIn;
+ }
+
+ public cgCompass(Context contextIn, AttributeSet attrs) {
+ super(contextIn, attrs);
+ context = contextIn;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ compassUnderlay = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_underlay);
+ compassRose = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_rose);
+ compassArrow = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_arrow);
+ compassOverlay = BitmapFactory.decodeResource(context.getResources(), R.drawable.compass_overlay);
+
+ compassUnderlayWidth = compassUnderlay.getWidth();
+ compassUnderlayHeight = compassUnderlay.getWidth();
+ compassRoseWidth = compassRose.getWidth();
+ compassRoseHeight = compassRose.getWidth();
+ compassArrowWidth = compassArrow.getWidth();
+ compassArrowHeight = compassArrow.getWidth();
+ compassOverlayWidth = compassOverlay.getWidth();
+ compassOverlayHeight = compassOverlay.getWidth();
+
+ setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ wantStop = false;
+
+ watchdog = new changeThread(changeHandler);
+ watchdog.start();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ wantStop = true;
+
+ if (compassUnderlay != null) {
+ compassUnderlay.recycle();
+ }
+
+ if (compassRose != null) {
+ compassRose.recycle();
+ }
+
+ if (compassArrow != null) {
+ compassArrow.recycle();
+ }
+
+ if (compassOverlay != null) {
+ compassOverlay.recycle();
+ }
+ }
+
+ protected void updateNorth(Double northHeadingIn, Double cacheHeadingIn) {
+ northHeading = northHeadingIn;
+ cacheHeading = cacheHeadingIn;
+ }
+
+ private class changeThread extends Thread {
+
+ Handler handler = null;
+
+ public changeThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ while (wantStop == false) {
+ try {
+ sleep(50);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (Math.abs(azimuth - northHeading) < 2 && Math.abs(heading - cacheHeading) < 2) {
+ continue;
+ }
+
+ lock = true;
+
+ Double diff = new Double(0);
+ Double diffAbs = new Double(0);
+ Double tempAzimuth = new Double(0);
+ Double tempHeading = new Double(0);
+
+ Double actualAzimuth = azimuth;
+ Double actualHeading = heading;
+
+ diff = northHeading - actualAzimuth;
+ diffAbs = Math.abs(northHeading - actualAzimuth);
+ if (diff < 0) {
+ diff = diff + 360;
+ } else if (diff >= 360) {
+ diff = diff - 360;
+ }
+
+ if (diff > 0 && diff <= 180) {
+ if (diffAbs > 5) {
+ tempAzimuth = actualAzimuth + 2;
+ } else if (diffAbs > 1) {
+ tempAzimuth = actualAzimuth + 1;
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+ } else if (diff > 180 && diff < 360) {
+ if (diffAbs > 5) {
+ tempAzimuth = actualAzimuth - 2;
+ } else if (diffAbs > 1) {
+ tempAzimuth = actualAzimuth - 1;
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+ } else {
+ tempAzimuth = actualAzimuth;
+ }
+
+ diff = cacheHeading - actualHeading;
+ diffAbs = Math.abs(cacheHeading - actualHeading);
+ if (diff < 0) {
+ diff = diff + 360;
+ } else if (diff >= 360) {
+ diff = diff - 360;
+ }
+
+ if (diff > 0 && diff <= 180) {
+ if (diffAbs > 5) {
+ tempHeading = actualHeading + 2;
+ } else if (diffAbs > 1) {
+ tempHeading = actualHeading + 1;
+ } else {
+ tempHeading = actualHeading;
+ }
+ } else if (diff > 180 && diff < 360) {
+ if (diffAbs > 5) {
+ tempHeading = actualHeading - 2;
+ } else if (diffAbs > 1) {
+ tempHeading = actualHeading - 1;
+ } else {
+ tempHeading = actualHeading;
+ }
+ } else {
+ tempHeading = actualHeading;
+ }
+
+ if (tempAzimuth >= 360) {
+ tempAzimuth = tempAzimuth - 360;
+ } else if (tempAzimuth < 0) {
+ tempAzimuth = tempAzimuth + 360;
+ }
+
+ if (tempHeading >= 360) {
+ tempHeading = tempHeading - 360;
+ } else if (tempHeading < 0) {
+ tempHeading = tempHeading + 360;
+ }
+
+ azimuth = tempAzimuth;
+ heading = tempHeading;
+
+ lock = false;
+
+ changeHandler.sendMessage(new Message());
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (lock == true) {
+ return;
+ }
+ if (drawing == true) {
+ return;
+ }
+
+ Double azimuthTemp = azimuth;
+ Double azimuthRelative = azimuthTemp - heading;
+ if (azimuthRelative < 0) {
+ azimuthRelative = azimuthRelative + 360;
+ } else if (azimuthRelative >= 360) {
+ azimuthRelative = azimuthRelative - 360;
+ }
+
+ // compass margins
+ int canvasCenterX = (compassRoseWidth / 2) + ((getWidth() - compassRoseWidth) / 2);
+ int canvasCenterY = (compassRoseHeight / 2) + ((getHeight() - compassRoseHeight) / 2);
+
+ int marginLeftTemp = 0;
+ int marginTopTemp = 0;
+
+ drawing = true;
+ super.onDraw(canvas);
+
+ canvas.save();
+ canvas.setDrawFilter(setfil);
+
+ marginLeftTemp = (getWidth() - compassUnderlayWidth) / 2;
+ marginTopTemp = (getHeight() - compassUnderlayHeight) / 2;
+
+ canvas.drawBitmap(compassUnderlay, marginLeftTemp, marginTopTemp, null);
+
+ marginLeftTemp = (getWidth() - compassRoseWidth) / 2;
+ marginTopTemp = (getHeight() - compassRoseHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthTemp)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassRose, marginLeftTemp, marginTopTemp, null);
+ canvas.rotate(new Float(azimuthTemp), canvasCenterX, canvasCenterY);
+
+ marginLeftTemp = (getWidth() - compassArrowWidth) / 2;
+ marginTopTemp = (getHeight() - compassArrowHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthRelative)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassArrow, marginLeftTemp, marginTopTemp, null);
+ canvas.rotate(new Float(azimuthRelative), canvasCenterX, canvasCenterY);
+
+ marginLeftTemp = (getWidth() - compassOverlayWidth) / 2;
+ marginTopTemp = (getHeight() - compassOverlayHeight) / 2;
+
+ canvas.drawBitmap(compassOverlay, marginLeftTemp, marginTopTemp, null);
+
+ canvas.setDrawFilter(remfil);
+ canvas.restore();
+
+ drawing = false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
+ }
+
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = compassArrow.getWidth() + getPaddingLeft() + getPaddingRight();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = compassArrow.getHeight() + getPaddingTop() + getPaddingBottom();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCompassMini.java b/src/cgeo/geocaching/cgCompassMini.java
new file mode 100644
index 0000000..cc815bf
--- /dev/null
+++ b/src/cgeo/geocaching/cgCompassMini.java
@@ -0,0 +1,176 @@
+package cgeo.geocaching;
+
+import android.util.AttributeSet;
+import android.view.View;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Canvas;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+public class cgCompassMini extends View {
+ private int arrowSkin = R.drawable.compass_arrow_mini_white;
+ private Boolean lock = false;
+ private Context context = null;
+ private cgBase base = null;
+ private Double cacheLat = null;
+ private Double cacheLon = null;
+ private Bitmap compassArrow = null;
+ private Double azimuth = new Double(0);
+ private Double heading = new Double(0);
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+
+ public cgCompassMini(Context contextIn) {
+ super(contextIn);
+ context = contextIn;
+ }
+
+ public cgCompassMini(Context contextIn, AttributeSet attrs) {
+ super(contextIn, attrs);
+ context = contextIn;
+
+ TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.cgCompassMini);
+ int usedSkin = attributes.getInt(R.styleable.cgCompassMini_skin, 0);
+ if (usedSkin == 1) arrowSkin = R.drawable.compass_arrow_mini_black;
+ else arrowSkin = R.drawable.compass_arrow_mini_white;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ compassArrow = BitmapFactory.decodeResource(context.getResources(), arrowSkin);
+
+ setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ if (compassArrow != null) {
+ compassArrow.recycle();
+ compassArrow = null;
+ }
+ }
+
+ public void setContent(cgBase baseIn, Double cacheLatIn, Double cacheLonIn) {
+ base = baseIn;
+ cacheLat = cacheLatIn;
+ cacheLon = cacheLonIn;
+ }
+
+ protected void updateAzimuth(Double azimuthIn) {
+ azimuth = azimuthIn;
+
+ updateDirection();
+ }
+
+ protected void updateHeading(Double headingIn) {
+ heading = headingIn;
+
+ updateDirection();
+ }
+
+ protected void updateCoords(Double latitudeIn, Double longitudeIn) {
+ if (latitudeIn == null || longitudeIn == null || cacheLat == null || cacheLon == null) {
+ return;
+ }
+
+ heading = cgBase.getHeading(latitudeIn, longitudeIn, cacheLat, cacheLon);
+
+ updateDirection();
+ }
+
+ protected void updateDirection() {
+ if (compassArrow == null || compassArrow.isRecycled() == true) {
+ return;
+ }
+
+ // compass margins
+ int compassRoseWidth = compassArrow.getWidth();
+ int compassRoseHeight = compassArrow.getWidth();
+ int marginLeft = (getWidth() - compassRoseWidth) / 2;
+ int marginTop = (getHeight() - compassRoseHeight) / 2;
+
+ invalidate(marginLeft, marginTop, (marginLeft + compassRoseWidth), (marginTop + compassRoseHeight));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas){
+ lock = true;
+
+ super.onDraw(canvas);
+
+ Double azimuthRelative = azimuth - heading;
+ if (azimuthRelative < 0) {
+ azimuthRelative = azimuthRelative + 360;
+ } else if (azimuthRelative >= 360) {
+ azimuthRelative = azimuthRelative - 360;
+ }
+
+ // compass margins
+ canvas.setDrawFilter(setfil);
+
+ int marginLeft = 0;
+ int marginTop = 0;
+
+ int compassArrowWidth = compassArrow.getWidth();
+ int compassArrowHeight = compassArrow.getWidth();
+
+ int canvasCenterX = (compassArrowWidth / 2) + ((getWidth() - compassArrowWidth) / 2);
+ int canvasCenterY = (compassArrowHeight / 2) + ((getHeight() - compassArrowHeight) / 2);
+
+ marginLeft = (getWidth() - compassArrowWidth) / 2;
+ marginTop = (getHeight() - compassArrowHeight) / 2;
+
+ canvas.rotate(new Float(-(azimuthRelative)), canvasCenterX, canvasCenterY);
+ canvas.drawBitmap(compassArrow, marginLeft, marginTop, null);
+ canvas.rotate(new Float(azimuthRelative), canvasCenterX, canvasCenterY);
+
+ canvas.setDrawFilter(remfil);
+
+ lock = false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
+ }
+
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = 21 + getPaddingLeft() + getPaddingRight();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ } else {
+ result = 21 + getPaddingTop() + getPaddingBottom();
+
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgCoord.java b/src/cgeo/geocaching/cgCoord.java
new file mode 100644
index 0000000..4e7d3b2
--- /dev/null
+++ b/src/cgeo/geocaching/cgCoord.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching;
+
+public class cgCoord {
+
+ public Integer id = null;
+ public String geocode = "";
+ public String type = "cache";
+ public String typeSpec = "traditional";
+ public String name = "";
+ public boolean found = false;
+ public boolean disabled = false;
+ public Double latitude = new Double(0);
+ public Double longitude = new Double(0);
+ public Float difficulty = null;
+ public Float terrain = null;
+ public String size = null;
+
+ public cgCoord() {
+ }
+
+ public cgCoord(cgCache cache) {
+ disabled = cache.disabled;
+ found = cache.found;
+ geocode = cache.geocode;
+ latitude = cache.latitude;
+ longitude = cache.longitude;
+ name = cache.name;
+ type = "cache";
+ typeSpec = cache.type;
+ difficulty = cache.difficulty;
+ terrain = cache.terrain;
+ size = cache.size;
+ }
+
+ public cgCoord(cgWaypoint waypoint) {
+ id = waypoint.id;
+ disabled = false;
+ found = false;
+ geocode = "";
+ latitude = waypoint.latitude;
+ longitude = waypoint.longitude;
+ name = waypoint.name;
+ type = "waypoint";
+ typeSpec = waypoint.type;
+ }
+}
diff --git a/src/cgeo/geocaching/cgData.java b/src/cgeo/geocaching/cgData.java
new file mode 100644
index 0000000..0338cf7
--- /dev/null
+++ b/src/cgeo/geocaching/cgData.java
@@ -0,0 +1,3046 @@
+package cgeo.geocaching;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.util.Log;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteStatement;
+import android.os.Environment;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class cgData {
+
+ public cgCacheWrap caches;
+ private Context context = null;
+ private String path = null;
+ private cgDbHelper dbHelper = null;
+ private SQLiteDatabase databaseRO = null;
+ private SQLiteDatabase databaseRW = null;
+ private static final int dbVersion = 51;
+ private static final String dbName = "data";
+ private static final String dbTableCaches = "cg_caches";
+ private static final String dbTableLists = "cg_lists";
+ private static final String dbTableAttributes = "cg_attributes";
+ private static final String dbTableWaypoints = "cg_waypoints";
+ private static final String dbTableSpoilers = "cg_spoilers";
+ private static final String dbTableLogs = "cg_logs";
+ private static final String dbTableLogCount = "cg_logCount";
+ private static final String dbTableLogsOffline = "cg_logs_offline";
+ private static final String dbTableTrackables = "cg_trackables";
+ private static final String dbCreateCaches = ""
+ + "create table " + dbTableCaches + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "visiteddate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "own integer not null default 0, "
+ + "owner text, "
+ + "owner_real text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "direction double, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "reliable_latlon integer, "
+ + "elevation double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "favourite_cnt integer, "
+ + "rating float, "
+ + "votes integer, "
+ + "myvote float, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+ private static final String dbCreateLists = ""
+ + "create table " + dbTableLists + " ("
+ + "_id integer primary key autoincrement, "
+ + "title text not null, "
+ + "updated long not null, "
+ + "latitude double, "
+ + "longitude double "
+ + "); ";
+ private static final String dbCreateAttributes = ""
+ + "create table " + dbTableAttributes + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "attribute text "
+ + "); ";
+ private static final String dbCreateWaypoints = ""
+ + "create table " + dbTableWaypoints + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type text not null default 'waypoint', "
+ + "prefix text, "
+ + "lookup text, "
+ + "name text, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "latitude double, "
+ + "longitude double, "
+ + "note text "
+ + "); ";
+ private static final String dbCreateSpoilers = ""
+ + "create table " + dbTableSpoilers + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "url text, "
+ + "title text, "
+ + "description text "
+ + "); ";
+ private static final String dbCreateLogs = ""
+ + "create table " + dbTableLogs + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "author text, "
+ + "log text, "
+ + "date long, "
+ + "found integer not null default 0 "
+ + "); ";
+ private static final String dbCreateLogCount = ""
+ + "create table " + dbTableLogCount + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "count integer not null default 0 "
+ + "); ";
+ private static final String dbCreateLogsOffline = ""
+ + "create table " + dbTableLogsOffline + " ("
+ + "_id integer primary key autoincrement, "
+ + "geocode text not null, "
+ + "updated long not null, " // date of save
+ + "type integer not null default 4, "
+ + "log text, "
+ + "date long "
+ + "); ";
+ private static final String dbCreateTrackables = ""
+ + "create table " + dbTableTrackables + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, " // date of save
+ + "tbcode text not null, "
+ + "guid text, "
+ + "title text, "
+ + "owner text, "
+ + "released long, "
+ + "goal text, "
+ + "description text, "
+ + "geocode text "
+ + "); ";
+ public boolean initialized = false;
+
+ public cgData(Context contextIn) {
+ context = contextIn;
+ }
+
+ public void init() {
+ if (databaseRW == null || databaseRW.isOpen() == false) {
+ try {
+ if (dbHelper == null) {
+ dbHelper = new cgDbHelper(context);
+ }
+ databaseRW = dbHelper.getWritableDatabase();
+
+ if (databaseRW != null && databaseRW.isOpen()) {
+ Log.i(cgSettings.tag, "Connection to RW database established.");
+ } else {
+ Log.e(cgSettings.tag, "Failed to open connection to RW database.");
+ }
+
+ if (databaseRW.inTransaction() == true) {
+ databaseRW.endTransaction();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.openDb.RW: " + e.toString());
+ }
+ }
+
+ if (databaseRO == null || databaseRO.isOpen() == false) {
+ try {
+ if (dbHelper == null) {
+ dbHelper = new cgDbHelper(context);
+ }
+ databaseRO = dbHelper.getReadableDatabase();
+
+ if (databaseRO.needUpgrade(dbVersion) == true) {
+ databaseRO = null;
+ }
+
+ if (databaseRO != null && databaseRO.isOpen()) {
+ Log.i(cgSettings.tag, "Connection to RO database established.");
+ } else {
+ Log.e(cgSettings.tag, "Failed to open connection to RO database.");
+ }
+
+ if (databaseRO.inTransaction() == true) {
+ databaseRO.endTransaction();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.openDb.RO: " + e.toString());
+ }
+ }
+
+ initialized = true;
+ }
+
+ public void closeDb() {
+ if (databaseRO != null) {
+ path = databaseRO.getPath();
+
+ if (databaseRO.inTransaction() == true) {
+ databaseRO.endTransaction();
+ }
+
+ databaseRO.close();
+ databaseRO = null;
+ SQLiteDatabase.releaseMemory();
+
+ Log.d(cgSettings.tag, "Closing RO database");
+ }
+
+ if (databaseRW != null) {
+ path = databaseRW.getPath();
+
+ if (databaseRW.inTransaction() == true) {
+ databaseRW.endTransaction();
+ }
+
+ databaseRW.close();
+ databaseRW = null;
+ SQLiteDatabase.releaseMemory();
+
+ Log.d(cgSettings.tag, "Closing RW database");
+ }
+
+ if (dbHelper != null) {
+ dbHelper.close();
+ dbHelper = null;
+ }
+ }
+
+ public String backupDatabase() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) {
+ Log.w(cgSettings.tag, "Database wasn't backed up: no external memory");
+
+ return null;
+ }
+
+ closeDb();
+
+ try {
+ final String directoryImg = cgSettings.cache;
+ final String directoryTarget = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/";
+ final String fileTarget = directoryTarget + "cgeo.sqlite";
+ final String fileSource = path;
+
+ File directoryTargetFile = new File(directoryTarget);
+ if (directoryTargetFile.exists() == false) {
+ directoryTargetFile.mkdir();
+ }
+
+ InputStream input = new FileInputStream(fileSource);
+ OutputStream output = new FileOutputStream(fileTarget);
+
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = input.read(buffer)) > 0) {
+ output.write(buffer, 0, length);
+ }
+
+ output.flush();
+ output.close();
+ input.close();
+
+ Log.i(cgSettings.tag, "Database was copied to " + fileTarget);
+
+ init();
+
+ return fileTarget;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Database wasn't backed up: " + e.toString());
+ }
+
+ init();
+
+ return null;
+ }
+
+ public File isRestoreFile() {
+ final String directoryImg = cgSettings.cache;
+ final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite";
+
+ File fileSourceFile = new File(fileSource);
+ if (fileSourceFile.exists()) {
+ return fileSourceFile;
+ } else {
+ return null;
+ }
+ }
+
+ public boolean restoreDatabase() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == false) {
+ Log.w(cgSettings.tag, "Database wasn't restored: no external memory");
+
+ return false;
+ }
+
+ closeDb();
+
+ try {
+ final String directoryImg = cgSettings.cache;
+ final String fileSource = Environment.getExternalStorageDirectory() + "/" + directoryImg + "/cgeo.sqlite";
+ final String fileTarget = path;
+
+ File fileSourceFile = new File(fileSource);
+ if (fileSourceFile.exists() == false) {
+ Log.w(cgSettings.tag, "Database backup was not found");
+
+ init();
+
+ return false;
+ }
+
+ InputStream input = new FileInputStream(fileSource);
+ OutputStream output = new FileOutputStream(fileTarget);
+
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = input.read(buffer)) > 0) {
+ output.write(buffer, 0, length);
+ }
+
+ output.flush();
+ output.close();
+ input.close();
+
+ Log.i(cgSettings.tag, "Database was restored");
+
+ init();
+
+ return true;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Database wasn't restored: " + e.toString());
+ }
+
+ init();
+
+ return false;
+ }
+
+ private class cgDbHelper extends SQLiteOpenHelper {
+
+ cgDbHelper(Context context) {
+ super(context, dbName, null, dbVersion);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(dbCreateCaches);
+ db.execSQL(dbCreateLists);
+ db.execSQL(dbCreateAttributes);
+ db.execSQL(dbCreateWaypoints);
+ db.execSQL(dbCreateSpoilers);
+ db.execSQL(dbCreateLogs);
+ db.execSQL(dbCreateLogCount);
+ db.execSQL(dbCreateLogsOffline);
+ db.execSQL(dbCreateTrackables);
+
+ db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)");
+ db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)");
+ db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)");
+ db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)");
+ db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)");
+ db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)");
+ db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogCount + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogsOffline + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.i(cgSettings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": start");
+
+ try {
+ if (db.isReadOnly() == true) {
+ return;
+ }
+
+ db.beginTransaction();
+
+ if (oldVersion <= 0) { // new table
+ dropDatabase(db);
+ onCreate(db);
+
+ Log.i(cgSettings.tag, "Database structure created.");
+ }
+
+ if (oldVersion > 0) {
+ db.execSQL("delete from " + dbTableCaches + " where reason = 0");
+
+ if (oldVersion < 34) { // upgrade to 34
+ try {
+ db.execSQL("create index if not exists in_a on " + dbTableCaches + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableCaches + " (guid)");
+ db.execSQL("create index if not exists in_c on " + dbTableCaches + " (reason)");
+ db.execSQL("create index if not exists in_d on " + dbTableCaches + " (detailed)");
+ db.execSQL("create index if not exists in_e on " + dbTableCaches + " (type)");
+ db.execSQL("create index if not exists in_a on " + dbTableAttributes + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableWaypoints + " (geocode)");
+ db.execSQL("create index if not exists in_b on " + dbTableWaypoints + " (geocode, type)");
+ db.execSQL("create index if not exists in_a on " + dbTableSpoilers + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableLogs + " (geocode)");
+ db.execSQL("create index if not exists in_a on " + dbTableTrackables + " (geocode)");
+
+ Log.i(cgSettings.tag, "Indexes added.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 34: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 37) { // upgrade to 37
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column direction text");
+ db.execSQL("alter table " + dbTableCaches + " add column distance double");
+
+ Log.i(cgSettings.tag, "Columns direction and distance added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 37: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 38) { // upgrade to 38
+ try {
+ db.execSQL("drop table " + dbTableLogs);
+ db.execSQL(dbCreateLogs);
+
+ Log.i(cgSettings.tag, "Changed type column in " + dbTableLogs + " to integer.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 38: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 39) { // upgrade to 39
+ try {
+ db.execSQL(dbCreateLists);
+
+ Log.i(cgSettings.tag, "Created lists table.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 39: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 40) { // upgrade to 40
+ try {
+ db.execSQL("drop table " + dbTableTrackables);
+ db.execSQL(dbCreateTrackables);
+
+ Log.i(cgSettings.tag, "Changed type of geocode column in trackables table.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 40: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 41) { // upgrade to 41
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column rating float");
+ db.execSQL("alter table " + dbTableCaches + " add column votes integer");
+ db.execSQL("alter table " + dbTableCaches + " add column vote integer");
+
+ Log.i(cgSettings.tag, "Added columns for GCvote.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 41: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 42) { // upgrade to 42
+ try {
+ db.execSQL(dbCreateLogsOffline);
+
+ Log.i(cgSettings.tag, "Added table for offline logs");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 42: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 43) { // upgrade to 43
+ try {
+ final String dbCreateCachesTemp = ""
+ + "create temporary table " + dbTableCaches + "_temp ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "owner text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "rating float, "
+ + "votes integer, "
+ + "vote integer, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+ final String dbCreateCachesNew = ""
+ + "create table " + dbTableCaches + " ("
+ + "_id integer primary key autoincrement, "
+ + "updated long not null, "
+ + "detailed integer not null default 0, "
+ + "detailedupdate long, "
+ + "geocode text unique not null, "
+ + "reason integer not null default 0, " // cached, favourite...
+ + "cacheid text, "
+ + "guid text, "
+ + "type text, "
+ + "name text, "
+ + "owner text, "
+ + "hidden long, "
+ + "hint text, "
+ + "size text, "
+ + "difficulty float, "
+ + "terrain float, "
+ + "latlon text, "
+ + "latitude_string text, "
+ + "longitude_string text, "
+ + "location text, "
+ + "direction double, "
+ + "distance double, "
+ + "latitude double, "
+ + "longitude double, "
+ + "shortdesc text, "
+ + "description text, "
+ + "rating float, "
+ + "votes integer, "
+ + "vote integer, "
+ + "disabled integer not null default 0, "
+ + "archived integer not null default 0, "
+ + "members integer not null default 0, "
+ + "found integer not null default 0, "
+ + "favourite integer not null default 0, "
+ + "inventorycoins integer default 0, "
+ + "inventorytags integer default 0, "
+ + "inventoryunknown integer default 0 "
+ + "); ";
+
+ db.beginTransaction();
+ db.execSQL(dbCreateCachesTemp);
+ db.execSQL("insert into " + dbTableCaches + "_temp select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches);
+ db.execSQL("drop table " + dbTableCaches);
+ db.execSQL(dbCreateCachesNew);
+ db.execSQL("insert into " + dbTableCaches + " select _id, updated, detailed, detailedupdate, geocode, reason, cacheid, guid, type, name, owner, hidden, hint, size, difficulty, terrain, latlon, latitude_string, longitude_string, location, null, distance, latitude, longitude, shortdesc, description, rating, votes, vote, disabled, archived, members, found, favourite, inventorycoins, inventorytags, inventoryunknown from " + dbTableCaches + "_temp");
+ db.execSQL("drop table " + dbTableCaches + "_temp");
+ db.setTransactionSuccessful();
+
+ Log.i(cgSettings.tag, "Changed direction column");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 43: " + e.toString());
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ if (oldVersion < 44) { // upgrade to 44
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column favourite_cnt integer");
+
+ Log.i(cgSettings.tag, "Column favourite_cnt added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 44: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 45) { // upgrade to 45
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column owner_real text");
+
+ Log.i(cgSettings.tag, "Column owner_real added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 45: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 46) { // upgrade to 46
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column visiteddate long");
+ db.execSQL("create index if not exists in_f on " + dbTableCaches + " (visiteddate, detailedupdate)");
+
+ Log.i(cgSettings.tag, "Added column for date of visit.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 46: " + e.toString());
+ }
+ }
+ if (oldVersion < 47) { // upgrade to 47
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column own integer not null default 0");
+
+ Log.i(cgSettings.tag, "Added column own.");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 47: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 48) { // upgrade to 48
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column elevation double");
+
+ Log.i(cgSettings.tag, "Column elevation added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 48: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 49) { // upgrade to 49
+ try {
+ db.execSQL(dbCreateLogCount);
+
+ Log.i(cgSettings.tag, "Created table " + dbTableLogCount + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 49: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 50) { // upgrade to 50
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column myvote float");
+
+ Log.i(cgSettings.tag, "Added float column for votes to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 50: " + e.toString());
+ }
+ }
+
+ if (oldVersion < 51) { // upgrade to 51
+ try {
+ db.execSQL("alter table " + dbTableCaches + " add column reliable_latlon integer");
+
+ Log.i(cgSettings.tag, "Column reliable_latlon added to " + dbTableCaches + ".");
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Failed to upgrade to ver. 51: " + e.toString());
+ }
+ }
+ }
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ Log.i(cgSettings.tag, "Upgrade database from ver. " + oldVersion + " to ver. " + newVersion + ": completed");
+ }
+ }
+
+ private static void dropDatabase(SQLiteDatabase db) {
+ db.execSQL("drop table if exists " + dbTableCaches);
+ db.execSQL("drop table if exists " + dbTableAttributes);
+ db.execSQL("drop table if exists " + dbTableWaypoints);
+ db.execSQL("drop table if exists " + dbTableSpoilers);
+ db.execSQL("drop table if exists " + dbTableLogs);
+ db.execSQL("drop table if exists " + dbTableLogCount);
+ db.execSQL("drop table if exists " + dbTableLogsOffline);
+ db.execSQL("drop table if exists " + dbTableTrackables);
+ }
+
+ public String[] allDetailedThere() {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> thereA = new ArrayList<String>();
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "(detailed = 1 and detailedupdate > " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + ") or reason > 0",
+ null,
+ null,
+ null,
+ "detailedupdate desc",
+ "100");
+
+ if (cursor != null) {
+ int index = 0;
+ String geocode = null;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ index = cursor.getColumnIndex("geocode");
+ geocode = (String) cursor.getString(index);
+
+ thereA.add(geocode);
+ } while (cursor.moveToNext());
+ } else {
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return null;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.allDetailedThere: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return thereA.toArray(new String[thereA.size()]);
+ }
+
+ public boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
+ init();
+
+ Cursor cursor = null;
+
+ int cnt = 0;
+ long dataUpdated = 0;
+ long dataDetailedUpdate = 0;
+ int dataDetailed = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "detailed", "detailedupdate", "updated"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "detailed", "detailedupdate", "updated"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ int index = 0;
+ cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("updated");
+ dataUpdated = (long) cursor.getLong(index);
+ index = cursor.getColumnIndex("detailedupdate");
+ dataDetailedUpdate = (long) cursor.getLong(index);
+ index = cursor.getColumnIndex("detailed");
+ dataDetailed = (int) cursor.getInt(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isThere: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ if (cnt > 0) {
+ if (detailed == true && dataDetailed == 0) {
+ // we want details, but these are not stored
+ return false;
+ }
+
+ if (checkTime == true && detailed == true && dataDetailedUpdate < (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000))) {
+ // we want to check time for detailed cache, but data are older than 3 hours
+ return false;
+ }
+
+ if (checkTime == true && detailed == false && dataUpdated < (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000))) {
+ // we want to check time for short cache, but data are older than 3 hours
+ return false;
+ }
+
+ // we have some cache
+ return true;
+ }
+
+ // we have no such cache stored in cache
+ return false;
+ }
+
+ public boolean isOffline(String geocode, String guid) {
+ init();
+
+ Cursor cursor = null;
+ long reason = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reason"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reason"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ final int cnt = cursor.getCount();
+ int index = 0;
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("reason");
+ reason = (long) cursor.getLong(index);
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isOffline: " + e.toString());
+ }
+
+ if (reason >= 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isReliableLatLon(String geocode, String guid) {
+ init();
+
+ Cursor cursor = null;
+ int rel = 0;
+
+ try {
+ if (geocode != null && geocode.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reliable_latlon"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else if (guid != null && guid.length() > 0) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"reliable_latlon"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+ } else {
+ return false;
+ }
+
+ if (cursor != null) {
+ final int cnt = cursor.getCount();
+ int index = 0;
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("reliable_latlon");
+ rel = (int) cursor.getInt(index);
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.isOffline: " + e.toString());
+ }
+
+ if (rel >= 1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public String getGeocodeForGuid(String guid) {
+ init();
+
+ if (guid == null || guid.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ String geocode = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "guid = \"" + guid + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("geocode");
+ geocode = (String) cursor.getString(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getGeocodeForGuid: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return geocode;
+ }
+
+ public String getCacheidForGeocode(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ String cacheid = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "cacheid"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ index = cursor.getColumnIndex("cacheid");
+ cacheid = (String) cursor.getString(index);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getCacheidForGeocode: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return cacheid;
+ }
+
+ public boolean saveCache(cgCache cache) {
+ //LeeB - writing to the DB is slow
+ if (cache == null) {
+ return false;
+ }
+
+ ContentValues values = new ContentValues();
+
+ if (cache.updated == null) {
+ values.put("updated", System.currentTimeMillis());
+ } else {
+ values.put("updated", cache.updated);
+ }
+ values.put("reason", cache.reason);
+ if (cache.detailed == true) {
+ values.put("detailed", 1);
+ } else {
+ values.put("detailed", 0);
+ }
+ values.put("detailedupdate", cache.detailedUpdate);
+ values.put("visiteddate", cache.visitedDate);
+ values.put("geocode", cache.geocode);
+ values.put("cacheid", cache.cacheid);
+ values.put("guid", cache.guid);
+ values.put("type", cache.type);
+ values.put("name", cache.name);
+ if (cache.own == true) {
+ values.put("own", 1);
+ } else {
+ values.put("own", 0);
+ }
+ values.put("owner", cache.owner);
+ values.put("owner_real", cache.ownerReal);
+ if (cache.hidden == null) {
+ values.put("hidden", 0);
+ } else {
+ values.put("hidden", cache.hidden.getTime());
+ }
+ values.put("hint", cache.hint);
+ values.put("size", cache.size);
+ values.put("difficulty", cache.difficulty);
+ values.put("terrain", cache.terrain);
+ values.put("latlon", cache.latlon);
+ values.put("latitude_string", cache.latitudeString);
+ values.put("longitude_string", cache.longitudeString);
+ values.put("location", cache.location);
+ values.put("distance", cache.distance);
+ values.put("direction", cache.direction);
+ // save coordinates
+ final boolean rel = isReliableLatLon(cache.geocode, cache.guid);
+ if (cache.reliableLatLon) { // new cache has reliable coordinates, store
+ values.put("latitude", cache.latitude);
+ values.put("longitude", cache.longitude);
+ values.put("reliable_latlon", 1);
+ } else if (!rel) { // new cache neither stored cache is not reliable, just update
+ values.put("latitude", cache.latitude);
+ values.put("longitude", cache.longitude);
+ values.put("reliable_latlon", 0);
+ }
+ values.put("elevation", cache.elevation);
+ values.put("shortdesc", cache.shortdesc);
+ values.put("description", cache.description);
+ values.put("favourite_cnt", cache.favouriteCnt);
+ values.put("rating", cache.rating);
+ values.put("votes", cache.votes);
+ values.put("myvote", cache.myVote);
+ if (cache.disabled == true) {
+ values.put("disabled", 1);
+ } else {
+ values.put("disabled", 0);
+ }
+ if (cache.archived == true) {
+ values.put("archived", 1);
+ } else {
+ values.put("archived", 0);
+ }
+ if (cache.members == true) {
+ values.put("members", 1);
+ } else {
+ values.put("members", 0);
+ }
+ if (cache.found == true) {
+ values.put("found", 1);
+ } else {
+ values.put("found", 0);
+ }
+ if (cache.favourite == true) {
+ values.put("favourite", 1);
+ } else {
+ values.put("favourite", 0);
+ }
+ values.put("inventoryunknown", cache.inventoryItems);
+
+ boolean status = false;
+ boolean statusOk = true;
+
+ if (cache.attributes != null) {
+ status = saveAttributes(cache.geocode, cache.attributes);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.waypoints != null) {
+ status = saveWaypoints(cache.geocode, cache.waypoints, true);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.spoilers != null) {
+ status = saveSpoilers(cache.geocode, cache.spoilers);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.logs != null) {
+ status = saveLogs(cache.geocode, cache.logs);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.logCounts != null && cache.logCounts.isEmpty() == false) {
+ status = saveLogCount(cache.geocode, cache.logCounts);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (cache.inventory != null) {
+ status = saveInventory(cache.geocode, cache.inventory);
+ if (status == false) {
+ statusOk = false;
+ }
+ }
+
+ if (statusOk == false) {
+ cache.detailed = false;
+ cache.detailedUpdate = 0l;
+ }
+
+ init();
+
+ //try to update record else insert fresh..
+ try {
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + cache.geocode + "\"", null);
+ if (rows > 0) {
+ values = null;
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ try {
+ long id = databaseRW.insert(dbTableCaches, null, values);
+ if (id > 0) {
+ values = null;
+ return true;
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ values = null;
+
+ return false;
+ }
+
+ public boolean saveAttributes(String geocode, ArrayList<String> attributes) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || attributes == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ databaseRW.delete(dbTableAttributes, "geocode = \"" + geocode + "\"", null);
+
+ if (!attributes.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (String oneAttribute : attributes) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("attribute", oneAttribute);
+
+ databaseRW.insert(dbTableAttributes, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveWaypoints(String geocode, ArrayList<cgWaypoint> waypoints, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || waypoints == null) {
+ return false;
+ }
+
+ boolean ok = false;
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableWaypoints, "geocode = \"" + geocode + "\" and type <> \"own\"", null);
+ }
+
+ if (!waypoints.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgWaypoint oneWaypoint : waypoints) {
+ if (oneWaypoint.type.equalsIgnoreCase("own") == true) {
+ continue;
+ }
+
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", oneWaypoint.type);
+ values.put("prefix", oneWaypoint.prefix);
+ values.put("lookup", oneWaypoint.lookup);
+ values.put("name", oneWaypoint.name);
+ values.put("latlon", oneWaypoint.latlon);
+ values.put("latitude_string", oneWaypoint.latitudeString);
+ values.put("longitude_string", oneWaypoint.longitudeString);
+ values.put("latitude", oneWaypoint.latitude);
+ values.put("longitude", oneWaypoint.longitude);
+ values.put("note", oneWaypoint.note);
+
+ databaseRW.insert(dbTableWaypoints, null, values);
+ }
+ }
+
+ databaseRW.setTransactionSuccessful();
+ ok = true;
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return ok;
+ }
+
+ public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) {
+ init();
+
+ if (((geocode == null || geocode.length() == 0) && id <= 0) || waypoint == null) {
+ return false;
+ }
+
+ boolean ok = false;
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", waypoint.type);
+ values.put("prefix", waypoint.prefix);
+ values.put("lookup", waypoint.lookup);
+ values.put("name", waypoint.name);
+ values.put("latlon", waypoint.latlon);
+ values.put("latitude_string", waypoint.latitudeString);
+ values.put("longitude_string", waypoint.longitudeString);
+ values.put("latitude", waypoint.latitude);
+ values.put("longitude", waypoint.longitude);
+ values.put("note", waypoint.note);
+
+ if (id <= 0) {
+ databaseRW.insert(dbTableWaypoints, null, values);
+ ok = true;
+ } else {
+ final int rows = databaseRW.update(dbTableWaypoints, values, "_id = " + id, null);
+ if (rows > 0) {
+ ok = true;
+ } else {
+ ok = false;
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return ok;
+ }
+
+ public boolean deleteWaypoint(int id) {
+ init();
+
+ if (id == 0) {
+ return false;
+ }
+
+ int deleted = databaseRW.delete(dbTableWaypoints, "_id = " + id, null);
+
+ if (deleted > 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean saveSpoilers(String geocode, ArrayList<cgSpoiler> spoilers) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || spoilers == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ databaseRW.delete(dbTableSpoilers, "geocode = \"" + geocode + "\"", null);
+
+ if (!spoilers.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgSpoiler oneSpoiler : spoilers) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("url", oneSpoiler.url);
+ values.put("title", oneSpoiler.title);
+ values.put("description", oneSpoiler.description);
+
+ databaseRW.insert(dbTableSpoilers, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveLogs(String geocode, ArrayList<cgLog> logs) {
+ return saveLogs(geocode, logs, true);
+ }
+
+ public boolean saveLogs(String geocode, ArrayList<cgLog> logs, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || logs == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableLogs, "geocode = \"" + geocode + "\"", null);
+ }
+
+ if (!logs.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgLog oneLog : logs) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", oneLog.type);
+ values.put("author", oneLog.author);
+ values.put("log", oneLog.log);
+ values.put("date", oneLog.date);
+ values.put("found", oneLog.found);
+
+ databaseRW.insert(dbTableLogs, null, values);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveLogCount(String geocode, HashMap<Integer, Integer> logCounts) {
+ return saveLogCount(geocode, logCounts, true);
+ }
+
+ public boolean saveLogCount(String geocode, HashMap<Integer, Integer> logCounts, boolean drop) {
+ init();
+
+ if (geocode == null || geocode.length() == 0 || logCounts == null || logCounts.isEmpty()) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (drop == true) {
+ databaseRW.delete(dbTableLogCount, "geocode = \"" + geocode + "\"", null);
+ }
+
+ ContentValues values = new ContentValues();
+
+ Set<Entry<Integer, Integer>> logCountsItems = logCounts.entrySet();
+ for (Entry<Integer, Integer> pair : logCountsItems) {
+ values.clear();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", pair.getKey().intValue());
+ values.put("count", pair.getValue().intValue());
+
+ databaseRW.insert(dbTableLogCount, null, values);
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public boolean saveInventory(String geocode, ArrayList<cgTrackable> trackables) {
+ init();
+
+ if (trackables == null) {
+ return false;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ if (geocode != null) {
+ databaseRW.delete(dbTableTrackables, "geocode = \"" + geocode + "\"", null);
+ }
+
+ if (!trackables.isEmpty()) {
+ ContentValues values = new ContentValues();
+ for (cgTrackable oneTrackable : trackables) {
+ values.clear();
+ if (geocode != null) {
+ values.put("geocode", geocode);
+ }
+ values.put("updated", System.currentTimeMillis());
+ values.put("tbcode", oneTrackable.geocode);
+ values.put("guid", oneTrackable.guid);
+ values.put("title", oneTrackable.name);
+ values.put("owner", oneTrackable.owner);
+ if (oneTrackable.released != null) {
+ values.put("released", oneTrackable.released.getTime());
+ } else {
+ values.put("released", 0l);
+ }
+ values.put("goal", oneTrackable.goal);
+ values.put("description", oneTrackable.details);
+
+ databaseRW.insert(dbTableTrackables, null, values);
+
+ saveLogs(oneTrackable.geocode, oneTrackable.logs);
+ }
+ }
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return true;
+ }
+
+ public ArrayList<Object> getBounds(Object[] geocodes) {
+ init();
+
+ Cursor cursor = null;
+
+ final ArrayList<Object> viewport = new ArrayList<Object>();
+
+ try {
+ final StringBuilder where = new StringBuilder();
+
+ if (geocodes != null && geocodes.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : geocodes) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("geocode in (");
+ where.append(all);
+ where.append(")");
+ }
+
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"count(_id) as cnt", "min(latitude) as latMin", "max(latitude) as latMax", "min(longitude) as lonMin", "max(longitude) as lonMax"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ int cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ viewport.add((Integer) cursor.getInt(cursor.getColumnIndex("cnt")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("latMin")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("latMax")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("lonMin")));
+ viewport.add((Double) cursor.getDouble(cursor.getColumnIndex("lonMax")));
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getBounds: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return viewport;
+ }
+
+ public cgCache loadCache(String geocode, String guid) {
+ return loadCache(geocode, guid, false, true, false, false, false, false);
+ }
+
+ public cgCache loadCache(String geocode, String guid, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ Object[] geocodes = new Object[1];
+ Object[] guids = new Object[1];
+
+ if (geocode != null && geocode.length() > 0) {
+ geocodes[0] = geocode;
+ } else {
+ geocodes = null;
+ }
+
+ if (guid != null && guid.length() > 0) {
+ guids[0] = guid;
+ } else {
+ guids = null;
+ }
+
+ ArrayList<cgCache> caches = loadCaches(geocodes, guids, null, null, null, null, loadA, loadW, loadS, loadL, loadI, loadO);
+ if (caches != null && caches.isEmpty() == false) {
+ return caches.get(0);
+ }
+
+ return null;
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids) {
+ return loadCaches(geocodes, guids, null, null, null, null, false, true, false, false, false, false);
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids, boolean lite) {
+ if (lite == true) {
+ return loadCaches(geocodes, guids, null, null, null, null, false, true, false, false, false, false);
+ } else {
+ return loadCaches(geocodes, guids, null, null, null, null, true, true, true, true, true, true);
+ }
+ }
+
+ public ArrayList<cgCache> loadCaches(Object[] geocodes, Object[] guids, Long centerLat, Long centerLon, Long spanLat, Long spanLon, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ init();
+
+ StringBuilder where = new StringBuilder();
+ Cursor cursor = null;
+ ArrayList<cgCache> caches = new ArrayList<cgCache>();
+
+ try {
+ if (geocodes != null && geocodes.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : geocodes) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("geocode in (");
+ where.append(all);
+ where.append(")");
+ } else if (guids != null && guids.length > 0) {
+ StringBuilder all = new StringBuilder();
+ for (Object one : guids) {
+ if (all.length() > 0) {
+ all.append(", ");
+ }
+ all.append("\"");
+ all.append((String) one);
+ all.append("\"");
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("guid in (");
+ where.append(all);
+ where.append(")");
+ } else {
+ return caches;
+ }
+
+ // viewport limitation
+ if (centerLat != null && centerLon != null && spanLat != null && spanLon != null) {
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("(");
+ where.append("latitude >= ");
+ where.append(String.format((Locale) null, "%.6f", latMin));
+ where.append(" and latitude <= ");
+ where.append(String.format((Locale) null, "%.6f", latMax));
+ where.append(" and longitude >= ");
+ where.append(String.format((Locale) null, "%.6f", lonMin));
+ where.append(" and longitude <= ");
+ where.append(String.format((Locale) null, "%.6f", lonMax));
+ where.append(")");
+ }
+
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{
+ "_id", "updated", "reason", "detailed", "detailedupdate", "visiteddate", "geocode", "cacheid", "guid", "type", "name", "own", "owner", "owner_real", "hidden", "hint", "size",
+ "difficulty", "distance", "direction", "terrain", "latlon", "latitude_string", "longitude_string", "location", "latitude", "longitude", "elevation", "shortdesc",
+ "description", "favourite_cnt", "rating", "votes", "myvote", "disabled", "archived", "members", "found", "favourite", "inventorycoins", "inventorytags",
+ "inventoryunknown"
+ },
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ int index = 0;
+
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgCache cache = new cgCache();
+
+ cache.updated = (long) cursor.getLong(cursor.getColumnIndex("updated"));
+ cache.reason = (int) cursor.getInt(cursor.getColumnIndex("reason"));
+ index = cursor.getColumnIndex("detailed");
+ if ((int) cursor.getInt(index) == 1) {
+ cache.detailed = true;
+ } else {
+ cache.detailed = false;
+ }
+ cache.detailedUpdate = (Long) cursor.getLong(cursor.getColumnIndex("detailedupdate"));
+ cache.visitedDate = (Long) cursor.getLong(cursor.getColumnIndex("visiteddate"));
+ cache.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ cache.cacheid = (String) cursor.getString(cursor.getColumnIndex("cacheid"));
+ cache.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ cache.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ cache.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ index = cursor.getColumnIndex("own");
+ if ((int) cursor.getInt(index) == 1) {
+ cache.own = true;
+ } else {
+ cache.own = false;
+ }
+ cache.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ cache.ownerReal = (String) cursor.getString(cursor.getColumnIndex("owner_real"));
+ cache.hidden = new Date((long) cursor.getLong(cursor.getColumnIndex("hidden")));
+ cache.hint = (String) cursor.getString(cursor.getColumnIndex("hint"));
+ cache.size = (String) cursor.getString(cursor.getColumnIndex("size"));
+ cache.difficulty = (Float) cursor.getFloat(cursor.getColumnIndex("difficulty"));
+ index = cursor.getColumnIndex("direction");
+ if (cursor.isNull(index) == true) {
+ cache.direction = null;
+ } else {
+ cache.direction = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("distance");
+ if (cursor.isNull(index) == true) {
+ cache.distance = null;
+ } else {
+ cache.distance = (Double) cursor.getDouble(index);
+ }
+ cache.terrain = (Float) cursor.getFloat(cursor.getColumnIndex("terrain"));
+ cache.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ cache.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ cache.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ cache.location = (String) cursor.getString(cursor.getColumnIndex("location"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ cache.latitude = null;
+ } else {
+ cache.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ cache.longitude = null;
+ } else {
+ cache.longitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("elevation");
+ if (cursor.isNull(index) == true) {
+ cache.elevation = null;
+ } else {
+ cache.elevation = (Double) cursor.getDouble(index);
+ }
+ cache.shortdesc = (String) cursor.getString(cursor.getColumnIndex("shortdesc"));
+ cache.description = (String) cursor.getString(cursor.getColumnIndex("description"));
+ cache.favouriteCnt = (Integer) cursor.getInt(cursor.getColumnIndex("favourite_cnt"));
+ cache.rating = (Float) cursor.getFloat(cursor.getColumnIndex("rating"));
+ cache.votes = (Integer) cursor.getInt(cursor.getColumnIndex("votes"));
+ cache.myVote = (Float) cursor.getFloat(cursor.getColumnIndex("myvote"));
+ index = cursor.getColumnIndex("disabled");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.disabled = true;
+ } else {
+ cache.disabled = false;
+ }
+ index = cursor.getColumnIndex("archived");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ index = cursor.getColumnIndex("members");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.members = true;
+ } else {
+ cache.members = false;
+ }
+ index = cursor.getColumnIndex("found");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.found = true;
+ } else {
+ cache.found = false;
+ }
+ index = cursor.getColumnIndex("favourite");
+ if ((int) cursor.getLong(index) == 1) {
+ cache.favourite = true;
+ } else {
+ cache.favourite = false;
+ }
+ cache.inventoryItems = (Integer) cursor.getInt(cursor.getColumnIndex("inventoryunknown"));
+
+ if (loadA == true) {
+ ArrayList<String> attributes = loadAttributes(cache.geocode);
+ if (attributes != null && attributes.isEmpty() == false) {
+ if (cache.attributes == null)
+ cache.attributes = new ArrayList<String>();
+ else
+ cache.attributes.clear();
+ cache.attributes.addAll(attributes);
+ }
+ }
+
+ if (loadW == true) {
+ ArrayList<cgWaypoint> waypoints = loadWaypoints(cache.geocode);
+ if (waypoints != null && waypoints.isEmpty() == false) {
+ if (cache.waypoints == null)
+ cache.waypoints = new ArrayList<cgWaypoint>();
+ else
+ cache.waypoints.clear();
+ cache.waypoints.addAll(waypoints);
+ }
+ }
+
+ if (loadS == true) {
+ ArrayList<cgSpoiler> spoilers = loadSpoilers(cache.geocode);
+ if (spoilers != null && spoilers.isEmpty() == false) {
+ if (cache.spoilers == null)
+ cache.spoilers = new ArrayList<cgSpoiler>();
+ else
+ cache.spoilers.clear();
+ cache.spoilers.addAll(spoilers);
+ }
+ }
+
+ if (loadL == true) {
+ ArrayList<cgLog> logs = loadLogs(cache.geocode);
+ if (logs != null && logs.isEmpty() == false) {
+ if (cache.logs == null)
+ cache.logs = new ArrayList<cgLog>();
+ else
+ cache.logs.clear();
+ cache.logs.addAll(logs);
+ }
+ HashMap<Integer, Integer> logCounts = loadLogCounts(cache.geocode);
+ if (logCounts != null && logCounts.isEmpty() == false) {
+ cache.logCounts.clear();
+ cache.logCounts.putAll(logCounts);
+ }
+ }
+
+ if (loadI == true) {
+ ArrayList<cgTrackable> inventory = loadInventory(cache.geocode);
+ if (inventory != null && inventory.isEmpty() == false) {
+ if (cache.inventory == null)
+ cache.inventory = new ArrayList<cgTrackable>();
+ else
+ cache.inventory.clear();
+ cache.inventory.addAll(inventory);
+ }
+ }
+
+ if (loadO == true) {
+ cache.logOffline = hasLogOffline(cache.geocode);
+ }
+
+ caches.add(cache);
+ } while (cursor.moveToNext());
+ } else {
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return null;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadCaches: " + e.toString());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return caches;
+ }
+
+ public ArrayList<String> loadAttributes(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<String> attributes = new ArrayList<String>();
+
+ cursor = databaseRO.query(
+ dbTableAttributes,
+ new String[]{"_id", "attribute"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ attributes.add((String) cursor.getString(cursor.getColumnIndex("attribute")));
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return attributes;
+ }
+
+ public cgWaypoint loadWaypoint(Integer id) {
+ init();
+
+ if (id == null || id == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgWaypoint waypoint = new cgWaypoint();
+
+ cursor = databaseRO.query(
+ dbTableWaypoints,
+ new String[]{"_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude_string", "longitude_string", "latitude", "longitude", "note"},
+ "_id = " + id,
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ int index;
+ cursor.moveToFirst();
+
+ waypoint.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ waypoint.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ waypoint.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ waypoint.prefix = (String) cursor.getString(cursor.getColumnIndex("prefix"));
+ waypoint.lookup = (String) cursor.getString(cursor.getColumnIndex("lookup"));
+ waypoint.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ waypoint.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ waypoint.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ waypoint.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.latitude = null;
+ } else {
+ waypoint.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.longitude = null;
+ } else {
+ waypoint.longitude = (Double) cursor.getDouble(index);
+ }
+ waypoint.note = (String) cursor.getString(cursor.getColumnIndex("note"));
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return waypoint;
+ }
+
+ public ArrayList<cgWaypoint> loadWaypoints(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgWaypoint> waypoints = new ArrayList<cgWaypoint>();
+
+ cursor = databaseRO.query(
+ dbTableWaypoints,
+ new String[]{"_id", "geocode", "updated", "type", "prefix", "lookup", "name", "latlon", "latitude_string", "longitude_string", "latitude", "longitude", "note"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ int index;
+ cursor.moveToFirst();
+
+ do {
+ cgWaypoint waypoint = new cgWaypoint();
+ waypoint.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ waypoint.geocode = (String) cursor.getString(cursor.getColumnIndex("geocode"));
+ waypoint.type = (String) cursor.getString(cursor.getColumnIndex("type"));
+ waypoint.prefix = (String) cursor.getString(cursor.getColumnIndex("prefix"));
+ waypoint.lookup = (String) cursor.getString(cursor.getColumnIndex("lookup"));
+ waypoint.name = (String) cursor.getString(cursor.getColumnIndex("name"));
+ waypoint.latlon = (String) cursor.getString(cursor.getColumnIndex("latlon"));
+ waypoint.latitudeString = (String) cursor.getString(cursor.getColumnIndex("latitude_string"));
+ waypoint.longitudeString = (String) cursor.getString(cursor.getColumnIndex("longitude_string"));
+ index = cursor.getColumnIndex("latitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.latitude = null;
+ } else {
+ waypoint.latitude = (Double) cursor.getDouble(index);
+ }
+ index = cursor.getColumnIndex("longitude");
+ if (cursor.isNull(index) == true) {
+ waypoint.longitude = null;
+ } else {
+ waypoint.longitude = (Double) cursor.getDouble(index);
+ }
+ waypoint.note = (String) cursor.getString(cursor.getColumnIndex("note"));
+
+ waypoints.add(waypoint);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return waypoints;
+ }
+
+ public ArrayList<cgSpoiler> loadSpoilers(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgSpoiler> spoilers = new ArrayList<cgSpoiler>();
+
+ cursor = databaseRO.query(
+ dbTableSpoilers,
+ new String[]{"_id", "url", "title", "description"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgSpoiler spoiler = new cgSpoiler();
+ spoiler.url = (String) cursor.getString(cursor.getColumnIndex("url"));
+ spoiler.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ spoiler.description = (String) cursor.getString(cursor.getColumnIndex("description"));
+
+ spoilers.add(spoiler);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return spoilers;
+ }
+
+ public ArrayList<cgLog> loadLogs(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgLog> logs = new ArrayList<cgLog>();
+
+ cursor = databaseRO.query(
+ dbTableLogs,
+ new String[]{"_id", "type", "author", "log", "date", "found"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ "date desc, _id asc",
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgLog log = new cgLog();
+ log.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ log.type = (int) cursor.getInt(cursor.getColumnIndex("type"));
+ log.author = (String) cursor.getString(cursor.getColumnIndex("author"));
+ log.log = (String) cursor.getString(cursor.getColumnIndex("log"));
+ log.date = (long) cursor.getLong(cursor.getColumnIndex("date"));
+ log.found = (int) cursor.getInt(cursor.getColumnIndex("found"));
+
+ logs.add(log);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return logs;
+ }
+
+ public HashMap<Integer, Integer> loadLogCounts(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ HashMap<Integer, Integer> logCounts = new HashMap<Integer, Integer>();
+
+ cursor = databaseRO.query(
+ dbTableLogCount,
+ new String[]{"_id", "type", "count"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ Integer type = new Integer(cursor.getInt(cursor.getColumnIndex("type")));
+ Integer count = new Integer(cursor.getInt(cursor.getColumnIndex("count")));
+
+ logCounts.put(type, count);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return logCounts;
+ }
+
+ public ArrayList<cgTrackable> loadInventory(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ ArrayList<cgTrackable> trackables = new ArrayList<cgTrackable>();
+
+ cursor = databaseRO.query(
+ dbTableTrackables,
+ new String[]{"_id", "updated", "tbcode", "guid", "title", "owner", "released", "goal", "description"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "100");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgTrackable trackable = new cgTrackable();
+ trackable.geocode = (String) cursor.getString(cursor.getColumnIndex("tbcode"));
+ trackable.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ trackable.name = (String) cursor.getString(cursor.getColumnIndex("title"));
+ trackable.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ String releasedPre = cursor.getString(cursor.getColumnIndex("released"));
+ if (releasedPre != null && Long.getLong(releasedPre) != null) {
+ trackable.released = new Date(Long.getLong(releasedPre));
+ } else {
+ trackable.released = null;
+ }
+ trackable.goal = (String) cursor.getString(cursor.getColumnIndex("goal"));
+ trackable.details = (String) cursor.getString(cursor.getColumnIndex("description"));
+ trackable.logs = loadLogs(trackable.geocode);
+
+ trackables.add(trackable);
+ } while (cursor.moveToNext());
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return trackables;
+ }
+
+ public cgTrackable loadTrackable(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgTrackable trackable = new cgTrackable();
+
+ cursor = databaseRO.query(
+ dbTableTrackables,
+ new String[]{"_id", "updated", "tbcode", "guid", "title", "owner", "released", "goal", "description"},
+ "tbcode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ null,
+ "1");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ trackable.geocode = (String) cursor.getString(cursor.getColumnIndex("tbcode"));
+ trackable.guid = (String) cursor.getString(cursor.getColumnIndex("guid"));
+ trackable.name = (String) cursor.getString(cursor.getColumnIndex("title"));
+ trackable.owner = (String) cursor.getString(cursor.getColumnIndex("owner"));
+ String releasedPre = cursor.getString(cursor.getColumnIndex("released"));
+ if (releasedPre != null && Long.getLong(releasedPre) != null) {
+ trackable.released = new Date(Long.getLong(releasedPre));
+ } else {
+ trackable.released = null;
+ }
+ trackable.goal = (String) cursor.getString(cursor.getColumnIndex("goal"));
+ trackable.details = (String) cursor.getString(cursor.getColumnIndex("description"));
+ trackable.logs = loadLogs(trackable.geocode);
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return trackable;
+ }
+
+ public int getAllStoredCachesCount(boolean detailedOnly, String cachetype, Integer list) {
+ int count = 0;
+
+ String listSql = null;
+ String listSqlW = null;
+ if (list == null) {
+ listSql = " where reason >= 1";
+ listSqlW = " and reason >= 1";
+ } else if (list >= 1) {
+ listSql = " where reason = " + list;
+ listSqlW = " and reason = " + list;
+ } else {
+ return count;
+ }
+
+ try {
+ if (detailedOnly == false) {
+ if (cachetype == null) {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + listSql);
+ count = (int) sqlCount.simpleQueryForLong();
+ } else {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where type = \"" + cachetype + "\"" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ }
+ } else {
+ if (cachetype == null) {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where detailed = 1" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ } else {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where detailed = 1 and type = \"" + cachetype + "\"" + listSqlW);
+ count = (int) sqlCount.simpleQueryForLong();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadAllStoredCachesCount: " + e.toString());
+ }
+
+ return count;
+ }
+
+ public int getAllHistoricCachesCount(boolean detailedOnly, String cachetype) {
+ init();
+
+ int count = 0;
+
+ try {
+ SQLiteStatement sqlCount = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where visiteddate > 0");
+ count = (int) sqlCount.simpleQueryForLong();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getAllHistoricCachesCount: " + e.toString());
+ }
+
+ return count;
+ }
+
+ public ArrayList<String> loadBatchOfStoredGeocodes(boolean detailedOnly, Double latitude, Double longitude, String cachetype, int list) {
+ init();
+
+ if (list < 1) {
+ list = 1;
+ }
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder specifySql = new StringBuilder();
+
+ specifySql.append("reason = ");
+ specifySql.append(list);
+
+ if (detailedOnly == true) {
+ if (specifySql.length() > 0) {
+ specifySql.append(" and ");
+ }
+
+ specifySql.append("detailed = 1");
+ }
+
+ if (cachetype != null) {
+ if (specifySql.length() > 0) {
+ specifySql.append(" and ");
+ }
+
+ specifySql.append("type = \"");
+ specifySql.append(cachetype);
+ specifySql.append("\"");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode", "(abs(latitude-" + String.format((Locale) null, "%.6f", latitude) + ") + abs(longitude-" + String.format((Locale) null, "%.6f", longitude) + ")) as dif"},
+ specifySql.toString(),
+ null,
+ null,
+ null,
+ "dif",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadBatchOfStoredGeocodes: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> loadBatchOfHistoricGeocodes(boolean detailedOnly, String cachetype) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder specifySql = new StringBuilder();
+ if (detailedOnly == true) {
+ specifySql.append(" and detailed = 1");
+ }
+ if (cachetype != null) {
+ specifySql.append(" and type = \"");
+ specifySql.append(cachetype);
+ specifySql.append("\"");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "visiteddate > 0" + specifySql.toString(),
+ null,
+ null,
+ null,
+ "visiteddate",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.loadBatchOfHistoricGeocodes: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> getCachedInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ return getInViewport(false, centerLat, centerLon, spanLat, spanLon, cachetype);
+ }
+
+ public ArrayList<String> getStoredInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ return getInViewport(true, centerLat, centerLon, spanLat, spanLon, cachetype);
+ }
+
+ public ArrayList<String> getInViewport(boolean stored, Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (centerLat == null || centerLon == null || spanLat == null || spanLon == null) {
+ return null;
+ }
+
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ // viewport limitation
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ StringBuilder where = new StringBuilder();
+ where.append("latitude >= ");
+ where.append(String.format((Locale) null, "%.6f", latMin));
+ where.append(" and latitude <= ");
+ where.append(String.format((Locale) null, "%.6f", latMax));
+ where.append(" and longitude >= ");
+ where.append(String.format((Locale) null, "%.6f", lonMin));
+ where.append(" and longitude <= ");
+ where.append(String.format((Locale) null, "%.6f", lonMax));
+
+ // cachetype limitation
+ if (cachetype != null) {
+ where.append(" and type = \"");
+ where.append(cachetype);
+ where.append("\"");
+ }
+
+ // offline caches only
+ if (stored) {
+ where.append(" and reason >= 1");
+ }
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ "500");
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getOfflineInViewport: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public ArrayList<String> getOfflineAll(String cachetype) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ StringBuilder where = new StringBuilder();
+
+ // cachetype limitation
+ if (cachetype != null) {
+ where.append(cachetype);
+ where.append("\"");
+ }
+
+ // offline caches only
+ if (where.length() > 0) {
+ where.append(" and ");
+ }
+ where.append("reason >= 1");
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ where.toString(),
+ null,
+ null,
+ null,
+ null,
+ "5000");
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add((String) cursor.getString(cursor.getColumnIndex("geocode")));
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return null;
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getOfflineAll: " + e.toString());
+ }
+
+ return geocodes;
+ }
+
+ public void markStored(String geocode, int listId) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ if (listId <= 0) {
+ listId = 1;
+ }
+
+ ContentValues values = new ContentValues();
+ values.put("reason", listId);
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\" and reason < 1", null);
+ }
+
+ public boolean markDropped(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put("reason", 0);
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.markDropped: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public boolean markFound(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ try {
+ ContentValues values = new ContentValues();
+ values.put("found", 1);
+ int rows = databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.markFound: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public void clean() {
+ clean(false);
+ }
+
+ public void clean(boolean more) {
+ init();
+
+ Log.d(cgSettings.tag, "Database clean: started");
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ try {
+ if (more) {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = 0",
+ null,
+ null,
+ null,
+ null,
+ null);
+ } else {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = 0 and detailed < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + " and detailedupdate < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)) + " and visiteddate < " + (System.currentTimeMillis() - (3 * 24 * 60 * 60 * 1000)),
+ null,
+ null,
+ null,
+ null,
+ null);
+ }
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add("\"" + (String) cursor.getString(cursor.getColumnIndex("geocode")) + "\"");
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+
+ final int size = geocodes.size();
+ if (size > 0) {
+ Log.d(cgSettings.tag, "Database clean: removing " + size + " geocaches");
+
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableAttributes + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableSpoilers + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogs + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogCount + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogsOffline + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableWaypoints + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ") and type <> \"own\"");
+ databaseRW.execSQL("delete from " + dbTableTrackables + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+
+ geocodes.clear();
+ }
+
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode = \"\"");
+
+ final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableCaches + " where reason = 0");
+ final int count = (int) countSql.simpleQueryForLong();
+ Log.d(cgSettings.tag, "Database clean: " + count + " cached geocaches remaining");
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgData.clean: " + e.toString());
+ }
+
+ Log.d(cgSettings.tag, "Database clean: finished");
+ }
+
+ public void dropStored(int listId) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<String> geocodes = new ArrayList<String>();
+
+ try {
+ cursor = databaseRO.query(
+ dbTableCaches,
+ new String[]{"_id", "geocode"},
+ "reason = " + listId,
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ geocodes.add("\"" + (String) cursor.getString(cursor.getColumnIndex("geocode")) + "\"");
+ } while (cursor.moveToNext());
+ } else {
+ cursor.close();
+ return;
+ }
+
+ cursor.close();
+ }
+
+ if (geocodes.size() > 0) {
+ databaseRW.execSQL("delete from " + dbTableCaches + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableAttributes + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableSpoilers + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogs + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogCount + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableLogsOffline + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+ databaseRW.execSQL("delete from " + dbTableWaypoints + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ") and type <> \"own\"");
+ databaseRW.execSQL("delete from " + dbTableTrackables + " where geocode in (" + cgBase.implode(", ", geocodes.toArray()) + ")");
+
+ geocodes.clear();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.dropStored: " + e.toString());
+ }
+ }
+
+ public boolean saveLogOffline(String geocode, Date date, int type, String log) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+ if (type <= 0 && (log == null || log.length() == 0)) {
+ return false;
+ }
+
+ boolean status = false;
+
+ ContentValues values = new ContentValues();
+ values.put("geocode", geocode);
+ values.put("updated", System.currentTimeMillis());
+ values.put("type", type);
+ values.put("log", log);
+ values.put("date", date.getTime());
+
+ try {
+ if (hasLogOffline(geocode) == true) {
+ final int rows = databaseRW.update(dbTableLogsOffline, values, "geocode = \"" + geocode + "\"", null);
+
+ if (rows > 0) {
+ status = true;
+ }
+ } else {
+ final long id = databaseRW.insert(dbTableLogsOffline, null, values);
+
+ if (id > 0) {
+ status = true;
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.saveLogOffline: " + e.toString());
+ }
+
+ return status;
+ }
+
+ public cgLog loadLogOffline(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ Cursor cursor = null;
+ cgLog log = null;
+
+ cursor = databaseRO.query(
+ dbTableLogsOffline,
+ new String[]{"_id", "type", "log", "date"},
+ "geocode = \"" + geocode + "\"",
+ null,
+ null,
+ null,
+ "_id desc",
+ "1");
+
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ log = new cgLog();
+ log.id = (int) cursor.getInt(cursor.getColumnIndex("_id"));
+ log.type = (int) cursor.getInt(cursor.getColumnIndex("type"));
+ log.log = (String) cursor.getString(cursor.getColumnIndex("log"));
+ log.date = (long) cursor.getLong(cursor.getColumnIndex("date"));
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return log;
+ }
+
+ public void clearLogOffline(String geocode) {
+ init();
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ databaseRW.delete(dbTableLogsOffline, "geocode = \"" + geocode + "\"", null);
+ }
+
+ public boolean hasLogOffline(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+
+ init();
+
+ try {
+ final SQLiteStatement countSql = databaseRO.compileStatement("select count(_id) from " + dbTableLogsOffline + " where geocode = \"" + geocode.toUpperCase() + "\"");
+ final int count = (int) countSql.simpleQueryForLong();
+
+ if (count > 0) {
+ return true;
+ }
+
+ countSql.close();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.hasLogOffline: " + e.toString());
+ }
+
+ return false;
+ }
+
+ public void saveVisitDate(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ ContentValues values = new ContentValues();
+ values.put("visiteddate", System.currentTimeMillis());
+
+ try {
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.saveVisitDate: " + e.toString());
+ }
+ }
+
+ public ArrayList<cgList> getLists(Resources res) {
+ init();
+
+ Cursor cursor = null;
+ ArrayList<cgList> lists = new ArrayList<cgList>();
+
+ lists.add(new cgList(true, 1, res.getString(R.string.list_inbox)));
+ // lists.add(new cgList(true, 2, res.getString(R.string.list_wpt)));
+
+ try {
+ cursor = databaseRO.query(
+ dbTableLists,
+ new String[]{"_id", "title", "updated", "latitude", "longitude"},
+ null,
+ null,
+ null,
+ null,
+ "title COLLATE NOCASE ASC",
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ cgList list = new cgList(false);
+
+ list.id = ((int) cursor.getInt(cursor.getColumnIndex("_id"))) + 10;
+ list.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ list.updated = (Long) cursor.getLong(cursor.getColumnIndex("updated"));
+ list.latitude = (Double) cursor.getDouble(cursor.getColumnIndex("latitude"));
+ list.longitude = (Double) cursor.getDouble(cursor.getColumnIndex("longitude"));
+
+ lists.add(list);
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getLists: " + e.toString());
+ }
+
+ return lists;
+ }
+
+ public cgList getList(int id, Resources res) {
+ cgList list = null;
+
+ if (id == 1) {
+ list = new cgList(true, 1, res.getString(R.string.list_inbox));
+ } else if (id == 2) {
+ list = new cgList(true, 2, res.getString(R.string.list_wpt));
+ } else if (id >= 10) {
+ init();
+
+ Cursor cursor = null;
+
+ try {
+ cursor = databaseRO.query(
+ dbTableLists,
+ new String[]{"_id", "title", "updated", "latitude", "longitude"},
+ "_id = " + (id - 10),
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+
+ do {
+ list = new cgList(false);
+
+ list.id = ((int) cursor.getInt(cursor.getColumnIndex("_id"))) + 10;
+ list.title = (String) cursor.getString(cursor.getColumnIndex("title"));
+ list.updated = (Long) cursor.getLong(cursor.getColumnIndex("updated"));
+ list.latitude = (Double) cursor.getDouble(cursor.getColumnIndex("latitude"));
+ list.longitude = (Double) cursor.getDouble(cursor.getColumnIndex("longitude"));
+ } while (cursor.moveToNext());
+ }
+
+ cursor.close();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgData.getList: " + e.toString());
+ }
+ }
+
+ return list;
+ }
+
+ public int createList(String name) {
+ init();
+
+ int id = -1;
+ if (name == null || name.length() == 0) {
+ return id;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("title", name);
+ values.put("updated", System.currentTimeMillis());
+
+ id = (int) databaseRW.insert(dbTableLists, null, values);
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ if (id < 0) {
+ return -1;
+ } else {
+ return (id + 10);
+ }
+ }
+
+ public boolean removeList(int id) {
+ init();
+
+ boolean status = false;
+ if (id < 10) {
+ return status;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ int cnt = databaseRW.delete(dbTableLists, "_id = " + (id - 10), null);
+
+ if (cnt > 0) {
+ ContentValues values = new ContentValues();
+ values.put("reason", 1);
+ databaseRW.update(dbTableCaches, values, "reason = " + id, null);
+
+ status = true;
+ }
+
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+
+ return status;
+ }
+
+ public void moveToList(String geocode, int listId) {
+ if (geocode == null || geocode.length() == 0 || listId <= 0) {
+ return;
+ }
+
+ databaseRW.beginTransaction();
+ try {
+ ContentValues values = new ContentValues();
+ values.put("reason", listId);
+ databaseRW.update(dbTableCaches, values, "geocode = \"" + geocode + "\"", null);
+
+ databaseRW.setTransactionSuccessful();
+ } finally {
+ databaseRW.endTransaction();
+ }
+ }
+
+ public boolean status() {
+ if (databaseRO == null || databaseRW == null || initialized == false) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/cgeo/geocaching/cgDirection.java b/src/cgeo/geocaching/cgDirection.java
new file mode 100644
index 0000000..daf5df6
--- /dev/null
+++ b/src/cgeo/geocaching/cgDirection.java
@@ -0,0 +1,102 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorManager;
+import android.hardware.SensorEventListener;
+import android.os.Build;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+
+public class cgDirection {
+ private Resources res = null;
+ private cgDirection dir = null;
+ private cgeoapplication app = null;
+ private Context context = null;
+ private cgWarning warning = null;
+ private SensorManager sensorManager = null;
+ private cgeoSensorListener sensorListener = null;
+ private cgUpdateDir dirUpdate = null;
+ private cg8wrap cg8 = null;
+
+ public Double directionNow = null;
+
+ public cgDirection(cgeoapplication appIn, Context contextIn, cgUpdateDir dirUpdateIn, cgWarning warningIn) {
+ app = appIn;
+ context = contextIn;
+ dirUpdate = dirUpdateIn;
+ warning = warningIn;
+ res = context.getResources();
+
+ try {
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) cg8 = new cg8wrap((Activity)context);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ sensorListener = new cgeoSensorListener();
+ }
+
+ public void initDir() {
+ dir = this;
+
+ if (sensorManager == null) {
+ sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ }
+ sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ public void closeDir() {
+ if (sensorManager != null && sensorListener != null) {
+ sensorManager.unregisterListener(sensorListener);
+ }
+ }
+
+ public void replaceUpdate(cgUpdateDir dirUpdateIn) {
+ dirUpdate = dirUpdateIn;
+
+ if (dirUpdate != null && directionNow != null) dirUpdate.updateDir(dir);
+ }
+
+ private class cgeoSensorListener implements SensorEventListener {
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ /* There is a bug in Android, which appearently causes this method to be called every
+ * time the sensor _value_ changed, even if the _accuracy_ did not change. So logging
+ * this event leads to the log being flooded with multiple entries _per second_,
+ * which I experienced when running cgeo in a building (with GPS and network being
+ * unreliable).
+ *
+ * See for example https://code.google.com/p/android/issues/detail?id=14792
+ */
+
+ //Log.i(cgSettings.tag, "Compass' accuracy is low (" + accuracy + ")");
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ Double directionNowPre = new Double(event.values[0]);
+
+ if (cg8 != null) {
+ final int rotation = cg8.getRotation();
+ if (rotation == Surface.ROTATION_90) directionNowPre = directionNowPre + 90;
+ else if (rotation == Surface.ROTATION_180) directionNowPre = directionNowPre + 180;
+ else if (rotation == Surface.ROTATION_270) directionNowPre = directionNowPre + 270;
+ } else {
+ final Display display = ((Activity)context).getWindowManager().getDefaultDisplay();
+ final int rotation = display.getOrientation();
+ if (rotation == Configuration.ORIENTATION_LANDSCAPE) directionNowPre = directionNowPre + 90;
+ }
+
+ directionNow = directionNowPre;
+
+ if (dirUpdate != null && directionNow != null) dirUpdate.updateDir(dir);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgDirectionImg.java b/src/cgeo/geocaching/cgDirectionImg.java
new file mode 100644
index 0000000..fdfc2c5
--- /dev/null
+++ b/src/cgeo/geocaching/cgDirectionImg.java
@@ -0,0 +1,96 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgDirectionImg {
+ private cgSettings settings = null;
+
+ public cgDirectionImg(cgSettings settingsIn) {
+ settings = settingsIn;
+ }
+
+ public void getDrawable(String geocode, String code) {
+ String dirName;
+ String fileName;
+
+ if (geocode == null || geocode.length() == 0 || code == null || code.length() == 0) {
+ return;
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ dirName = settings.getStorage() + geocode + "/";
+ fileName = settings.getStorage() + geocode + "/direction.png";
+ } else {
+ return;
+ }
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ boolean ok = false;
+
+ for (int i = 0; i < 3; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgDirectionImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet("http://www.geocaching.com/ImgGen/seek/CacheDir.ashx?k=" + code);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ Log.i(cgSettings.tag, "[" + entity.getContentLength() + "B] Downloading direction image " + code);
+
+ if (bufferedEntity != null) {
+ InputStream is = (InputStream)bufferedEntity.getContent();
+ FileOutputStream fos = new FileOutputStream(fileName);
+
+ try {
+ byte[] buffer = new byte[4096];
+ int l;
+ while ((l = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, l);
+ }
+ ok = true;
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgDirectionImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+ }
+
+ if (ok == true) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgDirectionImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgDistanceView.java b/src/cgeo/geocaching/cgDistanceView.java
new file mode 100644
index 0000000..9610e4f
--- /dev/null
+++ b/src/cgeo/geocaching/cgDistanceView.java
@@ -0,0 +1,45 @@
+package cgeo.geocaching;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+public class cgDistanceView extends TextView {
+ private cgBase base = null;
+ private Double cacheLat = null;
+ private Double cacheLon = null;
+
+ public cgDistanceView(Context context) {
+ super(context);
+ }
+
+ public cgDistanceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public cgDistanceView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setContent(cgBase baseIn, Double cacheLatIn, Double cacheLonIn) {
+ base = baseIn;
+ cacheLat = cacheLatIn;
+ cacheLon = cacheLonIn;
+ }
+
+ public void update(Double latitude, Double longitude) {
+ if (cacheLat == null || cacheLon == null) return;
+ if (latitude == null || longitude == null) return;
+ if (base == null) return;
+
+ setText(base.getHumanDistance(cgBase.getDistance(latitude, longitude, cacheLat, cacheLon)));
+ }
+
+ public void setDistance(Double distance) {
+ setText("~" + base.getHumanDistance(distance));
+ }
+
+ public void clear() {
+ setText(null);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgGPXListAdapter.java b/src/cgeo/geocaching/cgGPXListAdapter.java
new file mode 100644
index 0000000..78ad881
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXListAdapter.java
@@ -0,0 +1,75 @@
+package cgeo.geocaching;
+
+import java.util.List;
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.TextView;
+import android.widget.ArrayAdapter;
+import android.util.Log;
+import java.io.File;
+
+public class cgGPXListAdapter extends ArrayAdapter<File> {
+ private cgGPXView holder = null;
+ private cgeogpxes parent = null;
+ private cgSettings settings = null;
+ private LayoutInflater inflater = null;
+
+ public cgGPXListAdapter(cgeogpxes parentIn, cgSettings settingsIn, List<File> listIn) {
+ super(parentIn, 0, listIn);
+
+ parent = parentIn;
+ settings = settingsIn;
+ }
+
+ @Override
+ public View getView(int position, View rowView, ViewGroup parent) {
+ if (inflater == null) inflater = ((Activity)getContext()).getLayoutInflater();
+
+ if (position > getCount()) {
+ Log.w(cgSettings.tag, "cgGPXListAdapter.getView: Attempt to access missing item #" + position);
+ return null;
+ }
+
+ File file = getItem(position);
+
+ if (rowView == null) {
+ rowView = (View)inflater.inflate(R.layout.gpx_item, null);
+
+ holder = new cgGPXView();
+ holder.filepath = (TextView)rowView.findViewById(R.id.filepath);
+ holder.filename = (TextView)rowView.findViewById(R.id.filename);
+
+ rowView.setTag(holder);
+ } else {
+ holder = (cgGPXView)rowView.getTag();
+ }
+
+ final touchListener touchLst = new touchListener(file);
+ rowView.setOnClickListener(touchLst);
+
+ holder.filepath.setText(file.getParent());
+ holder.filename.setText(file.getName());
+
+ return rowView;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ }
+
+ private class touchListener implements View.OnClickListener {
+ private File file = null;
+
+ public touchListener(File fileIn) {
+ file = fileIn;
+ }
+
+ // tap on item
+ public void onClick(View view) {
+ parent.loadGPX(file);
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgGPXParser.java b/src/cgeo/geocaching/cgGPXParser.java
new file mode 100644
index 0000000..a4b1961
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXParser.java
@@ -0,0 +1,547 @@
+package cgeo.geocaching;
+
+import android.os.Handler;
+import android.os.Message;
+import android.sax.Element;
+import android.sax.EndElementListener;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.text.Html;
+import android.util.Log;
+import android.util.Xml;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.xml.sax.Attributes;
+
+public class cgGPXParser {
+
+ private cgeoapplication app = null;
+ private cgBase base = null;
+ private int listId = 1;
+ private cgSearch search = null;
+ private Handler handler = null;
+ private cgCache cache = new cgCache();
+ private cgTrackable trackable = new cgTrackable();
+ private cgLog log = new cgLog();
+ private boolean htmlShort = true;
+ private boolean htmlLong = true;
+ private String type = null;
+ private String sym = null;
+ private String ns = null;
+ private ArrayList<String> nsGCList = new ArrayList<String>();
+ private final Pattern patternGeocode = Pattern.compile("(GC[0-9A-Z]+)", Pattern.CASE_INSENSITIVE);
+ private String name = null;
+ private String cmt = null;
+ private String desc = null;
+
+ public cgGPXParser(cgeoapplication appIn, cgBase baseIn, int listIdIn, cgSearch searchIn) {
+ app = appIn;
+ base = baseIn;
+ listId = listIdIn;
+ search = searchIn;
+
+ nsGCList.add("http://www.groundspeak.com/cache/1/1"); // PQ 1.1
+ nsGCList.add("http://www.groundspeak.com/cache/1/0/1"); // PQ 1.0.1
+ nsGCList.add("http://www.groundspeak.com/cache/1/0"); // PQ 1.0
+ }
+
+ public long parse(File file, int version, Handler handlerIn) {
+ handler = handlerIn;
+ if (file == null) {
+ return 0l;
+ }
+
+ if (version == 11) {
+ ns = "http://www.topografix.com/GPX/1/1"; // GPX 1.1
+ } else {
+ ns = "http://www.topografix.com/GPX/1/0"; // GPX 1.0
+ }
+ final RootElement root = new RootElement(ns, "gpx");
+ final Element waypoint = root.getChild(ns, "wpt");
+
+ // waypoint - attributes
+ waypoint.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("lat") > -1) {
+ cache.latitude = new Double(attrs.getValue("lat"));
+ }
+ if (attrs.getIndex("lon") > -1) {
+ cache.longitude = new Double(attrs.getValue("lon"));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse waypoint's latitude and/or longitude.");
+ }
+ }
+ });
+
+ // waypoint
+ waypoint.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (cache.geocode == null || cache.geocode.length() == 0) {
+ // try to find geocode somewhere else
+ String geocode = null;
+ Matcher matcherGeocode = null;
+
+ if (name != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(name);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (desc != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(desc);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (cmt != null && geocode == null) {
+ matcherGeocode = patternGeocode.matcher(cmt);
+ while (matcherGeocode.find()) {
+ if (matcherGeocode.groupCount() > 0) {
+ geocode = matcherGeocode.group(1);
+ }
+ }
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ cache.geocode = geocode;
+ }
+
+ geocode = null;
+ matcherGeocode = null;
+ }
+
+ if (cache.geocode != null && cache.geocode.length() > 0
+ && cache.latitude != null && cache.longitude != null
+ && ((type == null && sym == null)
+ || (type != null && type.indexOf("geocache") > -1)
+ || (sym != null && sym.indexOf("geocache") > -1))) {
+ cache.latitudeString = base.formatCoordinate(cache.latitude, "lat", true);
+ cache.longitudeString = base.formatCoordinate(cache.longitude, "lon", true);
+ if (cache.inventory != null) {
+ cache.inventoryItems = cache.inventory.size();
+ } else {
+ cache.inventoryItems = 0;
+ }
+ cache.reason = listId;
+ cache.updated = new Date().getTime();
+ cache.detailedUpdate = new Date().getTime();
+ cache.detailed = true;
+
+ app.addCacheToSearch(search, cache);
+ }
+
+ if (handler != null) {
+ final Message msg = new Message();
+ msg.obj = search.getCount();
+ handler.sendMessage(msg);
+ }
+
+ htmlShort = true;
+ htmlLong = true;
+ type = null;
+ sym = null;
+ name = null;
+ desc = null;
+ cmt = null;
+
+ cache = null;
+ cache = new cgCache();
+ }
+ });
+
+ // waypoint.time
+ waypoint.getChild(ns, "time").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.hidden = cgBase.dateGPXIn.parse(body.trim());
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse cache date: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.name
+ waypoint.getChild(ns, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ name = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.name = content;
+ if (cache.name.length() > 2 && cache.name.substring(0, 2).equalsIgnoreCase("GC") == true) {
+ cache.geocode = cache.name.toUpperCase();
+ }
+ }
+ });
+
+ // waypoint.desc
+ waypoint.getChild(ns, "desc").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ desc = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.shortdesc = content;
+ }
+ });
+
+ // waypoint.cmt
+ waypoint.getChild(ns, "cmt").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ cmt = body;
+
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.description = content;
+ }
+ });
+
+ // waypoint.type
+ waypoint.getChild(ns, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String[] content = body.split("\\|");
+ if (content.length > 0) {
+ type = content[0].toLowerCase().trim();
+ }
+ }
+ });
+
+ // waypoint.sym
+ waypoint.getChild(ns, "sym").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ body = body.toLowerCase();
+ sym = body;
+ if (body.indexOf("geocache") != -1 && body.indexOf("found") != -1) {
+ cache.found = true;
+ }
+ }
+ });
+
+ for (String nsGC : nsGCList) {
+ // waypoints.cache
+ final Element gcCache = waypoint.getChild(nsGC, "cache");
+
+ gcCache.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("id") > -1) {
+ cache.cacheid = attrs.getValue("id");
+ }
+ if (attrs.getIndex("archived") > -1) {
+ final String at = attrs.getValue("archived").toLowerCase();
+ if (at.equals("true")) {
+ cache.archived = true;
+ } else {
+ cache.archived = false;
+ }
+ }
+ if (attrs.getIndex("available") > -1) {
+ final String at = attrs.getValue("available").toLowerCase();
+ if (at.equals("true")) {
+ cache.disabled = false;
+ } else {
+ cache.disabled = true;
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse cache attributes.");
+ }
+ }
+ });
+
+ // waypoint.cache.name
+ gcCache.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.name = content;
+ }
+ });
+
+ // waypoint.cache.owner
+ gcCache.getChild(nsGC, "owner").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = Html.fromHtml(body).toString().trim();
+ cache.owner = content;
+ }
+ });
+
+ // waypoint.cache.type
+ gcCache.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = cgBase.cacheTypes.get(body.toLowerCase());
+ cache.type = content;
+ }
+ });
+
+ // waypoint.cache.container
+ gcCache.getChild(nsGC, "container").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = body.toLowerCase();
+ cache.size = content;
+ }
+ });
+
+ // waypoint.cache.difficulty
+ gcCache.getChild(nsGC, "difficulty").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.difficulty = new Float(body);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse difficulty: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.terrain
+ gcCache.getChild(nsGC, "terrain").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ cache.terrain = new Float(body);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse terrain: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.country
+ gcCache.getChild(nsGC, "country").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (cache.location == null || cache.location.length() == 0) {
+ cache.location = body.trim();
+ } else {
+ cache.location = cache.location + ", " + body.trim();
+ }
+ }
+ });
+
+ // waypoint.cache.state
+ gcCache.getChild(nsGC, "state").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (cache.location == null || cache.location.length() == 0) {
+ cache.location = body.trim();
+ } else {
+ cache.location = body.trim() + ", " + cache.location;
+ }
+ }
+ });
+
+ // waypoint.cache.encoded_hints
+ gcCache.getChild(nsGC, "encoded_hints").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ cache.hint = body.trim();
+ }
+ });
+
+ // waypoint.cache.short_description
+ gcCache.getChild(nsGC, "short_description").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("html") > -1) {
+ final String at = attrs.getValue("html").toLowerCase();
+ if (at.equals("false")) {
+ htmlShort = false;
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcCache.getChild(nsGC, "short_description").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (htmlShort == false) {
+ cache.shortdesc = Html.fromHtml(body).toString();
+ } else {
+ cache.shortdesc = body;
+ }
+ }
+ });
+
+ // waypoint.cache.long_description
+ gcCache.getChild(nsGC, "long_description").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ try {
+ if (attrs.getIndex("html") > -1) {
+ final String at = attrs.getValue("html").toLowerCase();
+ if (at.equals("false")) {
+ htmlLong = false;
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcCache.getChild(nsGC, "long_description").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ if (htmlLong == false) {
+ cache.description = Html.fromHtml(body).toString().trim();
+ } else {
+ cache.description = body;
+ }
+ }
+ });
+
+ // waypoint.cache.travelbugs
+ final Element gcTBs = gcCache.getChild(nsGC, "travelbugs");
+
+ // waypoint.cache.travelbugs.travelbug
+ gcTBs.getChild(nsGC, "travelbug").setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ trackable = new cgTrackable();
+
+ try {
+ if (attrs.getIndex("ref") > -1) {
+ trackable.geocode = attrs.getValue("ref").toUpperCase();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ // waypoint.cache.travelbug
+ final Element gcTB = gcTBs.getChild(nsGC, "travelbug");
+
+ gcTB.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (trackable.geocode != null && trackable.geocode.length() > 0 && trackable.name != null && trackable.name.length() > 0) {
+ if (cache.inventory == null)
+ cache.inventory = new ArrayList<cgTrackable>();
+ cache.inventory.add(trackable);
+ }
+ }
+ });
+
+ // waypoint.cache.travelbugs.travelbug.name
+ gcTB.getChild(nsGC, "name").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ trackable.name = content;
+ }
+ });
+
+ // waypoint.cache.logs
+ final Element gcLogs = gcCache.getChild(nsGC, "logs");
+
+ // waypoint.cache.log
+ final Element gcLog = gcLogs.getChild(nsGC, "log");
+
+ gcLog.setStartElementListener(new StartElementListener() {
+
+ public void start(Attributes attrs) {
+ log = new cgLog();
+
+ try {
+ if (attrs.getIndex("id") > -1) {
+ log.id = Integer.parseInt(attrs.getValue("id"));
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ });
+
+ gcLog.setEndElementListener(new EndElementListener() {
+
+ public void end() {
+ if (log.log != null && log.log.length() > 0) {
+ if (cache.logs == null)
+ cache.logs = new ArrayList<cgLog>();
+ cache.logs.add(log);
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.date
+ gcLog.getChild(nsGC, "date").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ try {
+ log.date = cgBase.dateGPXIn.parse(body.trim()).getTime();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to parse log date: " + e.toString());
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.type
+ gcLog.getChild(nsGC, "type").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ final String content = body.trim().toLowerCase();
+ if (cgBase.logTypes0.containsKey(content) == true) {
+ log.type = cgBase.logTypes0.get(content);
+ } else {
+ log.type = 4;
+ }
+ }
+ });
+
+ // waypoint.cache.logs.log.finder
+ gcLog.getChild(nsGC, "finder").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ log.author = content;
+ }
+ });
+
+ // waypoint.cache.logs.log.finder
+ gcLog.getChild(nsGC, "text").setEndTextElementListener(new EndTextElementListener() {
+
+ public void end(String body) {
+ String content = Html.fromHtml(body).toString();
+ log.log = content;
+ }
+ });
+ }
+
+ try {
+ Xml.parse(new FileInputStream(file), Xml.Encoding.UTF_8, root.getContentHandler());
+
+ return search.getCurrentId();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "Cannot parse .gpx file " + file.getAbsolutePath() + " as GPX " + version + ": " + e.toString());
+ }
+
+ return 0l;
+ }
+}
diff --git a/src/cgeo/geocaching/cgGPXView.java b/src/cgeo/geocaching/cgGPXView.java
new file mode 100644
index 0000000..f68b477
--- /dev/null
+++ b/src/cgeo/geocaching/cgGPXView.java
@@ -0,0 +1,9 @@
+package cgeo.geocaching;
+
+import android.widget.TextView;
+
+public class cgGPXView {
+ // layouts & views
+ public TextView filepath;
+ public TextView filename;
+}
diff --git a/src/cgeo/geocaching/cgGeo.java b/src/cgeo/geocaching/cgGeo.java
new file mode 100644
index 0000000..95c0b9d
--- /dev/null
+++ b/src/cgeo/geocaching/cgGeo.java
@@ -0,0 +1,445 @@
+package cgeo.geocaching;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.location.GpsSatellite;
+import android.location.GpsStatus;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+
+public class cgGeo {
+
+ private Context context = null;
+ private cgeoapplication app = null;
+ private LocationManager geoManager = null;
+ private cgUpdateLoc geoUpdate = null;
+ private cgWarning warning = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgeoGeoListener geoNetListener = null;
+ private cgeoGeoListener geoGpsListener = null;
+ private cgeoGpsStatusListener geoGpsStatusListener = null;
+ private Integer time = 0;
+ private Integer distance = 0;
+ private Location locGps = null;
+ private Location locNet = null;
+ private long locGpsLast = 0l;
+ private boolean g4cRunning = false;
+ private Double lastGo4cacheLat = null;
+ private Double lastGo4cacheLon = null;
+ public Location location = null;
+ public int gps = -1;
+ public Double latitudeNow = null;
+ public Double longitudeNow = null;
+ public Double latitudeBefore = null;
+ public Double longitudeBefore = null;
+ public Double altitudeNow = null;
+ public Double bearingNow = null;
+ public Float speedNow = null;
+ public Float accuracyNow = null;
+ public Integer satellitesVisible = null;
+ public Integer satellitesFixed = null;
+ public double distanceNow = 0d;
+
+ public cgGeo(Context contextIn, cgeoapplication appIn, cgUpdateLoc geoUpdateIn, cgBase baseIn, cgSettings settingsIn, cgWarning warningIn, int timeIn, int distanceIn) {
+ context = contextIn;
+ app = appIn;
+ geoUpdate = geoUpdateIn;
+ base = baseIn;
+ settings = settingsIn;
+ warning = warningIn;
+ time = timeIn;
+ distance = distanceIn;
+
+ if (prefs == null) {
+ prefs = context.getSharedPreferences(cgSettings.preferences, 0);
+ }
+ distanceNow = prefs.getFloat("dst", 0f);
+ if (Double.isNaN(distanceNow) == true) {
+ distanceNow = 0d;
+ }
+ if (distanceNow == 0f) {
+ final SharedPreferences.Editor prefsEdit = context.getSharedPreferences(cgSettings.preferences, 0).edit();
+ if (prefsEdit != null) {
+ prefsEdit.putLong("dst-since", System.currentTimeMillis());
+ prefsEdit.commit();
+ }
+ }
+
+ geoNetListener = new cgeoGeoListener();
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+
+ geoGpsListener = new cgeoGeoListener();
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+
+ geoGpsStatusListener = new cgeoGpsStatusListener();
+ }
+
+ public void initGeo() {
+ location = null;
+ gps = -1;
+ latitudeNow = null;
+ longitudeNow = null;
+ altitudeNow = null;
+ bearingNow = null;
+ speedNow = null;
+ accuracyNow = null;
+ satellitesVisible = 0;
+ satellitesFixed = 0;
+
+ if (geoManager == null) {
+ geoManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ lastLoc();
+
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+ geoManager.addGpsStatusListener(geoGpsStatusListener);
+
+ try {
+ geoManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, time, distance, geoNetListener);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "There is no NETWORK location provider");
+ }
+
+ try {
+ geoManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, time, distance, geoGpsListener);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "There is no GPS location provider");
+ }
+ }
+
+ public void closeGeo() {
+ if (geoManager != null && geoNetListener != null) {
+ geoManager.removeUpdates(geoNetListener);
+ }
+ if (geoManager != null && geoGpsListener != null) {
+ geoManager.removeUpdates(geoGpsListener);
+ }
+ if (geoManager != null) {
+ geoManager.removeGpsStatusListener(geoGpsStatusListener);
+ }
+
+ final SharedPreferences.Editor prefsEdit = context.getSharedPreferences(cgSettings.preferences, 0).edit();
+ if (prefsEdit != null && Double.isNaN(distanceNow) == false) {
+ prefsEdit.putFloat("dst", (float) distanceNow);
+ prefsEdit.commit();
+ }
+ }
+
+ public void replaceUpdate(cgUpdateLoc geoUpdateIn) {
+ geoUpdate = geoUpdateIn;
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+ }
+
+ public class cgeoGeoListener implements LocationListener {
+
+ public String active = null;
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // nothing
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location.getProvider().equals(LocationManager.GPS_PROVIDER) == true) {
+ locGps = location;
+ locGpsLast = System.currentTimeMillis();
+ } else if (location.getProvider().equals(LocationManager.NETWORK_PROVIDER) == true) {
+ locNet = location;
+ }
+
+ selectBest(location.getProvider());
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoManager != null && geoNetListener != null) {
+ geoManager.removeUpdates(geoNetListener);
+ }
+ } else if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoManager != null && geoGpsListener != null) {
+ geoManager.removeUpdates(geoGpsListener);
+ }
+ }
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoNetListener == null) {
+ geoNetListener = new cgeoGeoListener();
+ }
+ geoNetListener.setProvider(LocationManager.NETWORK_PROVIDER);
+ } else if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoGpsListener == null) {
+ geoGpsListener = new cgeoGeoListener();
+ }
+ geoGpsListener.setProvider(LocationManager.GPS_PROVIDER);
+ }
+ }
+
+ public void setProvider(String provider) {
+ if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ if (geoManager != null && geoManager.isProviderEnabled(LocationManager.GPS_PROVIDER) == true) {
+ active = provider;
+ } else {
+ active = null;
+ }
+ } else if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ if (geoManager != null && geoManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true) {
+ active = provider;
+ } else {
+ active = null;
+ }
+ }
+ }
+ }
+
+ public class cgeoGpsStatusListener implements GpsStatus.Listener {
+
+ @Override
+ public void onGpsStatusChanged(int event) {
+ if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
+ GpsStatus status = geoManager.getGpsStatus(null);
+ Iterator<GpsSatellite> statusIterator = status.getSatellites().iterator();
+
+ int satellites = 0;
+ int fixed = 0;
+
+ while (statusIterator.hasNext()) {
+ GpsSatellite sat = statusIterator.next();
+ if (sat.usedInFix() == true) {
+ fixed++;
+ }
+ satellites++;
+
+ /* satellite signal strength
+ if (sat.usedInFix()) {
+ Log.d(cgSettings.tag, "Sat #" + satellites + ": " + sat.getSnr() + " FIX");
+ } else {
+ Log.d(cgSettings.tag, "Sat #" + satellites + ": " + sat.getSnr());
+ }
+ */
+ }
+
+ boolean changed = false;
+ if (satellitesVisible == null || satellites != satellitesVisible) {
+ satellitesVisible = satellites;
+ changed = true;
+ }
+ if (satellitesFixed == null || fixed != satellitesFixed) {
+ satellitesFixed = fixed;
+ changed = true;
+ }
+
+ if (changed == true) {
+ selectBest(null);
+ }
+ }
+ }
+ }
+
+ private void selectBest(String initProvider) {
+ if (locNet == null && locGps != null) { // we have only GPS
+ assign(locGps);
+ return;
+ }
+
+ if (locNet != null && locGps == null) { // we have only NET
+ assign(locNet);
+ return;
+ }
+
+ if (satellitesFixed > 0) { // GPS seems to be fixed
+ assign(locGps);
+ return;
+ }
+
+ if (initProvider != null && initProvider.equals(LocationManager.GPS_PROVIDER) == true) { // we have new location from GPS
+ assign(locGps);
+ return;
+ }
+
+ if (locGpsLast > (System.currentTimeMillis() - 30 * 1000)) { // GPS was working in last 30 seconds
+ assign(locGps);
+ return;
+ }
+
+ assign(locNet); // nothing else, using NET
+ }
+
+ private void assign(Double lat, Double lon) {
+ if (lat == null || lon == null) {
+ return;
+ }
+
+ gps = -1;
+ latitudeNow = lat;
+ longitudeNow = lon;
+ altitudeNow = null;
+ bearingNow = new Double(0);
+ speedNow = 0f;
+ accuracyNow = 999f;
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+ }
+
+ private void assign(Location loc) {
+ if (loc == null) {
+ gps = -1;
+ return;
+ }
+
+ location = loc;
+
+ String provider = location.getProvider();
+ if (provider.equals(LocationManager.GPS_PROVIDER) == true) {
+ gps = 1;
+ } else if (provider.equals(LocationManager.NETWORK_PROVIDER) == true) {
+ gps = 0;
+ } else if (provider.equals("last") == true) {
+ gps = -1;
+ }
+
+ latitudeNow = location.getLatitude();
+ longitudeNow = location.getLongitude();
+ app.setLastLoc(latitudeNow, longitudeNow);
+
+ if (location.hasAltitude() && gps != -1) {
+ altitudeNow = location.getAltitude() + settings.altCorrection;
+ } else {
+ altitudeNow = null;
+ }
+ if (location.hasBearing() && gps != -1) {
+ bearingNow = new Double(location.getBearing());
+ } else {
+ bearingNow = new Double(0);
+ }
+ if (location.hasSpeed() && gps != -1) {
+ speedNow = location.getSpeed();
+ } else {
+ speedNow = 0f;
+ }
+ if (location.hasAccuracy() && gps != -1) {
+ accuracyNow = location.getAccuracy();
+ } else {
+ accuracyNow = 999f;
+ }
+
+ if (gps == 1) {
+ // save travelled distance only when location is from GPS
+ if (latitudeBefore != null && longitudeBefore != null && latitudeNow != null && longitudeNow != null) {
+ final double dst = cgBase.getDistance(latitudeBefore, longitudeBefore, latitudeNow, longitudeNow);
+
+ if (Double.isNaN(dst) == false && dst > 0.005) {
+ distanceNow += dst;
+
+ latitudeBefore = latitudeNow;
+ longitudeBefore = longitudeNow;
+ }
+ } else if (latitudeBefore == null || longitudeBefore == null) { // values aren't initialized
+ latitudeBefore = latitudeNow;
+ longitudeBefore = longitudeNow;
+ }
+ }
+
+ if (geoUpdate != null) {
+ geoUpdate.updateLoc(this);
+ }
+
+ if (gps > -1) {
+ (new publishLoc()).start();
+ }
+ }
+
+ private class publishLoc extends Thread {
+
+ private publishLoc() {
+ setPriority(Thread.MIN_PRIORITY);
+ }
+
+ @Override
+ public void run() {
+ if (g4cRunning == true) {
+ return;
+ }
+
+ if (settings.publicLoc == 1 && (lastGo4cacheLat == null || lastGo4cacheLon == null || cgBase.getDistance(latitudeNow, longitudeNow, lastGo4cacheLat, lastGo4cacheLon) > 0.75)) {
+ g4cRunning = true;
+
+ final String host = "api.go4cache.com";
+ final String path = "/";
+ final String method = "POST";
+ String action = null;
+ if (app != null) {
+ action = app.getAction();
+ } else {
+ action = "";
+ }
+
+ final String username = settings.getUsername();
+ if (username != null) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ final String latStr = String.format((Locale) null, "%.6f", latitudeNow);
+ final String lonStr = String.format((Locale) null, "%.6f", longitudeNow);
+ params.put("u", username);
+ params.put("lt", latStr);
+ params.put("ln", lonStr);
+ params.put("a", action);
+ params.put("s", (cgBase.sha1(username + "|" + latStr + "|" + lonStr + "|" + action + "|" + cgBase.md5("carnero: developing your dreams"))).toLowerCase());
+ if (base.version != null) {
+ params.put("v", base.version);
+ }
+ final String res = base.request(false, host, path, method, params, false, false, false).getData();
+
+ if (res != null && res.length() > 0) {
+ lastGo4cacheLat = latitudeNow;
+ lastGo4cacheLon = longitudeNow;
+ }
+ }
+ }
+
+ g4cRunning = false;
+ }
+ }
+
+ public void lastLoc() {
+ assign(app.getLastLat(), app.getLastLon());
+
+ Location lastGps = geoManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+
+ if (lastGps != null) {
+ lastGps.setProvider("last");
+ assign(lastGps);
+
+ Log.i(cgSettings.tag, "Using last location from GPS");
+ return;
+ }
+
+ Location lastGsm = geoManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+
+ if (lastGsm != null) {
+ lastGsm.setProvider("last");
+ assign(lastGsm);
+
+ Log.i(cgSettings.tag, "Using last location from NETWORK");
+ return;
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgHtmlImg.java b/src/cgeo/geocaching/cgHtmlImg.java
new file mode 100644
index 0000000..023912a
--- /dev/null
+++ b/src/cgeo/geocaching/cgHtmlImg.java
@@ -0,0 +1,286 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.util.Log;
+import android.text.Html;
+import android.view.Display;
+import android.view.WindowManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgHtmlImg implements Html.ImageGetter {
+
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private String geocode = null;
+ private boolean placement = true;
+ private int reason = 0;
+ private boolean onlySave = false;
+ private BitmapFactory.Options bfOptions = new BitmapFactory.Options();
+ private Display display = null;
+ private int maxWidth = 0;
+ private int maxHeight = 0;
+ private double ratio = 1.0d;
+ private int width = 0;
+ private int height = 0;
+
+ public cgHtmlImg(Activity activityIn, cgSettings settingsIn, String geocodeIn, boolean placementIn, int reasonIn, boolean onlySaveIn) {
+ activity = activityIn;
+ settings = settingsIn;
+ geocode = geocodeIn;
+ placement = placementIn;
+ reason = reasonIn;
+ onlySave = onlySaveIn;
+
+ bfOptions.inTempStorage = new byte[16 * 1024];
+
+ display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+ maxWidth = display.getWidth() - 25;
+ maxHeight = display.getHeight() - 25;
+ }
+
+ @Override
+ public BitmapDrawable getDrawable(String url) {
+ Bitmap imagePre = null;
+ String dirName = null;
+ String fileName = null;
+ String fileNameSec = null;
+
+ if (url == null || url.length() == 0) {
+ return null;
+ }
+
+ final String[] urlParts = url.split("\\.");
+ String urlExt = null;
+ if (urlParts.length > 1) {
+ urlExt = "." + urlParts[(urlParts.length - 1)];
+ if (urlExt.length() > 5) {
+ urlExt = "";
+ }
+ } else {
+ urlExt = "";
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ dirName = settings.getStorage() + geocode + "/";
+ fileName = settings.getStorage() + geocode + "/" + cgBase.md5(url) + urlExt;
+ fileNameSec = settings.getStorageSec() + geocode + "/" + cgBase.md5(url) + urlExt;
+ } else {
+ dirName = settings.getStorage() + "_others/";
+ fileName = settings.getStorage() + "_others/" + cgBase.md5(url) + urlExt;
+ fileNameSec = settings.getStorageSec() + "_others/" + cgBase.md5(url) + urlExt;
+ }
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+
+ // load image from cache
+ if (onlySave == false) {
+ try {
+ final Date now = new Date();
+
+ final File file = new File(fileName);
+ if (file.exists() == true) {
+ final long imageSize = file.length();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (reason > 0 || file.lastModified() > (now.getTime() - (24 * 60 * 60 * 1000))) {
+ imagePre = BitmapFactory.decodeFile(fileName, bfOptions);
+ }
+ }
+
+ if (imagePre == null) {
+ final File fileSec = new File(fileNameSec);
+ if (fileSec.exists() == true) {
+ final long imageSize = fileSec.length();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (reason > 0 || file.lastModified() > (now.getTime() - (24 * 60 * 60 * 1000))) {
+ imagePre = BitmapFactory.decodeFile(fileNameSec, bfOptions);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgHtmlImg.getDrawable (reading cache): " + e.toString());
+ }
+ }
+
+ // download image and save it to the cache
+ if ((imagePre == null && reason == 0) || onlySave == true) {
+ Uri uri = null;
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ try {
+ // check if uri is absolute or not, if not attach geocaching.com hostname and scheme
+ uri = Uri.parse(url);
+
+ if (uri.isAbsolute() == false) {
+ url = "http://www.geocaching.com" + url;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (parse URL): " + e.toString());
+ }
+
+ if (uri != null) {
+ for (int i = 0; i < 2; i++) {
+ if (i > 0) {
+ Log.w(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+ }
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+ bufferedEntity = new BufferedHttpEntity(entity);
+
+ final long imageSize = bufferedEntity.getContentLength();
+
+ // large images will be downscaled on input to save memory
+ if (imageSize > (6 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 48;
+ } else if (imageSize > (4 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 16;
+ } else if (imageSize > (2 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 10;
+ } else if (imageSize > (1 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 6;
+ } else if (imageSize > (0.5 * 1024 * 1024)) {
+ bfOptions.inSampleSize = 2;
+ }
+
+ if (bufferedEntity != null) {
+ imagePre = BitmapFactory.decodeStream(bufferedEntity.getContent(), null, bfOptions);
+ }
+ if (imagePre != null) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+
+ try {
+ // save to memory/SD cache
+ if (bufferedEntity != null) {
+ final InputStream is = (InputStream) bufferedEntity.getContent();
+ final FileOutputStream fos = new FileOutputStream(fileName);
+ try {
+ final byte[] buffer = new byte[4096];
+ int l;
+ while ((l = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, l);
+ }
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (saving to cache): " + e.toString());
+ }
+
+ entity = null;
+ bufferedEntity = null;
+ }
+
+ if (onlySave == true) {
+ return null;
+ }
+
+ // get image and return
+ if (imagePre == null) {
+ Log.d(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to obtain image");
+
+ if (placement == false) {
+ imagePre = BitmapFactory.decodeResource(activity.getResources(), R.drawable.image_no_placement);
+ } else {
+ imagePre = BitmapFactory.decodeResource(activity.getResources(), R.drawable.image_not_loaded);
+ }
+ }
+
+ final int imgWidth = imagePre.getWidth();
+ final int imgHeight = imagePre.getHeight();
+
+ if (imgWidth > maxWidth || imgHeight > maxHeight) {
+ if ((maxWidth / imgWidth) > (maxHeight / imgHeight)) {
+ ratio = (double) maxHeight / (double) imgHeight;
+ } else {
+ ratio = (double) maxWidth / (double) imgWidth;
+ }
+
+ width = (int) Math.ceil(imgWidth * ratio);
+ height = (int) Math.ceil(imgHeight * ratio);
+
+ try {
+ imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true);
+ } catch (Exception e) {
+ Log.d(cgSettings.tag, "cgHtmlImg.getDrawable: Failed to scale image");
+ return null;
+ }
+ } else {
+ width = imgWidth;
+ height = imgHeight;
+ }
+
+ final BitmapDrawable image = new BitmapDrawable(imagePre);
+ image.setBounds(new Rect(0, 0, width, height));
+
+ return image;
+ }
+}
diff --git a/src/cgeo/geocaching/cgList.java b/src/cgeo/geocaching/cgList.java
new file mode 100644
index 0000000..65d08ac
--- /dev/null
+++ b/src/cgeo/geocaching/cgList.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching;
+
+public class cgList {
+ public boolean def = false;
+ public int id = 0;
+ public String title = null;
+ public Long updated = null;
+ public Double latitude = null;
+ public Double longitude = null;
+
+ public cgList(boolean defIn) {
+ def = defIn;
+ }
+
+ public cgList(boolean defIn, int idIn, String titleIn) {
+ def = defIn;
+ id = idIn;
+ title = titleIn;
+ }
+}
diff --git a/src/cgeo/geocaching/cgLog.java b/src/cgeo/geocaching/cgLog.java
new file mode 100644
index 0000000..5b1b44a
--- /dev/null
+++ b/src/cgeo/geocaching/cgLog.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+public class cgLog {
+ public int id = 0;
+ public int type = 4; // note
+ public String author = "";
+ public String log = "";
+ public long date = 0;
+ public int found = -1;
+ public String cacheName = ""; // used for trackables
+ public String cacheGuid = ""; // used for trackables
+}
diff --git a/src/cgeo/geocaching/cgLogForm.java b/src/cgeo/geocaching/cgLogForm.java
new file mode 100644
index 0000000..9cbd557
--- /dev/null
+++ b/src/cgeo/geocaching/cgLogForm.java
@@ -0,0 +1,10 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import java.util.Calendar;
+
+public class cgLogForm extends Activity {
+ public void setDate(Calendar dateIn) {
+ // to be overwritten
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgMapImg.java b/src/cgeo/geocaching/cgMapImg.java
new file mode 100644
index 0000000..57639ff
--- /dev/null
+++ b/src/cgeo/geocaching/cgMapImg.java
@@ -0,0 +1,114 @@
+package cgeo.geocaching;
+
+import android.util.Log;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+public class cgMapImg {
+ /**
+ * in my tests the "no image available" image had 5470 bytes, while "street only" maps had at least 20000 bytes
+ */
+ private static final int MIN_MAP_IMAGE_BYTES = 6000;
+ private cgSettings settings = null;
+ private String geocode = null;
+
+ public cgMapImg(cgSettings settingsIn, String geocodeIn) {
+ geocode = geocodeIn;
+ settings = settingsIn;
+
+ if (geocode != null && geocode.length() > 0) {
+ final String dirName = settings.getStorage() + geocode + "/";
+
+ File dir = null;
+ dir = new File(settings.getStorage());
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = new File(dirName);
+ if (dir.exists() == false) {
+ dir.mkdirs();
+ }
+ dir = null;
+ }
+ }
+
+ public void getDrawable(String url, int level) {
+ if (url == null || url.length() == 0) {
+ return;
+ }
+
+ if (geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ final String fileName = settings.getStorage() + geocode + "/map_" + level;
+ HttpClient client = null;
+ HttpGet getMethod = null;
+ HttpResponse httpResponse = null;
+ HttpEntity entity = null;
+ BufferedHttpEntity bufferedEntity = null;
+
+ boolean ok = false;
+
+ for (int i = 0; i < 3; i ++) {
+ if (i > 0) Log.w(cgSettings.tag, "cgMapImg.getDrawable: Failed to download data, retrying. Attempt #" + (i + 1));
+
+ try {
+ client = new DefaultHttpClient();
+ getMethod = new HttpGet(url);
+ httpResponse = client.execute(getMethod);
+ entity = httpResponse.getEntity();
+
+ // if image is to small, don't download and save, there is no map data for this zoom level
+ long contentSize = entity.getContentLength();
+ if (contentSize > 0 && contentSize <= MIN_MAP_IMAGE_BYTES) {
+ break;
+ }
+
+ bufferedEntity = new BufferedHttpEntity(entity);
+ if (bufferedEntity != null) {
+ InputStream is = (InputStream)bufferedEntity.getContent();
+ FileOutputStream fos = new FileOutputStream(fileName);
+
+ int fileSize = 0;
+ try {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) != -1) {
+ fos.write(buffer, 0, bytesRead);
+ fileSize += bytesRead;
+ }
+ ok = true;
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "cgMapImg.getDrawable (saving to cache): " + e.toString());
+ } finally {
+ is.close();
+ fos.flush();
+ fos.close();
+ }
+
+ bufferedEntity = null;
+
+ // delete image if it has no contents
+ if (ok && fileSize < MIN_MAP_IMAGE_BYTES) {
+ (new File(fileName)).delete();
+ }
+ }
+
+ if (ok == true) {
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapImg.getDrawable (downloading from web): " + e.toString());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgOAuth.java b/src/cgeo/geocaching/cgOAuth.java
new file mode 100644
index 0000000..8897993
--- /dev/null
+++ b/src/cgeo/geocaching/cgOAuth.java
@@ -0,0 +1,53 @@
+package cgeo.geocaching;
+
+import java.util.Date;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class cgOAuth {
+ public static String signOAuth(String host, String path, String method, boolean https, HashMap<String, String> params, String token, String tokenSecret) {
+ String paramsDone = "";
+ if (method.equalsIgnoreCase("GET") == false && method.equalsIgnoreCase("POST") == false) {
+ method = "POST";
+ } else {
+ method = method.toUpperCase();
+ }
+
+ if (token == null) token = "";
+ if (tokenSecret == null) tokenSecret = "";
+
+ long currentTime = new Date().getTime(); // miliseconds
+ currentTime = currentTime / 1000; // seconds
+ currentTime = (long)Math.floor(currentTime);
+
+ params.put("oauth_consumer_key", cgSettings.keyConsumerPublic);
+ params.put("oauth_nonce", cgBase.md5(Long.toString(System.currentTimeMillis())));
+ params.put("oauth_signature_method", "HMAC-SHA1");
+ params.put("oauth_timestamp", Long.toString(currentTime));
+ params.put("oauth_token", token);
+ params.put("oauth_version", "1.0");
+
+ Object[] keys = params.keySet().toArray();
+ Arrays.sort(keys);
+
+ ArrayList<String> paramsEncoded = new ArrayList<String>();
+ for (int i = 0; i < keys.length; i++) {
+ String value = params.get(keys[i].toString());
+
+ paramsEncoded.add(keys[i] + "=" + cgBase.urlencode_rfc3986(value.toString()));
+ }
+
+ String keysPacked;
+ String requestPacked;
+
+ keysPacked = cgSettings.keyConsumerSecret + "&" + tokenSecret; // both even if empty some of them!
+ if (https == true) requestPacked = method + "&" + cgBase.urlencode_rfc3986("https://" + host + path) + "&" + cgBase.urlencode_rfc3986(cgBase.implode("&", paramsEncoded.toArray()));
+ else requestPacked = method + "&" + cgBase.urlencode_rfc3986("http://" + host + path) + "&" + cgBase.urlencode_rfc3986(cgBase.implode("&", paramsEncoded.toArray()));
+ paramsEncoded.add("oauth_signature=" + cgBase.urlencode_rfc3986(cgBase.base64Encode(cgBase.hashHmac(requestPacked, keysPacked))));
+
+ paramsDone = cgBase.implode("&", paramsEncoded.toArray());
+
+ return paramsDone;
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgRating.java b/src/cgeo/geocaching/cgRating.java
new file mode 100644
index 0000000..374ae7c
--- /dev/null
+++ b/src/cgeo/geocaching/cgRating.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgRating {
+ public Float rating = null;
+ public Integer votes = null;
+ public Float myVote = null;
+}
diff --git a/src/cgeo/geocaching/cgResponse.java b/src/cgeo/geocaching/cgResponse.java
new file mode 100644
index 0000000..6735d85
--- /dev/null
+++ b/src/cgeo/geocaching/cgResponse.java
@@ -0,0 +1,40 @@
+package cgeo.geocaching;
+
+public class cgResponse {
+ private String url;
+ private int statusCode;
+ private String statusMessage;
+ private String data;
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setStatusCode(int code) {
+ statusCode = code;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusMessage(String message) {
+ statusMessage = message;
+ }
+
+ public String getStatusMessage() {
+ return statusMessage;
+ }
+
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ public String getData() {
+ return data;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearch.java b/src/cgeo/geocaching/cgSearch.java
new file mode 100644
index 0000000..a6638e5
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearch.java
@@ -0,0 +1,39 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+public class cgSearch {
+ private Long id = null;
+ private ArrayList<String> geocodes = new ArrayList<String>();
+
+ public int errorRetrieve = 0;
+ public String error = null;
+ public String url = "";
+ public String viewstate = "";
+ public String viewstate1 = "";
+ public int totalCnt = 0;
+
+ public cgSearch() {
+ id = System.currentTimeMillis(); // possible collisions here - not guaranteed to be unique
+ }
+
+ public Long getCurrentId() {
+ return id;
+ }
+
+ public ArrayList<String> getGeocodes() {
+ return geocodes;
+ }
+
+ public int getCount() {
+ return geocodes.size();
+ }
+
+ public void addGeocode(String geocode) {
+ if (geocodes == null) {
+ geocodes = new ArrayList<String>();
+ }
+
+ geocodes.add(geocode);
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearchHandler.java b/src/cgeo/geocaching/cgSearchHandler.java
new file mode 100644
index 0000000..3563c6d
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearchHandler.java
@@ -0,0 +1,104 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageView;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class cgSearchHandler extends Handler {
+ private Activity activity = null;
+ private Resources res = null;
+ private cgSearchThread recaptchaThread = null;
+ private ImageView imageView = null;
+ private Bitmap img = null;
+
+ private Handler imgHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (img != null && imageView != null) {
+ imageView.setImageBitmap(img);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ };
+
+ public cgSearchHandler(Activity activityIn, Resources resIn, cgSearchThread recaptchaThreadIn) {
+ activity = activityIn;
+ res = resIn;
+ recaptchaThread = recaptchaThreadIn;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (msg.what == 1) {
+ final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
+ final LayoutInflater inflater = activity.getLayoutInflater();
+ final View view = inflater.inflate(R.layout.recaptcha_dialog, null);
+
+ imageView = (ImageView) view.findViewById(R.id.image);
+
+ (new getCaptcha(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
+
+ dlg.setTitle(res.getString(R.string.caches_recaptcha_title));
+ dlg.setView(view);
+ dlg.setNeutralButton(res.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
+
+ recaptchaThread.setText(text);
+
+ dialog.cancel();
+ }
+ });
+
+ dlg.create().show();
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private class getCaptcha extends Thread {
+ private URL uri = null;
+
+ public getCaptcha(URL uriIn) {
+ uri = uriIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ HttpURLConnection connection = (HttpURLConnection)uri.openConnection();
+ connection.setDoInput(true);
+ connection.connect();
+
+ InputStream is = connection.getInputStream();
+
+ img = BitmapFactory.decodeStream(is);
+
+ is.close();
+
+ imgHandler.sendEmptyMessage(0);
+ } catch (IOException e) {
+ Log.e(cgSettings.tag, "Failed to download reCAPTCHA image");
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgSearchThread.java b/src/cgeo/geocaching/cgSearchThread.java
new file mode 100644
index 0000000..0cd99ce
--- /dev/null
+++ b/src/cgeo/geocaching/cgSearchThread.java
@@ -0,0 +1,46 @@
+package cgeo.geocaching;
+
+import android.os.Handler;
+import android.util.Log;
+
+public class cgSearchThread extends Thread {
+ private Handler recaptchaHandler = null;
+ private String recaptchaChallenge = null;
+ private String recaptchaText = null;
+
+ public void setRecaptchaHandler(Handler recaptchaHandlerIn) {
+ recaptchaHandler = recaptchaHandlerIn;
+ }
+
+ public void notifyNeed() {
+ if (recaptchaHandler != null) {
+ recaptchaHandler.sendEmptyMessage(1);
+ }
+ }
+
+ public synchronized void waitForUser() {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.w(cgSettings.tag, "searchThread is not waiting for user...");
+ }
+ }
+
+ public void setChallenge(String challenge) {
+ recaptchaChallenge = challenge;
+ }
+
+ public String getChallenge() {
+ return recaptchaChallenge;
+ }
+
+ public synchronized void setText(String text) {
+ recaptchaText = text;
+
+ notify();
+ }
+
+ public String getText() {
+ return recaptchaText;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSettings.java b/src/cgeo/geocaching/cgSettings.java
new file mode 100644
index 0000000..b88de0b
--- /dev/null
+++ b/src/cgeo/geocaching/cgSettings.java
@@ -0,0 +1,513 @@
+package cgeo.geocaching;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+import cgeo.geocaching.googlemaps.googleMapFactory;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapsforge.mfMapFactory;
+import android.os.Environment;
+import android.content.Intent;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.util.Log;
+
+public class cgSettings {
+
+ public enum mapSourceEnum {
+ googleMap,
+ mapsforgeMapnik,
+ mapsforgeOsmarender,
+ mapsforgeCycle,
+ mapsforgeOffline;
+
+ static mapSourceEnum fromInt(int id) {
+ mapSourceEnum[] values = mapSourceEnum.values();
+ if (id >= 0 && id < values.length) {
+ return values[id];
+ } else {
+ return googleMap;
+ }
+ }
+ }
+
+ // constants
+ public final static int unitsMetric = 1;
+ public final static int unitsImperial = 2;
+ public final static int mapSatellite = 1;
+ public final static int mapClassic = 2;
+ public final static String cache = ".cgeo";
+ public final static String analytics = "UA-1103507-15";
+
+ // twitter api keys
+ public final static String keyConsumerPublic = "RFafPiNi3xRhcS1TPE3wTw";
+ public final static String keyConsumerSecret = "7iDJprNPI9hzRwWhpzycSr9SPZMFrdVdsxD2OauI9k";
+
+ // version
+ public int version = 0;
+
+ // skin
+ public int skin = 0;
+ public int buttonActive = R.drawable.action_button_dark;
+ public int buttonInactive = R.drawable.action_button_dark_off;
+ public int buttonPressed = R.drawable.action_button_dark_pressed;
+
+ // settings
+ public boolean loaded = false;
+ public boolean hideMySearch = false;
+ public int helper = 0;
+ public int initialized = 0;
+ public String languages = null;
+ public int cachesFound = 0;
+ public int autoLoadDesc = 0;
+ public int units = unitsMetric;
+ public int livelist = 1;
+ public int maptype = mapSatellite;
+ public int mapzoom = 14;
+ public int maplive = 1;
+ public int maptrail = 1;
+ public boolean useEnglish = false;
+ public boolean showCaptcha = false;
+ public int excludeMine = 0;
+ public int excludeDisabled = 0;
+ public int storeOfflineMaps = 0;
+ public int asBrowser = 1;
+ public int useCompass = 1;
+ public int useGNavigation = 1;
+ public int showAddress = 1;
+ public int publicLoc = 0;
+ public int twitter = 0;
+ public int altCorrection = 0;
+ public String signature = null;
+ public String cacheType = null;
+ public String tokenPublic = null;
+ public String tokenSecret = null;
+ public String webDeviceName = null;
+ public String webDeviceCode = null;
+
+ // usable values
+ public static final String tag = "c:geo";
+
+ // preferences file
+ public static final String preferences = "cgeo.pref";
+
+ // private variables
+ private Context context = null;
+ private SharedPreferences prefs = null;
+ private String username = null;
+ private String password = null;
+ private String passVote = null;
+
+ // maps
+ public static final int MAP_GOOGLE = 0;
+ public static final int MAP_MF = 1;
+ public MapFactory mapFactory = null;
+ public mapSourceEnum mapProviderUsed = mapSourceEnum.googleMap;
+ public mapSourceEnum mapProvider = mapSourceEnum.googleMap;
+ public String mapFile = null;
+
+ public cgSettings(Context contextIn, SharedPreferences prefsIn) {
+ context = contextIn;
+ prefs = prefsIn;
+
+ load();
+ }
+
+ public void load() {
+ version = prefs.getInt("version", 0);
+
+ initialized = prefs.getInt("initialized", 0);
+ helper = prefs.getInt("helper", 0);
+
+ skin = prefs.getInt("skin", 0);
+ setSkinDefaults();
+
+ languages = prefs.getString("languages", null);
+ cachesFound = prefs.getInt("found", 0);
+ autoLoadDesc = prefs.getInt("autoloaddesc", 0);
+ units = prefs.getInt("units", 1);
+ livelist = prefs.getInt("livelist", 1);
+ maptype = prefs.getInt("maptype", 1);
+ maplive = prefs.getInt("maplive", 1);
+ mapzoom = prefs.getInt("mapzoom", 14);
+ maptrail = prefs.getInt("maptrail", 1);
+ useEnglish = prefs.getBoolean("useenglish", false);
+ showCaptcha = prefs.getBoolean("showcaptcha", false);
+ excludeMine = prefs.getInt("excludemine", 0);
+ excludeDisabled = prefs.getInt("excludedisabled", 0);
+ storeOfflineMaps = prefs.getInt("offlinemaps", 1);
+ asBrowser = prefs.getInt("asbrowser", 1);
+ useCompass = prefs.getInt("usecompass", 1);
+ useGNavigation = prefs.getInt("usegnav", 1);
+ showAddress = prefs.getInt("showaddress", 1);
+ publicLoc = prefs.getInt("publicloc", 0);
+ twitter = prefs.getInt("twitter", 0);
+ altCorrection = prefs.getInt("altcorrection", 0);
+ signature = prefs.getString("signature", null);
+ cacheType = prefs.getString("cachetype", null);
+ tokenPublic = prefs.getString("tokenpublic", null);
+ tokenSecret = prefs.getString("tokensecret", null);
+ mapFile = prefs.getString("mfmapfile", null);
+ mapProvider = mapSourceEnum.fromInt(prefs.getInt("mapsource", 0));
+ webDeviceName = prefs.getString("webDeviceName", null);
+ webDeviceCode = prefs.getString("webDeviceCode", null);
+
+ setLanguage(useEnglish);
+ }
+
+ private void setSkinDefaults() {
+ if (skin == 1) {
+ buttonActive = R.drawable.action_button_light;
+ buttonInactive = R.drawable.action_button_light_off;
+ buttonPressed = R.drawable.action_button_light_pressed;
+ } else {
+ skin = 0;
+ buttonActive = R.drawable.action_button_dark;
+ buttonInactive = R.drawable.action_button_dark_off;
+ buttonPressed = R.drawable.action_button_dark_pressed;
+ }
+ }
+
+ public void setSkin(int skinIn) {
+ if (skin == 1) {
+ skin = 1;
+ setSkinDefaults();
+ } else {
+ skin = 0;
+ setSkinDefaults();
+ }
+ }
+
+ public void setLanguage(boolean useEnglish) {
+ Locale locale = Locale.getDefault();
+ if (useEnglish) {
+ locale = new Locale("en");
+ }
+ Configuration config = new Configuration();
+ config.locale = locale;
+ context.getResources().updateConfiguration(config,
+ context.getResources().getDisplayMetrics());
+ }
+
+ public void reloadTwitterTokens() {
+ tokenPublic = prefs.getString("tokenpublic", null);
+ tokenSecret = prefs.getString("tokensecret", null);
+ }
+
+ public void reloadCacheType() {
+ cacheType = prefs.getString("cachetype", null);
+ }
+
+ public String getStorage() {
+ return getStorageSpecific(null)[0];
+ }
+
+ public String getStorageSec() {
+ return getStorageSpecific(null)[1];
+ }
+
+ public String[] getStorageSpecific(Boolean hidden) {
+ String[] storage = new String[2];
+
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ storage[0] = Environment.getExternalStorageDirectory() + "/" + cache + "/";
+ storage[1] = Environment.getDataDirectory() + "/data/cgeo.geocaching/" + cache + "/";
+ } else {
+ storage[0] = Environment.getDataDirectory() + "/data/cgeo.geocaching/" + cache + "/";
+ storage[1] = Environment.getExternalStorageDirectory() + "/" + cache + "/";
+ }
+
+ return storage;
+ }
+
+ public boolean isLogin() {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("password", null);
+
+ if (preUsername == null || prePassword == null || preUsername.length() == 0 || prePassword.length() == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public HashMap<String, String> getLogin() {
+ final HashMap<String, String> login = new HashMap<String, String>();
+
+ if (username == null || password == null) {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("password", null);
+
+ if (initialized == 0 && (preUsername == null || prePassword == null)) {
+ Intent initIntent = new Intent(context, cgeoinit.class);
+ context.startActivity(initIntent);
+
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+ prefsEdit.putInt("initialized", 1);
+ prefsEdit.commit();
+
+ initialized = 1;
+
+ return null;
+ } else if (initialized == 1 && (preUsername == null || prePassword == null)) {
+ return null;
+ }
+
+ login.put("username", preUsername);
+ login.put("password", prePassword);
+
+ username = preUsername;
+ password = prePassword;
+ } else {
+ login.put("username", username);
+ login.put("password", password);
+ }
+
+ return login;
+ }
+
+ public String getUsername() {
+ String user = null;
+
+ if (username == null) {
+ user = prefs.getString("username", null);
+ } else {
+ user = username;
+ }
+
+ return user;
+ }
+
+ public boolean setLogin(String username, String password) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (username == null || username.length() == 0 || password == null || password.length() == 0) {
+ // erase username and password
+ prefsEdit.remove("username");
+ prefsEdit.remove("password");
+ } else {
+ // save username and password
+ prefsEdit.putString("username", username);
+ prefsEdit.putString("password", password);
+ }
+
+ this.username = username;
+ this.password = password;
+
+ return prefsEdit.commit();
+ }
+
+ public boolean isGCvoteLogin() {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("pass-vote", null);
+
+ if (preUsername == null || prePassword == null || preUsername.length() == 0 || prePassword.length() == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public boolean setGCvoteLogin(String password) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (password == null || password.length() == 0) {
+ // erase password
+ prefsEdit.remove("pass-vote");
+ } else {
+ // save password
+ prefsEdit.putString("pass-vote", password);
+ }
+
+ passVote = password;
+
+ return prefsEdit.commit();
+ }
+
+ public HashMap<String, String> getGCvoteLogin() {
+ final HashMap<String, String> login = new HashMap<String, String>();
+
+ if (username == null || password == null) {
+ final String preUsername = prefs.getString("username", null);
+ final String prePassword = prefs.getString("pass-vote", null);
+
+ if (preUsername == null || prePassword == null) {
+ return null;
+ }
+
+ login.put("username", preUsername);
+ login.put("password", prePassword);
+
+ username = preUsername;
+ passVote = prePassword;
+ } else {
+ login.put("username", username);
+ login.put("password", password);
+ }
+
+ return login;
+ }
+
+ public boolean setSignature(String signature) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (signature == null || signature.length() == 0) {
+ // erase signature
+ prefsEdit.remove("signature");
+ } else {
+ // save signature
+ prefsEdit.putString("signature", signature);
+ }
+
+ this.signature = signature;
+
+ return prefsEdit.commit();
+ }
+
+ public String getSignature() {
+ return prefs.getString("signature", null);
+ }
+
+ public boolean setLanguages(String languages) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ if (languages == null || languages.length() == 0) {
+ // erase languages
+ prefsEdit.remove("languages");
+ } else {
+ // save langauges
+ languages = languages.toLowerCase();
+ languages = languages.replaceAll("([^a-z]+)", " ");
+ languages = languages.replaceAll("([ ]+)", " ");
+
+ prefsEdit.putString("languages", languages);
+ }
+
+ this.languages = languages;
+
+ return prefsEdit.commit();
+ }
+
+ public boolean setAltCorrection(int altitude) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ prefsEdit.putInt("altcorrection", altitude);
+
+ altCorrection = altitude;
+
+ return prefsEdit.commit();
+ }
+
+ public String getLanguages() {
+ return prefs.getString("languages", null);
+ }
+
+ public void deleteCookies() {
+ SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ // delete cookies
+ Map<String, ?> prefsValues = prefs.getAll();
+
+ if (prefsValues != null && prefsValues.size() > 0) {
+ Log.i(cgSettings.tag, "Removing cookies");
+
+ Object[] keys = prefsValues.keySet().toArray();
+
+ for (int i = 0; i < keys.length; i++) {
+ if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) {
+ prefsEdit.remove(keys[i].toString());
+ }
+ }
+ }
+
+ prefsEdit.commit();
+ }
+
+ public String setCacheType(String cacheTypeIn) {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putString("cachetype", cacheTypeIn);
+ edit.commit();
+
+ cacheType = cacheTypeIn;
+
+ return cacheType;
+ }
+
+ public void liveMapEnable() {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("maplive", 1);
+
+ if (edit.commit() == true) {
+ maplive = 1;
+ }
+ }
+
+ public void liveMapDisable() {
+ final SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("maplive", 0);
+
+ if (edit.commit() == true) {
+ maplive = 0;
+ }
+ }
+
+ public int getLastList() {
+ int listId = prefs.getInt("lastlist", -1);
+
+ return listId;
+ }
+
+ public void saveLastList(int listId) {
+ final SharedPreferences.Editor edit = prefs.edit();
+
+ edit.putInt("lastlist", listId);
+ edit.commit();
+ }
+
+ public void setWebNameCode(String name, String code) {
+ final SharedPreferences.Editor edit = prefs.edit();
+
+ this.webDeviceCode=code;
+ this.webDeviceName=name;
+
+ edit.putString("webDeviceName", name);
+ edit.putString("webDeviceCode", code);
+ edit.commit();
+ }
+
+ public MapFactory getMapFactory() {
+ if (mapProvider == mapSourceEnum.googleMap) {
+ if (mapProviderUsed != mapSourceEnum.googleMap || mapFactory == null) {
+ mapFactory = new googleMapFactory();
+ mapProviderUsed = mapProvider;
+ }
+ } else if (mapProvider != mapSourceEnum.googleMap) {
+ if (mapProviderUsed == mapSourceEnum.googleMap || mapFactory == null) {
+ mapFactory = new mfMapFactory();
+ mapProviderUsed = mapProvider;
+ }
+ }
+
+ return mapFactory;
+ }
+
+ public String getMapFile() {
+ return mapFile;
+ }
+
+ public boolean setMapFile(String mapFileIn) {
+ final SharedPreferences.Editor prefsEdit = prefs.edit();
+
+ prefsEdit.putString("mfmapfile", mapFileIn);
+
+ mapFile = mapFileIn;
+
+ return prefsEdit.commit();
+ }
+
+ public Context getContext() {
+ return context;
+ }
+}
diff --git a/src/cgeo/geocaching/cgSpoiler.java b/src/cgeo/geocaching/cgSpoiler.java
new file mode 100644
index 0000000..fca5648
--- /dev/null
+++ b/src/cgeo/geocaching/cgSpoiler.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgSpoiler {
+ public String url = "";
+ public String title = "";
+ public String description = "";
+}
diff --git a/src/cgeo/geocaching/cgTrackable.java b/src/cgeo/geocaching/cgTrackable.java
new file mode 100644
index 0000000..2244fc7
--- /dev/null
+++ b/src/cgeo/geocaching/cgTrackable.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching;
+
+import android.text.Spannable;
+import java.util.ArrayList;
+import java.util.Date;
+
+public class cgTrackable {
+ static public int SPOTTED_UNSET = 0;
+ static public int SPOTTED_CACHE = 1;
+ static public int SPOTTED_USER = 2;
+ static public int SPOTTED_UNKNOWN = 3;
+ static public int SPOTTED_OWNER = 4;
+
+ public int errorRetrieve = 0;
+ public String error = "";
+ public String guid = "";
+ public String geocode = "";
+ public String iconUrl = "";
+ public String name = "";
+ public String nameString = null;
+ public Spannable nameSp = null;
+ public String type = null;
+ public Date released = null;
+ public Double distance = null;
+ public String origin = null;
+ public String owner = null;
+ public String ownerGuid = null;
+ public String spottedName = null;
+ public int spottedType = SPOTTED_UNSET;
+ public String spottedGuid = null;
+ public String goal = null;
+ public String details = null;
+ public String image = null;
+ public ArrayList<cgLog> logs = new ArrayList<cgLog>();
+}
diff --git a/src/cgeo/geocaching/cgTrackableLog.java b/src/cgeo/geocaching/cgTrackableLog.java
new file mode 100644
index 0000000..7522d8d
--- /dev/null
+++ b/src/cgeo/geocaching/cgTrackableLog.java
@@ -0,0 +1,9 @@
+package cgeo.geocaching;
+
+public class cgTrackableLog {
+ public int ctl = -1;
+ public int id = -1;
+ public String trackCode = null;
+ public String name = null;
+ public int action = 0; // base.logTrackablesAction - no action
+}
diff --git a/src/cgeo/geocaching/cgUpdateDir.java b/src/cgeo/geocaching/cgUpdateDir.java
new file mode 100644
index 0000000..01346ec
--- /dev/null
+++ b/src/cgeo/geocaching/cgUpdateDir.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgUpdateDir {
+ public void updateDir(cgDirection dir) {
+ // to be overriden
+ }
+}
diff --git a/src/cgeo/geocaching/cgUpdateLoc.java b/src/cgeo/geocaching/cgUpdateLoc.java
new file mode 100644
index 0000000..3c063f2
--- /dev/null
+++ b/src/cgeo/geocaching/cgUpdateLoc.java
@@ -0,0 +1,7 @@
+package cgeo.geocaching;
+
+public class cgUpdateLoc {
+ public void updateLoc(cgGeo geo) {
+ // to be overriden
+ }
+}
diff --git a/src/cgeo/geocaching/cgUser.java b/src/cgeo/geocaching/cgUser.java
new file mode 100644
index 0000000..1389de8
--- /dev/null
+++ b/src/cgeo/geocaching/cgUser.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching;
+
+import java.util.Date;
+
+public class cgUser {
+ public Date located = null;
+ public String username = null;
+ public Double latitude = null;
+ public Double longitude = null;
+ public String action = null;
+ public String client = null;
+}
diff --git a/src/cgeo/geocaching/cgWarning.java b/src/cgeo/geocaching/cgWarning.java
new file mode 100644
index 0000000..93ddec7
--- /dev/null
+++ b/src/cgeo/geocaching/cgWarning.java
@@ -0,0 +1,52 @@
+package cgeo.geocaching;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.widget.Toast;
+import android.view.Gravity;
+
+public class cgWarning {
+ public Context context = null;
+
+ public cgWarning(Context contextIn) {
+ context = contextIn;
+ }
+
+ public void showToast(String text) {
+ if (text.length() > 0) {
+ Toast toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
+
+ toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM, 0, 100);
+ toast.show();
+ }
+ }
+
+ public void showShortToast(String text) {
+ if (text.length() > 0) {
+ Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
+
+ toast.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM, 0, 100);
+ toast.show();
+ }
+ }
+
+ public void helpDialog(String title, String message) {
+ if (message == null || message.length() == 0) {
+ return;
+ }
+
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setTitle(title);
+ dialog.setMessage(message);
+ dialog.setCancelable(true);
+ dialog.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+}
diff --git a/src/cgeo/geocaching/cgWaypoint.java b/src/cgeo/geocaching/cgWaypoint.java
new file mode 100644
index 0000000..d3f703c
--- /dev/null
+++ b/src/cgeo/geocaching/cgWaypoint.java
@@ -0,0 +1,16 @@
+package cgeo.geocaching;
+
+public class cgWaypoint {
+ public Integer id = 0;
+ public String geocode = "geocode";
+ public String type = "waypoint";
+ public String prefix = "";
+ public String lookup = "";
+ public String name = "";
+ public String latlon = "";
+ public String latitudeString = "";
+ public String longitudeString = "";
+ public Double latitude = null;
+ public Double longitude = null;
+ public String note = "";
+}
diff --git a/src/cgeo/geocaching/cgeo.java b/src/cgeo/geocaching/cgeo.java
new file mode 100644
index 0000000..67ff74a
--- /dev/null
+++ b/src/cgeo/geocaching/cgeo.java
@@ -0,0 +1,669 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.app.Activity;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Button;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.Message;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+public class cgeo extends Activity {
+
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Context context = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Integer version = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private TextView navType = null;
+ private TextView navAccuracy = null;
+ private TextView navSatellites = null;
+ private TextView navLocation = null;
+ private TextView filterTitle = null;
+ private TextView countBubble = null;
+ private boolean cleanupRunning = false;
+ private int countBubbleCnt = 0;
+ private Double addLat = null;
+ private Double addLon = null;
+ private List<Address> addresses = null;
+ private boolean addressObtaining = false;
+ private boolean initialized = false;
+ private Handler countBubbleHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (countBubble == null) {
+ countBubble = (TextView) findViewById(R.id.offline_count);
+ }
+
+ if (countBubbleCnt == 0) {
+ countBubble.setVisibility(View.GONE);
+ } else {
+ countBubble.setText(Integer.toString(countBubbleCnt));
+ countBubble.bringToFront();
+ countBubble.setVisibility(View.VISIBLE);
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeo.countBubbleHander: " + e.toString());
+ }
+ }
+ };
+ private Handler obtainAddressHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (addresses != null && addresses.isEmpty() == false) {
+ final Address address = addresses.get(0);
+ final StringBuilder addText = new StringBuilder();
+
+ if (address.getCountryName() != null) {
+ addText.append(address.getCountryName());
+ }
+ if (address.getLocality() != null) {
+ if (addText.length() > 0) {
+ addText.append(", ");
+ }
+ addText.append(address.getLocality());
+ } else if (address.getAdminArea() != null) {
+ if (addText.length() > 0) {
+ addText.append(", ");
+ }
+ addText.append(address.getAdminArea());
+ }
+
+ addLat = geo.latitudeNow;
+ addLon = geo.longitudeNow;
+
+ if (navLocation == null) {
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ navLocation.setText(addText.toString());
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ addresses = null;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ context = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ app.cleanGeo();
+ app.cleanDir();
+
+ setContentView(R.layout.main);
+ setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // type to search
+
+ try {
+ PackageManager manager = this.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
+
+ version = info.versionCode;
+
+ base.sendAnal(context, "/?ver=" + info.versionCode);
+ Log.i(cgSettings.tag, "Starting " + info.packageName + " " + info.versionCode + " a.k.a " + info.versionName + "...");
+
+ info = null;
+ manager = null;
+ } catch (Exception e) {
+ base.sendAnal(context, "/");
+ Log.i(cgSettings.tag, "No info.");
+ }
+
+ try {
+ if (settings.helper == 0) {
+ RelativeLayout helper = (RelativeLayout) findViewById(R.id.helper);
+ if (helper != null) {
+ helper.setVisibility(View.VISIBLE);
+ helper.setClickable(true);
+ helper.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-intro",
+ context,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+
+ view.setVisibility(View.GONE);
+ }
+ });
+
+ final SharedPreferences.Editor edit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ edit.putInt("helper", 1);
+ edit.commit();
+ }
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ initialized = false;
+
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 0, 0, res.getString(R.string.menu_about)).setIcon(android.R.drawable.ic_menu_help);
+ menu.add(0, 1, 0, res.getString(R.string.menu_helpers)).setIcon(android.R.drawable.ic_menu_add);
+ menu.add(0, 2, 0, res.getString(R.string.menu_settings)).setIcon(android.R.drawable.ic_menu_preferences);
+ menu.add(0, 3, 0, res.getString(R.string.menu_history)).setIcon(android.R.drawable.ic_menu_recent_history);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+ if (id == 0) {
+ showAbout(null);
+
+ return true;
+ } else if (id == 1) {
+ context.startActivity(new Intent(context, cgeohelpers.class));
+
+ return true;
+ } else if (id == 2) {
+ context.startActivity(new Intent(context, cgeoinit.class));
+
+ return true;
+ } else if (id == 3) {
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "history");
+ context.startActivity(cachesIntent);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ menu.setHeaderTitle(res.getString(R.string.menu_filter));
+
+ //first add the most used types
+ menu.add(1, 0, 0, res.getString(R.string.all_types));
+ menu.add(1, 1, 0, res.getString(R.string.traditional));
+ menu.add(1, 2, 0, res.getString(R.string.multi));
+ menu.add(1, 3, 0, res.getString(R.string.mystery));
+
+ // then add all other cache types sorted alphabetically
+ HashMap<String, String> allTypes = (HashMap<String, String>) base.cacheTypesInv.clone();
+ allTypes.remove("traditional");
+ allTypes.remove("multi");
+ allTypes.remove("mystery");
+ ArrayList<String> sorted = new ArrayList<String>(allTypes.values());
+ Collections.sort(sorted);
+ for (String choice : sorted) {
+ menu.add(1, menu.size(), 0, choice);
+ }
+
+ // mark current filter as checked
+ menu.setGroupCheckable(1, true, true);
+ boolean foundItem = false;
+ int itemCount = menu.size();
+ if (settings.cacheType != null) {
+ String typeTitle = cgBase.cacheTypesInv.get(settings.cacheType);
+ if (typeTitle != null) {
+ for (int i = 0; i < itemCount; i++) {
+ if (menu.getItem(i).getTitle().equals(typeTitle)) {
+ menu.getItem(i).setChecked(true);
+ foundItem = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!foundItem) {
+ menu.getItem(0).setChecked(true);
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 0) {
+ settings.setCacheType(null);
+ setFilterTitle();
+
+ return true;
+ } else if (id > 0) {
+ String itemTitle = item.getTitle().toString();
+ String choice = null;
+ for (Entry<String, String> entry : cgBase.cacheTypesInv.entrySet()) {
+ if (entry.getValue().equalsIgnoreCase(itemTitle)) {
+ choice = entry.getKey();
+ break;
+ }
+ }
+ if (choice == null) {
+ settings.setCacheType(null);
+ } else {
+ settings.setCacheType(choice);
+ }
+ setFilterTitle();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private void setFilterTitle() {
+ if (filterTitle == null) {
+ filterTitle = (TextView) findViewById(R.id.filter_button_title);
+ }
+ if (settings.cacheType != null) {
+ filterTitle.setText(cgBase.cacheTypesInv.get(settings.cacheType));
+ } else {
+ filterTitle.setText(res.getString(R.string.all));
+ }
+ }
+
+ private void init() {
+ if (initialized == true) {
+ return;
+ }
+
+ initialized = true;
+
+ settings.getLogin();
+ settings.reloadCacheType();
+
+ if (app.firstRun == true) {
+ new Thread() {
+
+ @Override
+ public void run() {
+ int status = base.login();
+
+ if (status == 1) {
+ app.firstRun = false;
+ }
+ }
+ }.start();
+ }
+
+ (new countBubbleUpdate()).start();
+ (new cleanDatabase()).start();
+
+ if (settings.cacheType != null && cgBase.cacheTypesInv.containsKey(settings.cacheType) == false) {
+ settings.setCacheType(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(context, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+
+ final LinearLayout findOnMap = (LinearLayout) findViewById(R.id.map);
+ findOnMap.setClickable(true);
+ findOnMap.setOnClickListener(new cgeoFindOnMapListener());
+
+ final RelativeLayout findByOffline = (RelativeLayout) findViewById(R.id.search_offline);
+ findByOffline.setClickable(true);
+ findByOffline.setOnClickListener(new cgeoFindByOfflineListener());
+
+ (new countBubbleUpdate()).start();
+
+ final LinearLayout advanced = (LinearLayout) findViewById(R.id.advanced_button);
+ advanced.setClickable(true);
+ advanced.setOnClickListener(new cgeoSearchListener());
+
+ final LinearLayout any = (LinearLayout) findViewById(R.id.any_button);
+ any.setClickable(true);
+ any.setOnClickListener(new cgeoPointListener());
+
+ final LinearLayout filter = (LinearLayout) findViewById(R.id.filter_button);
+ registerForContextMenu(filter);
+ filter.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+ filter.setClickable(true);
+
+ setFilterTitle();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (navType == null || navLocation == null || navAccuracy == null) {
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navSatellites = (TextView) findViewById(R.id.nav_satellites);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ LinearLayout findNearest = (LinearLayout) findViewById(R.id.nearest);
+ findNearest.setClickable(true);
+ findNearest.setOnClickListener(new cgeoFindNearestListener());
+
+ String satellites = null;
+ if (geo.satellitesVisible != null && geo.satellitesFixed != null && geo.satellitesFixed > 0) {
+ satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible;
+ } else if (geo.satellitesVisible != null) {
+ satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible;
+ } else {
+ satellites = "";
+ }
+ navSatellites.setText(satellites);
+
+ if (geo.gps == -1) {
+ navType.setText(res.getString(R.string.loc_last));
+ } else if (geo.gps == 0) {
+ navType.setText(res.getString(R.string.loc_net));
+ } else {
+ navType.setText(res.getString(R.string.loc_gps));
+ }
+
+ if (geo.accuracyNow != null) {
+ if (settings.units == cgSettings.unitsImperial) {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", (geo.accuracyNow * 3.2808399)) + " ft");
+ } else {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", geo.accuracyNow) + " m");
+ }
+ } else {
+ navAccuracy.setText(null);
+ }
+
+ if (settings.showAddress == 1) {
+ if (addLat == null || addLon == null) {
+ navLocation.setText(res.getString(R.string.loc_no_addr));
+ }
+ if (addLat == null || addLon == null || (cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, addLat, addLon) > 0.5 && addressObtaining == false)) {
+ (new obtainAddress()).start();
+ }
+ } else {
+ if (geo.altitudeNow != null) {
+ String humanAlt;
+ if (settings.units == cgSettings.unitsImperial) {
+ humanAlt = String.format("%.0f", (geo.altitudeNow * 3.2808399)) + " ft";
+ } else {
+ humanAlt = String.format("%.0f", geo.altitudeNow) + " m";
+ }
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true) + " | " + humanAlt);
+ } else {
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+ }
+ } else {
+ Button findNearest = (Button) findViewById(R.id.nearest);
+ findNearest.setClickable(false);
+ findNearest.setOnClickListener(null);
+
+ navType.setText(null);
+ navAccuracy.setText(null);
+ navLocation.setText(res.getString(R.string.loc_trying));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class cgeoFindNearestListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null) {
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "nearest");
+ cachesIntent.putExtra("latitude", geo.latitudeNow);
+ cachesIntent.putExtra("longitude", geo.longitudeNow);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ context.startActivity(cachesIntent);
+ }
+ }
+
+ private class cgeoFindOnMapListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, settings.getMapFactory().getMapClass()));
+ }
+ }
+
+ private class cgeoFindByOfflineListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final Intent cachesIntent = new Intent(context, cgeocaches.class);
+ cachesIntent.putExtra("type", "offline");
+ context.startActivity(cachesIntent);
+ }
+ }
+
+ private class cgeoSearchListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, cgeoadvsearch.class));
+ }
+ }
+
+ private class cgeoPointListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ context.startActivity(new Intent(context, cgeopoint.class));
+ }
+ }
+
+ private class countBubbleUpdate extends Thread {
+
+ @Override
+ public void run() {
+ if (app == null) {
+ return;
+ }
+
+ int checks = 0;
+ while (app.storageStatus() == false) {
+ try {
+ wait(500);
+ checks++;
+ } catch (Exception e) {
+ // nothing;
+ }
+
+ if (checks > 10) {
+ return;
+ }
+ }
+
+
+ countBubbleCnt = app.getAllStoredCachesCount(true, null, null);
+
+ countBubbleHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class cleanDatabase extends Thread {
+
+ @Override
+ public void run() {
+ if (app == null) {
+ return;
+ }
+ if (cleanupRunning == true) {
+ return;
+ }
+
+ boolean more = false;
+ if (version != settings.version) {
+ Log.i(cgSettings.tag, "Initializing hard cleanup - version changed from " + settings.version + " to " + version + ".");
+
+ more = true;
+ }
+
+ cleanupRunning = true;
+ app.cleanDatabase(more);
+ cleanupRunning = false;
+
+ if (version != null && version > 0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("version", version);
+ edit.commit();
+ }
+ }
+ }
+
+ private class obtainAddress extends Thread {
+
+ public obtainAddress() {
+ setPriority(Thread.MIN_PRIORITY);
+ }
+
+ @Override
+ public void run() {
+ if (geo == null) {
+ return;
+ }
+ if (addressObtaining == true) {
+ return;
+ }
+ addressObtaining = true;
+
+ try {
+ Geocoder geocoder = new Geocoder(context, Locale.getDefault());
+
+ addresses = geocoder.getFromLocation(geo.latitudeNow, geo.longitudeNow, 1);
+ } catch (Exception e) {
+ Log.i(cgSettings.tag, "Failed to obtain address");
+ }
+
+ obtainAddressHandler.sendEmptyMessage(0);
+
+ addressObtaining = false;
+ }
+ }
+
+ public void showAbout(View view) {
+ context.startActivity(new Intent(context, cgeoabout.class));
+ }
+
+ public void goSearch(View view) {
+ onSearchRequested();
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-main-screen",
+ context,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoabout.java b/src/cgeo/geocaching/cgeoabout.java
new file mode 100644
index 0000000..fe11660
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoabout.java
@@ -0,0 +1,110 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.method.LinkMovementMethod;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+public class cgeoabout extends Activity {
+ private Activity activity = null;
+ private Resources res = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ settings = new cgSettings(this, this.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase((cgeoapplication) this.getApplication(), settings, this.getSharedPreferences(cgSettings.preferences, 0));
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.about);
+ base.setTitle(activity, res.getString(R.string.about));
+
+ // google analytics
+ base.sendAnal(activity, "/about");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private void init() {
+ try {
+ PackageManager manager = this.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
+
+ base.setTitle(activity, res.getString(R.string.about) + " (ver. " + info.versionName + ")");
+
+ manager = null;
+
+ ((TextView)findViewById(R.id.contributors)).setMovementMethod(LinkMovementMethod.getInstance());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoabout.init: Failed to obtain package version.");
+ }
+ }
+
+ public void donateMore(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N2FKGNCPPRUVE")));
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2Z69QWLRCBE9N&lc=US&item_name=c%3ageo&currency_code=EUR&amount=15&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted")));
+ }
+
+ public void donateLess(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4PRD9CX4Y8XR6")));
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2Z69QWLRCBE9N&lc=US&item_name=c%3ageo&currency_code=EUR&amount=7&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted")));
+ }
+
+ public void author(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://carnero.cc/")));
+ }
+
+ public void support(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:support@cgeo.org")));
+ }
+
+ public void website(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.cgeo.org/")));
+ }
+
+ public void facebook(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.facebook.com/pages/cgeo/297269860090")));
+ }
+
+ public void twitter(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://twitter.com/android_gc")));
+ }
+
+ public void nutshellmanual(View view) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://cgeo.carnero.cc/manual/")));
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoaddresses.java b/src/cgeo/geocaching/cgeoaddresses.java
new file mode 100644
index 0000000..c917d50
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoaddresses.java
@@ -0,0 +1,201 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.view.View;
+import android.view.LayoutInflater;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.location.Address;
+import android.location.Geocoder;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import java.util.List;
+import java.util.Locale;
+
+public class cgeoaddresses extends Activity {
+ private final ArrayList<Address> addresses = new ArrayList<Address>();
+ private String keyword = null;
+ private Activity activity = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private Resources res = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private LinearLayout addList = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadPlacesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (addList == null) {
+ addList = (LinearLayout) findViewById(R.id.address_list);
+ }
+
+ if (addresses.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.err_search_address_no_match));
+
+ finish();
+ return;
+ } else {
+ LinearLayout oneAddPre = null;
+ for (Address address : addresses) {
+ oneAddPre = (LinearLayout) inflater.inflate(R.layout.address_button, null);
+
+ Button oneAdd = (Button) oneAddPre.findViewById(R.id.button);
+ int index = 0;
+ StringBuilder allAdd = new StringBuilder();
+ StringBuilder allAddLine = new StringBuilder();
+
+ while (address.getAddressLine(index) != null) {
+ if (allAdd.length() > 0) {
+ allAdd.append("\n");
+ }
+ if (allAddLine.length() > 0) {
+ allAddLine.append("; ");
+ }
+
+ allAdd.append(address.getAddressLine(index));
+ allAddLine.append(address.getAddressLine(index));
+
+ index++;
+ }
+
+ oneAdd.setText(allAdd.toString());
+ oneAdd.setLines(allAdd.toString().split("\n").length);
+ oneAdd.setClickable(true);
+ oneAdd.setOnClickListener(new buttonListener(address.getLatitude(), address.getLongitude(), allAddLine.toString()));
+ addList.addView(oneAddPre);
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeoaddresses.loadCachesHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+ inflater = getLayoutInflater();
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.addresses);
+ base.setTitle(activity, res.getString(R.string.search_address_result));
+
+ // google analytics
+ base.sendAnal(activity, "/addresses");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ keyword = extras.getString("keyword");
+ }
+
+ if (keyword == null) {
+ warning.showToast(res.getString(R.string.err_search_address_forgot));
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.search_address_started), keyword, true);
+ waitDialog.setCancelable(true);
+
+ (new loadPlaces()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ private class loadPlaces extends Thread {
+
+ @Override
+ public void run() {
+ Geocoder geocoder = new Geocoder(activity, Locale.getDefault());
+ try {
+ List<Address> knownLocations = geocoder.getFromLocationName(keyword, 20);
+
+ addresses.clear();
+ for (Address address : knownLocations) {
+ addresses.add(address);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoaddresses.loadPlaces.run: " + e.toString());
+ }
+
+ loadPlacesHandler.sendMessage(new Message());
+ }
+ }
+
+ private class buttonListener implements View.OnClickListener {
+
+ private Double latitude = null;
+ private Double longitude = null;
+ private String address = null;
+
+ public buttonListener(Double latitudeIn, Double longitudeIn, String addressIn) {
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ address = addressIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent addressIntent = new Intent(activity, cgeocaches.class);
+ addressIntent.putExtra("type", "address");
+ addressIntent.putExtra("latitude", (Double) latitude);
+ addressIntent.putExtra("longitude", (Double) longitude);
+ addressIntent.putExtra("address", (String) address);
+ addressIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(addressIntent);
+
+ finish();
+ return;
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoadvsearch.java b/src/cgeo/geocaching/cgeoadvsearch.java
new file mode 100644
index 0000000..568cbce
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoadvsearch.java
@@ -0,0 +1,552 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.HashMap;
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.SearchManager;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeoadvsearch extends Activity {
+
+ private Resources res = null;
+ private Activity activity = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private String[] geocodesInCache = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // search query
+ Intent intent = getIntent();
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ final String query = intent.getStringExtra(SearchManager.QUERY);
+ final boolean found = instantSearch(query);
+
+ if (found) {
+ finish();
+
+ return;
+ }
+ }
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.search);
+ base.setTitle(activity, res.getString(R.string.search));
+
+ // google analytics
+ base.sendAnal(activity, "/advanced-search");
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private boolean instantSearch(String query) {
+ boolean found = false;
+
+ final Pattern gcCode = Pattern.compile("^GC[0-9A-Z]+$", Pattern.CASE_INSENSITIVE);
+ final Pattern tbCode = Pattern.compile("^TB[0-9A-Z]+$", Pattern.CASE_INSENSITIVE);
+ final Matcher gcCodeM = gcCode.matcher(query);
+ final Matcher tbCodeM = tbCode.matcher(query);
+
+ try {
+ if (gcCodeM.find()) { // GC-code
+ final Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", query.trim().toUpperCase());
+ activity.startActivity(cachesIntent);
+
+ found = true;
+ } else if (tbCodeM.find()) { // TB-code
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", query.trim().toUpperCase());
+ activity.startActivity(trackablesIntent);
+
+ found = true;
+ } else { // keyword (fallback)
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "keyword");
+ cachesIntent.putExtra("keyword", query);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+
+ found = true;
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeoadvsearch.instantSearch: " + e.toString());
+ }
+
+ return found;
+ }
+
+ private void init() {
+ settings.getLogin();
+ settings.reloadCacheType();
+
+ if (settings.cacheType != null && cgBase.cacheTypesInv.containsKey(settings.cacheType) == false) {
+ settings.setCacheType(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setOnEditorActionListener(new findByCoordsAction());
+ ((EditText) findViewById(R.id.longitude)).setOnEditorActionListener(new findByCoordsAction());
+
+ final Button findByCoords = (Button) findViewById(R.id.search_coordinates);
+ findByCoords.setOnClickListener(new findByCoordsListener());
+
+ ((EditText) findViewById(R.id.address)).setOnEditorActionListener(new findByAddressAction());
+
+ final Button findByAddress = (Button) findViewById(R.id.search_address);
+ findByAddress.setOnClickListener(new findByAddressListener());
+
+ final AutoCompleteTextView geocodeEdit = (AutoCompleteTextView) findViewById(R.id.geocode);
+ geocodeEdit.setOnEditorActionListener(new findByGeocodeAction());
+ geocodesInCache = app.geocodesInCache();
+ if (geocodesInCache != null) {
+ final ArrayAdapter<String> geocodesAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, geocodesInCache);
+ geocodeEdit.setAdapter(geocodesAdapter);
+ }
+ // geocodeEdit.addTextChangedListener(new UpperCaseTextWatcher(geocodeEdit));
+
+ final Button displayByGeocode = (Button) findViewById(R.id.display_geocode);
+ displayByGeocode.setOnClickListener(new findByGeocodeListener());
+
+ ((EditText) findViewById(R.id.keyword)).setOnEditorActionListener(new findByKeywordAction());
+
+ final Button findByKeyword = (Button) findViewById(R.id.search_keyword);
+ findByKeyword.setOnClickListener(new findByKeywordListener());
+
+ ((EditText) findViewById(R.id.username)).setOnEditorActionListener(new findByUsernameAction());
+
+ final Button findByUserName = (Button) findViewById(R.id.search_username);
+ findByUserName.setOnClickListener(new findByUsernameListener());
+
+ ((EditText) findViewById(R.id.owner)).setOnEditorActionListener(new findByOwnerAction());
+
+ final Button findByOwner = (Button) findViewById(R.id.search_owner);
+ findByOwner.setOnClickListener(new findByOwnerListener());
+
+ EditText trackable = (EditText) findViewById(R.id.trackable);
+ trackable.setOnEditorActionListener(new findTrackableAction());
+ // trackable.addTextChangedListener(new UpperCaseTextWatcher(trackable)); // not working with HTC IMEs.
+
+ final Button displayTrackable = (Button) findViewById(R.id.display_trackable);
+ displayTrackable.setOnClickListener(new findTrackableListener());
+ }
+
+ /**
+ * converts user input to uppercase during typing
+ * @author bananeweizen
+ *
+ */
+ private final class UpperCaseTextWatcher implements TextWatcher {
+
+ private final EditText editText;
+
+ private UpperCaseTextWatcher(EditText editText) {
+ this.editText = editText;
+ }
+
+ @Override
+ public void afterTextChanged(Editable arg0) {
+ // empty
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ // empty
+ }
+
+ @Override
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ String oldText = editText.getText().toString();
+ String upperText = oldText.toUpperCase();
+ if (!oldText.equals(upperText)) {
+ int selectionStart = editText.getSelectionStart();
+ int selectionEnd = editText.getSelectionEnd();
+ editText.setText(upperText);
+ editText.setSelection(selectionStart, selectionEnd);
+ }
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class findByCoordsAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByCoordsFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByCoordsListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByCoordsFn();
+ }
+ }
+
+ private void findByCoordsFn() {
+ final EditText latView = (EditText) findViewById(R.id.latitude);
+ final EditText lonView = (EditText) findViewById(R.id.longitude);
+ final String latText = latView.getText().toString();
+ final String lonText = lonView.getText().toString();
+
+ if (latText == null || latText.length() == 0 || lonText == null || lonText.length() == 0) {
+ latView.setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ lonView.setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+ } else {
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", (Double) latParsed.get("coordinate"));
+ cachesIntent.putExtra("longitude", (Double) lonParsed.get("coordinate"));
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+ }
+
+ private class findByKeywordAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByKeywordFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByKeywordListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByKeywordFn();
+ }
+ }
+
+ private void findByKeywordFn() {
+ // find caches by coordinates
+ String keyText = ((EditText) findViewById(R.id.keyword)).getText().toString();
+
+ if (keyText == null || keyText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_keyword));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "keyword");
+ cachesIntent.putExtra("keyword", keyText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByAddressAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByAddressFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByAddressListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByAddressFn();
+ }
+ }
+
+ private void findByAddressFn() {
+ final String addText = ((EditText) findViewById(R.id.address)).getText().toString();
+
+ if (addText == null || addText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_address));
+ return;
+ }
+
+ final Intent addressesIntent = new Intent(activity, cgeoaddresses.class);
+ addressesIntent.putExtra("keyword", addText);
+ activity.startActivity(addressesIntent);
+ }
+
+ private class findByUsernameAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByUsernameFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByUsernameListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByUsernameFn();
+ }
+ }
+
+ public void findByUsernameFn() {
+ final String usernameText = ((EditText) findViewById(R.id.username)).getText().toString();
+
+ if (usernameText == null || usernameText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", usernameText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByOwnerAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByOwnerFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByOwnerListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByOwnerFn();
+ }
+ }
+
+ private void findByOwnerFn() {
+ final String usernameText = ((EditText) findViewById(R.id.owner)).getText().toString();
+
+ if (usernameText == null || usernameText.length() == 0) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_user));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", usernameText);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findByGeocodeAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findByGeocodeFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findByGeocodeListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findByGeocodeFn();
+ }
+ }
+
+ private void findByGeocodeFn() {
+ final String geocodeText = ((EditText) findViewById(R.id.geocode)).getText().toString();
+
+ if (geocodeText == null || geocodeText.length() == 0 || geocodeText.equalsIgnoreCase("GC")) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_gccode));
+ return;
+ }
+
+ final Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocodeText.toUpperCase());
+ activity.startActivity(cachesIntent);
+ }
+
+ private class findTrackableAction implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView view, int action, KeyEvent event) {
+ if (action == EditorInfo.IME_ACTION_GO) {
+ findTrackableFn();
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ private class findTrackableListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ findTrackableFn();
+ }
+ }
+
+ private void findTrackableFn() {
+ final String trackableText = ((EditText) findViewById(R.id.trackable)).getText().toString();
+
+ if (trackableText == null || trackableText.length() == 0 || trackableText.equalsIgnoreCase("TB")) {
+ warning.helpDialog(res.getString(R.string.warn_search_help_title), res.getString(R.string.warn_search_help_tb));
+ return;
+ }
+
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", trackableText.toUpperCase());
+ activity.startActivity(trackablesIntent);
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-search",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoapplication.java b/src/cgeo/geocaching/cgeoapplication.java
new file mode 100644
index 0000000..374f323
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoapplication.java
@@ -0,0 +1,828 @@
+package cgeo.geocaching;
+
+import android.app.Application;
+import android.content.Context;
+import android.util.Log;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+public class cgeoapplication extends Application {
+
+ private cgData storage = null;
+ private String action = null;
+ private Double lastLatitude = null;
+ private Double lastLongitude = null;
+ private cgGeo geo = null;
+ private boolean geoInUse = false;
+ private cgDirection dir = null;
+ private boolean dirInUse = false;
+ final private HashMap<Long, cgSearch> searches = new HashMap<Long, cgSearch>(); // information about searches
+ final private HashMap<String, cgCache> cachesCache = new HashMap<String, cgCache>(); // caching caches into memory
+ public boolean firstRun = true; // c:geo is just launched
+ public boolean warnedLanguage = false; // user was warned about different language settings on geocaching.com
+ private boolean databaseCleaned = false; // database was cleaned
+
+ public cgeoapplication() {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ Log.i(cgSettings.tag, "Cleaning applications cache.");
+
+ cachesCache.clear();
+ }
+
+ @Override
+ public void onTerminate() {
+ Log.d(cgSettings.tag, "Terminating c:geo...");
+
+ if (geo != null) {
+ geo.closeGeo();
+ geo = null;
+ }
+
+ if (dir != null) {
+ dir.closeDir();
+ dir = null;
+ }
+
+ if (storage != null) {
+ storage.clean();
+ storage.closeDb();
+ storage = null;
+ }
+
+ super.onTerminate();
+ }
+
+ public String backupDatabase() {
+ return storage.backupDatabase();
+ }
+
+ public File isRestoreFile() {
+ return storage.isRestoreFile();
+ }
+
+ public boolean restoreDatabase() {
+ return storage.restoreDatabase();
+ }
+
+ public void cleanGeo() {
+ if (geo != null) {
+ geo.closeGeo();
+ geo = null;
+ }
+ }
+
+ public void cleanDir() {
+ if (dir != null) {
+ dir.closeDir();
+ dir = null;
+ }
+ }
+
+ public boolean storageStatus() {
+ if (storage.status() == false) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public cgGeo startGeo(Context context, cgUpdateLoc geoUpdate, cgBase base, cgSettings settings, cgWarning warning, int time, int distance) {
+ if (geo == null) {
+ geo = new cgGeo(context, this, geoUpdate, base, settings, warning, time, distance);
+ geo.initGeo();
+
+ Log.i(cgSettings.tag, "Location service started");
+ }
+
+ geo.replaceUpdate(geoUpdate);
+ geoInUse = true;
+
+ return geo;
+ }
+
+ public cgGeo removeGeo() {
+ if (geo != null) {
+ geo.replaceUpdate(null);
+ }
+ geoInUse = false;
+
+ (new removeGeoThread()).start();
+
+ return null;
+ }
+
+ private class removeGeoThread extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ sleep(2500);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (geoInUse == false && geo != null) {
+ geo.closeGeo();
+ geo = null;
+
+ Log.i(cgSettings.tag, "Location service stopped");
+ }
+ }
+ }
+
+ public cgDirection startDir(Context context, cgUpdateDir dirUpdate, cgWarning warning) {
+ if (dir == null) {
+ dir = new cgDirection(this, context, dirUpdate, warning);
+ dir.initDir();
+
+ Log.i(cgSettings.tag, "Direction service started");
+ }
+
+ dir.replaceUpdate(dirUpdate);
+ dirInUse = true;
+
+ return dir;
+ }
+
+ public cgDirection removeDir() {
+ if (dir != null) {
+ dir.replaceUpdate(null);
+ }
+ dirInUse = false;
+
+ (new removeDirThread()).start();
+
+ return null;
+ }
+
+ private class removeDirThread extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ sleep(2500);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ if (dirInUse == false && dir != null) {
+ dir.closeDir();
+ dir = null;
+
+ Log.i(cgSettings.tag, "Direction service stopped");
+ }
+ }
+ }
+
+ public void cleanDatabase(boolean more) {
+ if (databaseCleaned == true) {
+ return;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.clean(more);
+ databaseCleaned = true;
+ }
+
+ public Boolean isThere(String geocode, String guid, boolean detailed, boolean checkTime) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.isThere(geocode, guid, detailed, checkTime);
+ }
+
+ public Boolean isOffline(String geocode, String guid) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.isOffline(geocode, guid);
+ }
+
+ public String getGeocode(String guid) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.getGeocodeForGuid(guid);
+ }
+
+ public String getCacheid(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.getCacheidForGeocode(geocode);
+ }
+
+ public String getError(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).error;
+ }
+
+ public boolean setError(Long searchId, String error) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).error = error;
+
+ return true;
+ }
+
+ public String getUrl(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).url;
+ }
+
+ public boolean setUrl(Long searchId, String url) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).url = url;
+
+ return true;
+ }
+
+ public String getViewstate(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).viewstate;
+ }
+
+ public String getViewstate1(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).viewstate1;
+ }
+
+ public boolean setViewstate(Long searchId, String viewstate) {
+ if (viewstate == null || viewstate.length() == 0) {
+ return false;
+ }
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).viewstate = viewstate;
+
+ return true;
+ }
+
+ public boolean setViewstate1(Long searchId, String viewstate1) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return false;
+ }
+
+ searches.get(searchId).viewstate1 = viewstate1;
+
+ return true;
+ }
+
+ public Integer getTotal(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ return searches.get(searchId).totalCnt;
+ }
+
+ public Integer getCount(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return 0;
+ }
+
+ return searches.get(searchId).getCount();
+ }
+
+ public Integer getNotOfflineCount(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return 0;
+ }
+
+ int count = 0;
+ ArrayList<String> geocodes = searches.get(searchId).getGeocodes();
+ if (geocodes != null) {
+ for (String geocode : geocodes) {
+ if (isOffline(geocode, null) == false) {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public cgCache getCacheByGeocode(String geocode) {
+ return getCacheByGeocode(geocode, false, true, false, false, false, false);
+ }
+
+ public cgCache getCacheByGeocode(String geocode, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ cgCache cache = null;
+ if (cachesCache.containsKey(geocode) == true) {
+ cache = cachesCache.get(geocode);
+ } else {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cache = storage.loadCache(geocode, null, loadA, loadW, loadS, loadL, loadI, loadO);
+
+ if (cache != null && cache.detailed == true && loadA == true && loadW == true && loadS == true && loadL == true && loadI == true) {
+ putCacheInCache(cache);
+ }
+ }
+
+ return cache;
+ }
+
+ public cgTrackable getTrackableByGeocode(String geocode) {
+ if (geocode == null || geocode.length() == 0) {
+ return null;
+ }
+
+ cgTrackable trackable = null;
+ trackable = storage.loadTrackable(geocode);
+
+ return trackable;
+ }
+
+ public void removeCacheFromCache(String geocode) {
+ if (geocode != null && cachesCache.containsKey(geocode) == true) {
+ cachesCache.remove(geocode);
+ }
+ }
+
+ public void putCacheInCache(cgCache cache) {
+ if (cache == null || cache.geocode == null) {
+ return;
+ }
+
+ if (cachesCache.containsKey(cache.geocode) == true) {
+ cachesCache.remove(cache.geocode);
+ }
+
+ cachesCache.put(cache.geocode, cache);
+ }
+
+ public String[] geocodesInCache() {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.allDetailedThere();
+ }
+
+ public cgWaypoint getWaypointById(Integer id) {
+ if (id == null || id == 0) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.loadWaypoint(id);
+ }
+
+ public ArrayList<Object> getBounds(String geocode) {
+ if (geocode == null) {
+ return null;
+ }
+
+ List<String> geocodeList = new ArrayList<String>();
+ geocodeList.add(geocode);
+
+ return getBounds(geocodeList);
+ }
+
+ public ArrayList<Object> getBounds(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final cgSearch search = searches.get(searchId);
+ final ArrayList<String> geocodeList = search.getGeocodes();
+
+ return getBounds(geocodeList);
+ }
+
+ public ArrayList<Object> getBounds(List<String> geocodes) {
+ if (geocodes == null || geocodes.isEmpty()) {
+ return null;
+ }
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getBounds(geocodes.toArray());
+ }
+
+ public cgCache getCache(Long searchId) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ cgSearch search = searches.get(searchId);
+ ArrayList<String> geocodeList = search.getGeocodes();
+
+ return getCacheByGeocode(geocodeList.get(0), true, true, true, true, true, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId) {
+ return getCaches(searchId, null, null, null, null, false, true, false, false, false, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ return getCaches(searchId, null, null, null, null, loadA, loadW, loadS, loadL, loadI, loadO);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, Long centerLat, Long centerLon, Long spanLat, Long spanLon) {
+ return getCaches(searchId, centerLat, centerLon, spanLat, spanLon, false, true, false, false, false, true);
+ }
+
+ public ArrayList<cgCache> getCaches(Long searchId, Long centerLat, Long centerLon, Long spanLat, Long spanLon, boolean loadA, boolean loadW, boolean loadS, boolean loadL, boolean loadI, boolean loadO) {
+ if (searchId == null || searches.containsKey(searchId) == false) {
+ ArrayList<cgCache> cachesOut = new ArrayList<cgCache>();
+
+ final ArrayList<cgCache> cachesPre = storage.loadCaches(null , null, centerLat, centerLon, spanLat, spanLon, loadA, loadW, loadS, loadL, loadI, loadO);
+
+ if (cachesPre != null) {
+ cachesOut.addAll(cachesPre);
+ }
+
+ return cachesOut;
+ }
+
+ ArrayList<cgCache> cachesOut = new ArrayList<cgCache>();
+
+ cgSearch search = searches.get(searchId);
+ ArrayList<String> geocodeList = search.getGeocodes();
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final ArrayList<cgCache> cachesPre = storage.loadCaches(geocodeList.toArray(), null, centerLat, centerLon, spanLat, spanLon, loadA, loadW, loadS, loadL, loadI, loadO);
+ if (cachesPre != null) {
+ cachesOut.addAll(cachesPre);
+ }
+
+ return cachesOut;
+ }
+
+ public cgSearch getBatchOfStoredCaches(boolean detailedOnly, Double latitude, Double longitude, String cachetype, int list) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.loadBatchOfStoredGeocodes(detailedOnly, latitude, longitude, cachetype, list);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search;
+ }
+
+ public cgSearch getHistoryOfCaches(boolean detailedOnly, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.loadBatchOfHistoricGeocodes(detailedOnly, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search;
+ }
+
+ public Long getCachedInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public Long getStoredInViewport(Long centerLat, Long centerLon, Long spanLat, Long spanLon, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public Long getOfflineAll(String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ cgSearch search = new cgSearch();
+
+ ArrayList<String> geocodes = storage.getOfflineAll(cachetype);
+ if (geocodes != null && geocodes.isEmpty() == false) {
+ for (String gccode : geocodes) {
+ search.addGeocode(gccode);
+ }
+ }
+ searches.put(search.getCurrentId(), search);
+
+ return search.getCurrentId();
+ }
+
+ public int getAllStoredCachesCount(boolean detailedOnly, String cachetype, Integer list) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getAllStoredCachesCount(detailedOnly, cachetype, list);
+ }
+
+ public int getAllHistoricCachesCount(boolean detailedOnly, String cachetype) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ return storage.getAllHistoricCachesCount(detailedOnly, cachetype);
+ }
+
+ public void markStored(String geocode, int listId) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.markStored(geocode, listId);
+ }
+
+ public boolean markDropped(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.markDropped(geocode);
+ }
+
+ public boolean markFound(String geocode) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.markFound(geocode);
+ }
+
+ public boolean saveWaypoints(String geocode, ArrayList<cgWaypoint> waypoints, boolean drop) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.saveWaypoints(geocode, waypoints, drop);
+ }
+
+ public boolean saveOwnWaypoint(int id, String geocode, cgWaypoint waypoint) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.saveOwnWaypoint(id, geocode, waypoint);
+ }
+
+ public boolean deleteWaypoint(int id) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ return storage.deleteWaypoint(id);
+ }
+
+ public boolean saveTrackable(cgTrackable trackable) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+
+ final ArrayList<cgTrackable> list = new ArrayList<cgTrackable>();
+ list.add(trackable);
+
+ return storage.saveInventory("---", list);
+ }
+
+ public void addGeocode(Long searchId, String geocode) {
+ if (this.searches.containsKey(searchId) == false || geocode == null || geocode.length() == 0) {
+ return;
+ }
+
+ this.searches.get(searchId).addGeocode(geocode);
+ }
+
+ public Long addSearch(Long searchId, ArrayList<cgCache> cacheList, Boolean newItem, int reason) {
+ if (this.searches.containsKey(searchId) == false) {
+ return null;
+ }
+
+ cgSearch search = this.searches.get(searchId);
+
+ return addSearch(search, cacheList, newItem, reason);
+ }
+
+ public Long addSearch(cgSearch search, ArrayList<cgCache> cacheList, Boolean newItem, int reason) {
+ if (cacheList == null || cacheList.isEmpty()) {
+ return null;
+ }
+
+ final long searchId = search.getCurrentId();
+ searches.put(searchId, search);
+
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ if (newItem == true) {
+ // save only newly downloaded data
+ for (cgCache oneCache : cacheList) {
+ String oneGeocode = oneCache.geocode.toUpperCase();
+ String oneGuid = oneCache.guid.toLowerCase();
+
+ oneCache.reason = reason;
+
+ if (storage.isThere(oneGeocode, oneGuid, false, false) == false || reason >= 1) {
+ // cache is not saved, new data are for storing
+ storage.saveCache(oneCache);
+ } else {
+ cgCache mergedCache = oneCache.merge(storage);
+
+ storage.saveCache(mergedCache);
+ }
+ }
+ }
+
+ return searchId;
+ }
+
+ public boolean addCacheToSearch(cgSearch search, cgCache cache) {
+ if (search == null || cache == null) {
+ return false;
+ }
+
+ final long searchId = search.getCurrentId();
+
+ if (searches.containsKey(searchId) == false) {
+ searches.put(searchId, search);
+ }
+
+ String geocode = cache.geocode.toUpperCase();
+ String guid = cache.guid.toLowerCase();
+
+ boolean status = false;
+
+ if (storage.isThere(geocode, guid, false, false) == false || cache.reason >= 1) { // if for offline, do not merge
+ status = storage.saveCache(cache);
+ } else {
+ cgCache mergedCache = cache.merge(storage);
+
+ status = storage.saveCache(mergedCache);
+ }
+
+ if (status == true) {
+ search.addGeocode(cache.geocode);
+ }
+
+ return status;
+ }
+
+ public void dropStored(int listId) {
+ if (storage == null) {
+ storage = new cgData(this);
+ }
+ storage.dropStored(listId);
+ }
+
+ public ArrayList<cgTrackable> loadInventory(String geocode) {
+ return storage.loadInventory(geocode);
+ }
+
+ public ArrayList<cgSpoiler> loadSpoilers(String geocode) {
+ return storage.loadSpoilers(geocode);
+ }
+
+ public cgWaypoint loadWaypoint(int id) {
+ return storage.loadWaypoint(id);
+ }
+
+ public void setAction(String act) {
+ action = act;
+ }
+
+ public String getAction() {
+ if (action == null) {
+ return "";
+ }
+ return action;
+ }
+
+ public boolean addLog(String geocode, cgLog log) {
+ if (geocode == null || geocode.length() == 0) {
+ return false;
+ }
+ if (log == null) {
+ return false;
+ }
+
+ ArrayList<cgLog> list = new ArrayList<cgLog>();
+ list.add(log);
+
+ return storage.saveLogs(geocode, list, false);
+ }
+
+ public void setLastLoc(Double lat, Double lon) {
+ lastLatitude = lat;
+ lastLongitude = lon;
+ }
+
+ public Double getLastLat() {
+ return lastLatitude;
+ }
+
+ public Double getLastLon() {
+ return lastLongitude;
+ }
+
+ public boolean saveLogOffline(String geocode, Date date, int logtype, String log) {
+ return storage.saveLogOffline(geocode, date, logtype, log);
+ }
+
+ public cgLog loadLogOffline(String geocode) {
+ return storage.loadLogOffline(geocode);
+ }
+
+ public void clearLogOffline(String geocode) {
+ storage.clearLogOffline(geocode);
+ }
+
+ public void saveVisitDate(String geocode) {
+ storage.saveVisitDate(geocode);
+ }
+
+ public ArrayList<cgList> getLists() {
+ return storage.getLists(getResources());
+ }
+
+ public cgList getList(int id) {
+ return storage.getList(id, getResources());
+ }
+
+ public int createList(String title) {
+ return storage.createList(title);
+ }
+
+ public boolean removeList(int id) {
+ return storage.removeList(id);
+ }
+
+ public void moveToList(String geocode, int listId) {
+ storage.moveToList(geocode, listId);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoauth.java b/src/cgeo/geocaching/cgeoauth.java
new file mode 100644
index 0000000..84514ba
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoauth.java
@@ -0,0 +1,413 @@
+package cgeo.geocaching;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import android.net.Uri;
+import android.content.Intent;
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.view.View;
+import android.widget.EditText;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.widget.Button;
+import java.io.IOException;
+import javax.net.ssl.HttpsURLConnection;
+
+public class cgeoauth extends Activity {
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+ 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\\-\\_\\.]+)");
+ private Button startButton = null;
+ private EditText pinEntry = null;
+ private Button pinEntryButton = null;
+ private ProgressDialog requestTokenDialog = null;
+ private ProgressDialog changeTokensDialog = null;
+ private Handler requestTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (requestTokenDialog != null && requestTokenDialog.isShowing() == true) {
+ requestTokenDialog.dismiss();
+ }
+
+ startButton.setOnClickListener(new startListener());
+ startButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ startButton.setText(res.getString(R.string.auth_again));
+
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ } else {
+ warning.showToast(res.getString(R.string.err_auth_initialize));
+ startButton.setText(res.getString(R.string.auth_start));
+ }
+ }
+ };
+ private Handler changeTokensHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (changeTokensDialog != null && changeTokensDialog.isShowing() == true) {
+ changeTokensDialog.dismiss();
+ }
+
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ pinEntryButton.setEnabled(true);
+
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.auth_dialog_completed));
+
+ pinEntryButton.setVisibility(View.GONE);
+
+ finish();
+ } else {
+ warning.showToast(res.getString(R.string.err_auth_process));
+
+ pinEntry.setVisibility(View.GONE);
+ pinEntryButton.setVisibility(View.GONE);
+ startButton.setText(res.getString(R.string.auth_start));
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction("setting up");
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.auth);
+ base.setTitle(activity, res.getString(R.string.auth_twitter));
+
+ // google analytics
+ base.sendAnal(activity, "/auth");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private void init() {
+ startButton = (Button) findViewById(R.id.start);
+ pinEntry = (EditText) findViewById(R.id.pin);
+ pinEntryButton = (Button) findViewById(R.id.pin_button);
+
+ OAtoken = prefs.getString("temp-token-public", null);
+ OAtokenSecret = prefs.getString("temp-token-secret", null);
+
+ startButton.setEnabled(true);
+ startButton.setOnClickListener(new startListener());
+
+ if (OAtoken == null || OAtoken.length() == 0 || OAtokenSecret == null || OAtokenSecret.length() == 0) {
+ // start authorization process
+ startButton.setText(res.getString(R.string.auth_start));
+ } else {
+ // already have temporary tokens, continue from pin
+ startButton.setText(res.getString(R.string.auth_again));
+
+ pinEntry.setVisibility(View.VISIBLE);
+ pinEntryButton.setVisibility(View.VISIBLE);
+ pinEntryButton.setOnClickListener(new confirmPINListener());
+ }
+ }
+
+ private void requestToken() {
+ final String host = "twitter.com";
+ final String pathRequest = "/oauth/request_token";
+ final String pathAuthorize = "/oauth/authorize";
+ final String method = "GET";
+
+ int status = 0;
+ try {
+ String lineOne = null;
+ HttpsURLConnection connection = null;
+
+ try {
+ final StringBuilder sb = new StringBuilder();
+ final String params = cgOAuth.signOAuth(host, pathRequest, method, true, new HashMap<String, String>(), null, null);
+
+ int code = -1;
+ int retries = 0;
+
+ do {
+ // base.trustAllHosts();
+ Log.d(cgSettings.tag, "https://" + host + pathRequest + "?" + params);
+ final URL u = new URL("https://" + host + pathRequest + "?" + params);
+ final URLConnection uc = u.openConnection();
+ connection = (HttpsURLConnection) uc;
+
+ // connection.setHostnameVerifier(base.doNotVerify);
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod(method);
+ HttpsURLConnection.setFollowRedirects(true);
+ connection.setDoInput(true);
+ connection.setDoOutput(false);
+
+ final InputStream in = connection.getInputStream();
+ final InputStreamReader ins = new InputStreamReader(in);
+ final BufferedReader br = new BufferedReader(ins);
+
+ while ((lineOne = br.readLine()) != null) {
+ sb.append(lineOne);
+ sb.append("\n");
+ }
+
+ code = connection.getResponseCode();
+ retries++;
+
+ Log.i(cgSettings.tag, host + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ br.close();
+ in.close();
+ ins.close();
+ } while (code == -1 && retries < 5);
+
+ final String line = sb.toString();
+
+ if (line != null && line.length() > 0) {
+ final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ if (paramsMatcher1.find() == true && paramsMatcher1.groupCount() > 0) {
+ OAtoken = paramsMatcher1.group(1).toString();
+ }
+ final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ if (paramsMatcher2.find() == true && paramsMatcher2.groupCount() > 0) {
+ OAtokenSecret = paramsMatcher2.group(1).toString();
+ }
+
+ if (OAtoken != null && OAtoken.length() > 0 && OAtokenSecret != null && OAtokenSecret.length() > 0) {
+ final SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putString("temp-token-public", OAtoken);
+ prefsEdit.putString("temp-token-secret", OAtokenSecret);
+ prefsEdit.commit();
+
+ try {
+ final HashMap<String, String> paramsPre = new HashMap<String, String>();
+ paramsPre.put("oauth_callback", "oob");
+
+ final String paramsBrowser = cgOAuth.signOAuth(host, pathAuthorize, "GET", true, paramsPre, OAtoken, OAtokenSecret);
+
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + paramsBrowser)));
+
+ status = 1;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(2): " + e.toString());
+ }
+ }
+ }
+ } catch (IOException eio) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(IO): " + eio.toString() + " ~ " + connection.getResponseCode() + ": " + connection.getResponseMessage());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(1): " + e.toString());
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ } catch (Exception e2) {
+ Log.e(cgSettings.tag, "cgeoauth.requestToken(3): " + e2.toString());
+ }
+
+ requestTokenHandler.sendEmptyMessage(status);
+ }
+
+ private void changeToken() {
+ final String host = "twitter.com";
+ final String path = "/oauth/access_token";
+ final String method = "POST";
+
+ int status = 0;
+ String lineOne = null;
+
+ try {
+ final HashMap<String, String> paramsPre = new HashMap<String, String>();
+ paramsPre.put("oauth_verifier", pinEntry.getText().toString());
+
+ int code = -1;
+ int retries = 0;
+
+ final String params = cgOAuth.signOAuth(host, path, method, true, paramsPre, OAtoken, OAtokenSecret);
+ final StringBuilder sb = new StringBuilder();
+ do {
+ // base.trustAllHosts();
+ final URL u = new URL("https://" + host + path);
+ final URLConnection uc = u.openConnection();
+ final HttpsURLConnection connection = (HttpsURLConnection) uc;
+
+ // connection.setHostnameVerifier(base.doNotVerify);
+ connection.setReadTimeout(30000);
+ connection.setRequestMethod(method);
+ HttpsURLConnection.setFollowRedirects(true);
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+
+ final OutputStream out = connection.getOutputStream();
+ final OutputStreamWriter wr = new OutputStreamWriter(out);
+
+ wr.write(params);
+ wr.flush();
+ wr.close();
+ out.close();
+
+ final InputStream in = connection.getInputStream();
+ final InputStreamReader ins = new InputStreamReader(in);
+ final BufferedReader br = new BufferedReader(ins);
+
+ while ((lineOne = br.readLine()) != null) {
+ sb.append(lineOne);
+ sb.append("\n");
+ }
+
+ code = connection.getResponseCode();
+ retries++;
+
+ Log.i(cgSettings.tag, host + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
+
+ br.close();
+ ins.close();
+ in.close();
+ connection.disconnect();
+ } while (code == -1 && retries < 5);
+
+ final String line = sb.toString();
+
+ OAtoken = "";
+ OAtokenSecret = "";
+
+ final Matcher paramsMatcher1 = paramsPattern1.matcher(line);
+ if (paramsMatcher1.find() == true && paramsMatcher1.groupCount() > 0) {
+ OAtoken = paramsMatcher1.group(1).toString();
+ }
+ final Matcher paramsMatcher2 = paramsPattern2.matcher(line);
+ if (paramsMatcher2.find() == true && paramsMatcher2.groupCount() > 0) {
+ OAtokenSecret = paramsMatcher2.group(1).toString();
+ }
+
+ if (OAtoken.length() == 0 || OAtokenSecret.length() == 0) {
+ OAtoken = "";
+ OAtokenSecret = "";
+
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.putString("tokenpublic", null);
+ prefs.putString("tokensecret", null);
+ prefs.putInt("twitter", 0);
+ prefs.commit();
+ } else {
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.remove("temp-token-public");
+ prefs.remove("temp-token-secret");
+ prefs.putString("tokenpublic", OAtoken);
+ prefs.putString("tokensecret", OAtokenSecret);
+ prefs.putInt("twitter", 1);
+ prefs.commit();
+
+ status = 1;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeoauth.changeToken: " + e.toString());
+ }
+
+ changeTokensHandler.sendEmptyMessage(status);
+ }
+
+ private class startListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (requestTokenDialog == null) {
+ requestTokenDialog = new ProgressDialog(activity);
+ requestTokenDialog.setCancelable(false);
+ requestTokenDialog.setMessage(res.getString(R.string.auth_dialog_wait));
+ }
+ requestTokenDialog.show();
+ startButton.setEnabled(false);
+ startButton.setOnTouchListener(null);
+ startButton.setOnClickListener(null);
+
+ final SharedPreferences.Editor prefs = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefs.putString("temp-token-public", null);
+ prefs.putString("temp-token-secret", null);
+ prefs.commit();
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ requestToken();
+ }
+ }).start();
+ }
+ }
+
+ private class confirmPINListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (((EditText) findViewById(R.id.pin)).getText().toString().length() == 0) {
+ warning.helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message));
+ return;
+ }
+
+ if (changeTokensDialog == null) {
+ changeTokensDialog = new ProgressDialog(activity);
+ changeTokensDialog.setCancelable(false);
+ changeTokensDialog.setMessage(res.getString(R.string.auth_dialog_wait));
+ }
+ changeTokensDialog.show();
+ pinEntryButton.setEnabled(false);
+ pinEntryButton.setOnTouchListener(null);
+ pinEntryButton.setOnClickListener(null);
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ changeToken();
+ }
+ }).start();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeocaches.java b/src/cgeo/geocaching/cgeocaches.java
new file mode 100644
index 0000000..9c730de
--- /dev/null
+++ b/src/cgeo/geocaching/cgeocaches.java
@@ -0,0 +1,2193 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import cgeo.geocaching.filter.cgFilterBySize;
+import cgeo.geocaching.filter.cgFilterByTrackables;
+import cgeo.geocaching.filter.cgFilterByType;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.Locale;
+
+public class cgeocaches extends ListActivity {
+
+ private GoogleAnalyticsTracker tracker = null;
+ private String action = null;
+ private String type = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private String cachetype = null;
+ private String keyword = null;
+ private String address = null;
+ private String username = null;
+ private Long searchId = null;
+ private ArrayList<cgCache> cacheList = new ArrayList<cgCache>();
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private static Activity activity = null;
+ private cgCacheListAdapter adapter = null;
+ private LayoutInflater inflater = null;
+ private View listFooter = null;
+ private TextView listFooterText = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private Double northHeading = new Double(0);
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private cgUpdateDir dirUpdate = new updateDir();
+ private String title = "";
+ private int detailTotal = 0;
+ private int detailProgress = 0;
+ private Long detailProgressTime = 0l;
+ private geocachesLoadDetails threadD = null;
+ private geocachesLoadFromWeb threadW = null;
+ private geocachesDropDetails threadR = null;
+ private int listId = 0;
+ private ArrayList<cgList> lists = null;
+ private String selectedFilter = null;
+ private cgCacheGeocodeComparator gcComparator = new cgCacheGeocodeComparator();
+ private Handler loadCachesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (searchId != null && searchId > 0) {
+ base.setTitle(activity, title + " [" + app.getCount(searchId) + "]");
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (cacheList == null) {
+ warning.showToast(res.getString(R.string.err_list_load_fail));
+ setMoreCaches(false);
+ } else {
+ final Integer count = app.getTotal(searchId);
+
+ if (count != null && count > 0) {
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ setMoreCaches(false);
+ }
+ }
+
+ if (cacheList != null && app.getError(searchId) != null && app.getError(searchId).equalsIgnoreCase(cgBase.errorRetrieve.get(-7)) == true) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.license));
+ dialog.setMessage(res.getString(R.string.err_license));
+ dialog.setCancelable(true);
+ dialog.setNegativeButton(res.getString(R.string.license_dismiss), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ settings.deleteCookies();
+ dialog.cancel();
+ }
+ });
+ dialog.setPositiveButton(res.getString(R.string.license_show), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ settings.deleteCookies();
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/software/agreement.aspx?ID=0")));
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ } else if (app != null && app.getError(searchId) != null && app.getError(searchId).length() > 0) {
+ warning.showToast(res.getString(R.string.err_download_fail) + app.getError(searchId) + ".");
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find_any));
+ Log.e(cgSettings.tag, "cgeocaches.loadCachesHandler: " + e.toString());
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ try {
+ hideLoading();
+ base.showProgress(activity, false);
+ } catch (Exception e2) {
+ Log.e(cgSettings.tag, "cgeocaches.loadCachesHandler.2: " + e2.toString());
+ }
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+ }
+ };
+ private Handler loadNextPageHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (searchId != null && searchId > 0) {
+ base.setTitle(activity, title + " [" + app.getCount(searchId) + "]");
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ if(adapter != null){
+ adapter.reFilter();
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (cacheList == null) {
+ warning.showToast(res.getString(R.string.err_list_load_fail));
+ setMoreCaches(false);
+ } else {
+ final Integer count = app.getTotal(searchId);
+ if (count != null && count > 0) {
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ setMoreCaches(false);
+ }
+ }
+
+ if (app.getError(searchId) != null && app.getError(searchId).length() > 0) {
+ warning.showToast(res.getString(R.string.err_download_fail) + app.getError(searchId) + ".");
+
+ listFooter.setOnClickListener(new moreCachesListener());
+ hideLoading();
+ base.showProgress(activity, false);
+
+ finish();
+ return;
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find_next));
+ Log.e(cgSettings.tag, "cgeocaches.loadNextPageHandler: " + e.toString());
+ }
+
+ listFooter.setOnClickListener(new moreCachesListener());
+
+ hideLoading();
+ base.showProgress(activity, false);
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+ }
+ };
+ private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (msg.what > -1) {
+ if (waitDialog != null) {
+ cacheList.get(msg.what).statusChecked = false;
+
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+
+ Float diffTime = new Float((System.currentTimeMillis() - detailProgressTime) / 1000); // seconds left
+ Float oneCache = diffTime / detailProgress; // left time per cache
+ int etaTime = (int) ((detailTotal - detailProgress) * oneCache / 60); // seconds remaining
+
+ waitDialog.setProgress(detailProgress);
+ if (etaTime < 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime == 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_mins));
+ }
+ }
+ } else {
+ if (cacheList != null && searchId != null) {
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.clear();
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+
+ base.showProgress(activity, false);
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ }
+ }
+ };
+ private Handler downloadFromWebHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+
+ if (msg.what == 0) { //no caches
+ waitDialog.setMessage(res.getString(R.string.web_import_waiting));
+ } else if (msg.what == 1) { //cache downloading
+ waitDialog.setMessage(res.getString(R.string.web_downloading)+" "+(String)msg.obj+"...");
+ } else if (msg.what == 2) { //Cache downloaded
+ waitDialog.setMessage(res.getString(R.string.web_downloaded)+" "+(String)msg.obj+".");
+ //Once a cache is downloaded I used switchList to refresh it.
+ switchList(listId, -1);
+ } else if (msg.what == -2) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ warning.showToast(res.getString(R.string.gpx_import_no_files));
+ finish();
+ return;
+ } else {
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+ }
+ };
+ private Handler dropDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ setAdapter();
+
+ if (msg.what > -1) {
+ cacheList.get(msg.what).statusChecked = false;
+ } else {
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ }
+
+ cacheList.clear();
+
+ final ArrayList<cgCache> cacheListTmp = app.getCaches(searchId);
+ if (cacheListTmp != null && cacheListTmp.isEmpty() == false) {
+ cacheList.addAll(cacheListTmp);
+ cacheListTmp.clear();
+
+ Collections.sort((List<cgCache>)cacheList, gcComparator);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+ }
+ }
+ };
+ private ContextMenuInfo lastMenuInfo;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ app.setAction(action);
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.caches);
+ base.setTitle(activity, "caches");
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/cache/list");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ type = extras.getString("type");
+ latitude = extras.getDouble("latitude");
+ longitude = extras.getDouble("longitude");
+ cachetype = extras.getString("cachetype");
+ keyword = extras.getString("keyword");
+ address = extras.getString("address");
+ username = extras.getString("username");
+ }
+
+ init();
+
+ Thread threadPure;
+ cgSearchThread thread;
+
+ if (type.equals("offline") == true) {
+ listId = settings.getLastList();
+ if (listId <= 0) {
+ listId = 1;
+ title = res.getString(R.string.caches_stored);
+ } else {
+ final cgList list = app.getList(listId);
+ title = list.title;
+ }
+
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ threadPure = new geocachesLoadByOffline(loadCachesHandler, latitude, longitude, listId);
+ threadPure.start();
+ } else if (type.equals("history") == true) {
+ if (adapter != null) {
+ adapter.setHistoric(true);
+ }
+
+ title = res.getString(R.string.caches_history);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ threadPure = new geocachesLoadByHistory(loadCachesHandler);
+ threadPure.start();
+ } else if (type.equals("nearest") == true) {
+ action = "pending";
+ title = res.getString(R.string.caches_nearby);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("coordinate") == true) {
+ action = "planning";
+ title = base.formatCoordinate(latitude, res.getString(R.string.search_lat), true) + " | " + base.formatCoordinate(longitude, res.getString(R.string.search_lon), true);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("keyword") == true) {
+ title = keyword;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByKeyword(loadCachesHandler, keyword, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("address") == true) {
+ action = "planning";
+ if (address != null && address.length() > 0) {
+ title = address;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ } else {
+ title = base.formatCoordinate(latitude, res.getString(R.string.search_lat), true) + " | " + base.formatCoordinate(longitude, res.getString(R.string.search_lon), true);
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ }
+
+ thread = new geocachesLoadByCoords(loadCachesHandler, latitude, longitude, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("username") == true) {
+ title = username;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByUserName(loadCachesHandler, username, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else if (type.equals("owner") == true) {
+ title = username;
+ base.setTitle(activity, title);
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ thread = new geocachesLoadByOwner(loadCachesHandler, username, cachetype);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ } else {
+ title = "caches";
+ base.setTitle(activity, title);
+ Log.e(cgSettings.tag, "cgeocaches.onCreate: No action or unknown action specified");
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+
+ if (adapter != null && geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ adapter.setActualHeading(northHeading);
+ }
+
+ if (adapter != null) {
+ adapter.setSelectMode(false, true);
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.forceSort(geo.latitudeNow, geo.longitudeNow);
+ }
+ }
+
+ if (loadCachesHandler != null && searchId != null) {
+ loadCachesHandler.sendEmptyMessage(0);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (adapter != null) {
+ adapter = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenuFilter = menu.addSubMenu(0, 105, 0, res.getString(R.string.caches_filter)).setIcon(android.R.drawable.ic_menu_search);
+ subMenuFilter.setHeaderTitle(res.getString(R.string.caches_filter_title));
+ subMenuFilter.add(0, 21, 0, res.getString(R.string.caches_filter_type));
+ subMenuFilter.add(0, 22, 0, res.getString(R.string.caches_filter_size));
+ subMenuFilter.add(0, 23, 0, res.getString(R.string.caches_filter_track));
+ subMenuFilter.add(0, 24, 0, res.getString(R.string.caches_filter_clear));
+
+ SubMenu subMenuSort = menu.addSubMenu(0, 104, 0, res.getString(R.string.caches_sort)).setIcon(android.R.drawable.ic_menu_sort_alphabetically);
+ subMenuSort.setHeaderTitle(res.getString(R.string.caches_sort_title));
+
+ // sort the context menu labels alphabetically for easier reading
+ HashMap<String, Integer> comparators = new HashMap<String, Integer>();
+ comparators.put(res.getString(R.string.caches_sort_distance), 10);
+ comparators.put(res.getString(R.string.caches_sort_difficulty), 11);
+ comparators.put(res.getString(R.string.caches_sort_terrain), 12);
+ comparators.put(res.getString(R.string.caches_sort_size), 13);
+ comparators.put(res.getString(R.string.caches_sort_favorites), 14);
+ comparators.put(res.getString(R.string.caches_sort_name), 15);
+ comparators.put(res.getString(R.string.caches_sort_gccode), 16);
+ comparators.put(res.getString(R.string.caches_sort_rating), 18);
+ comparators.put(res.getString(R.string.caches_sort_vote), 19);
+ comparators.put(res.getString(R.string.caches_sort_inventory), 20);
+
+ ArrayList<String> sortedLabels = new ArrayList<String>(comparators.keySet());
+ Collections.sort(sortedLabels);
+ for (String label : sortedLabels) {
+ Integer id = comparators.get(label);
+ subMenuSort.add(1, id, 0, label).setCheckable(true).setChecked(id == 10);
+ }
+
+ subMenuSort.setGroupCheckable(1, true, true);
+
+ menu.add(0, 0, 0, res.getString(R.string.caches_select_mode)).setIcon(android.R.drawable.ic_menu_agenda);
+ menu.add(0, 9, 0, res.getString(R.string.caches_select_invert)).setIcon(android.R.drawable.ic_menu_agenda);
+ if (type.equals("offline") == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 103, 0, res.getString(R.string.caches_manage)).setIcon(android.R.drawable.ic_menu_save);
+ subMenu.add(0, 5, 0, res.getString(R.string.caches_drop_all)); // delete saved caches
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches
+ if (settings.webDeviceCode == null)
+ {
+ menu.add(0, 6, 0, res.getString(R.string.gpx_import_title)).setIcon(android.R.drawable.ic_menu_upload); // import gpx file
+ } else {
+ SubMenu subMenuImport = menu.addSubMenu(0, 105, 0, res.getString(R.string.import_title)).setIcon(android.R.drawable.ic_menu_upload); // import
+ subMenuImport.add(1, 6, 0, res.getString(R.string.gpx_import_title)).setCheckable(false).setChecked(false);
+ subMenuImport.add(1, 25, 0, res.getString(R.string.web_import_title)).setCheckable(false).setChecked(false);
+ }
+ } else {
+ menu.add(0, 1, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as); // download details for all caches
+ }
+
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+ if (cgBase.isIntentAvailable(activity, intentTest) == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 101, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ subMenu.add(0, 2, 0, res.getString(R.string.caches_map_cgeo)); // show all caches on map using c:geo
+ subMenu.add(0, 3, 0, res.getString(R.string.caches_map_locus)); // show all caches on map using Locus
+ } else {
+ menu.add(0, 2, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode); // show all caches on map
+ }
+
+ if (type.equals("offline") == true) {
+ SubMenu subMenu = menu.addSubMenu(0, 102, 0, res.getString(R.string.list_menu)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 7, 0, res.getString(R.string.list_menu_create));
+ subMenu.add(0, 8, 0, res.getString(R.string.list_menu_drop));
+ subMenu.add(0, 17, 0, res.getString(R.string.list_menu_change));
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ if (adapter != null && adapter.getSelectMode() == true) {
+ menu.findItem(0).setTitle(res.getString(R.string.caches_select_mode_exit));
+ menu.findItem(9).setVisible(true);
+ } else {
+ menu.findItem(0).setTitle(res.getString(R.string.caches_select_mode));
+ menu.findItem(9).setVisible(false);
+ }
+
+ if (type != null && type.equals("offline") == true) {
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(5).setTitle(res.getString(R.string.caches_drop_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(5).setTitle(res.getString(R.string.caches_drop_all));
+ }
+
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_refresh_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_refresh_all));
+ }
+ } else {
+ if (adapter == null) {
+ Log.i(cgSettings.tag, "No adapter");
+ } else {
+ Log.i(cgSettings.tag, "Checked: " + adapter.getChecked());
+ }
+ if (adapter != null && adapter.getChecked() > 0) {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_store_selected) + " (" + adapter.getChecked() + ")");
+ } else {
+ menu.findItem(1).setTitle(res.getString(R.string.caches_store_offline));
+ }
+ }
+
+ if (type != null && type.equals("offline") == false && (cacheList != null && app != null && cacheList.size() >= app.getTotal(searchId))) { // there are no more caches
+ menu.findItem(0).setEnabled(false);
+ } else {
+ menu.findItem(0).setEnabled(true);
+ }
+
+ if (listId == 1) {
+ menu.findItem(8).setVisible(false);
+ } else {
+ menu.findItem(8).setVisible(true);
+ }
+ if (app.getLists().size() < 2) {
+ menu.findItem(17).setVisible(false);
+ } else {
+ menu.findItem(17).setVisible(true);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu: " + e.toString());
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case 0:
+ if (adapter != null) {
+ adapter.switchSelectMode();
+ }
+ return true;
+ case 1:
+ refreshStored();
+ return true;
+ case 2:
+ showOnMap();
+ return false;
+ case 3:
+ showOnLocus();
+ return false;
+ case 5:
+ dropStored();
+ return false;
+ case 6:
+ importGpx();
+ return false;
+ case 7:
+ createList();
+ return false;
+ case 8:
+ removeList();
+ return false;
+ case 9:
+ if (adapter != null) {
+ adapter.invertSelection();
+ }
+ return false;
+ case 10:
+ setComparator(item, null);
+ return false;
+ case 11:
+ setComparator(item, new cgCacheDifficultyComparator());
+ return false;
+ case 12:
+ setComparator(item, new cgCacheTerrainComparator());
+ return false;
+ case 13:
+ setComparator(item, new cgCacheSizeComparator());
+ return false;
+ case 14:
+ setComparator(item, new cgCachePopularityComparator());
+ return false;
+ case 15:
+ setComparator(item, new cgCacheNameComparator());
+ return false;
+ case 16:
+ setComparator(item, new cgCacheGeocodeComparator());
+ return false;
+ case 17:
+ selectList(null);
+ return false;
+ case 18:
+ setComparator(item, new cgCacheRatingComparator());
+ return false;
+ case 19:
+ setComparator(item, new cgCacheVoteComparator());
+ return false;
+ case 20:
+ setComparator(item, new cgCacheInventoryComparator());
+ return false;
+ case 21:
+ selectedFilter = res.getString(R.string.caches_filter_type);
+ openContextMenu(getListView());
+ return false;
+ case 22:
+ selectedFilter = res.getString(R.string.caches_filter_size);
+ openContextMenu(getListView());
+ return false;
+ case 23:
+ adapter.setFilter(new cgFilterByTrackables());
+ return false;
+ case 24:
+ if (adapter != null) {
+ adapter.setFilter(null);
+ }
+ return false;
+ case 25:
+ importWeb();
+ return false;
+ }
+
+ return false;
+ }
+
+ private void setComparator(MenuItem item,
+ Comparator<cgCache> comparator) {
+ if (adapter != null) {
+ adapter.setComparator(comparator);
+ }
+ item.setChecked(true);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+
+ if (adapter == null) {
+ return;
+ }
+
+ AdapterContextMenuInfo adapterInfo = null;
+ try {
+ adapterInfo = (AdapterContextMenuInfo) info;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeocaches.onCreateContextMenu: " + e.toString());
+ }
+
+ if ((adapterInfo == null || adapterInfo.position < 0) && selectedFilter != null){
+ // Context menu opened by selecting an option on the filter submenu
+
+ if (selectedFilter.equals(res.getString(R.string.caches_filter_size))) {
+ menu.setHeaderTitle(res.getString(R.string.caches_filter_size_title));
+ menu.add(0, 8, 0, res.getString(R.string.caches_filter_size_micro));
+ menu.add(0, 9, 0, res.getString(R.string.caches_filter_size_small));
+ menu.add(0, 10, 0, res.getString(R.string.caches_filter_size_regular));
+ menu.add(0, 11, 0, res.getString(R.string.caches_filter_size_large));
+ menu.add(0, 12, 0, res.getString(R.string.caches_filter_size_other));
+ menu.add(0, 13, 0, res.getString(R.string.caches_filter_size_virtual));
+ menu.add(0, 14, 0, res.getString(R.string.caches_filter_size_notchosen));
+ } else if (selectedFilter.equals(res.getString(R.string.caches_filter_type))) {
+ menu.setHeaderTitle(res.getString(R.string.caches_filter_type_title));
+ menu.add(0, 15, 0, res.getString(R.string.caches_filter_type_traditional));
+ menu.add(0, 16, 0, res.getString(R.string.caches_filter_type_multi));
+ menu.add(0, 17, 0, res.getString(R.string.caches_filter_type_mystery));
+ menu.add(0, 18, 0, res.getString(R.string.caches_filter_type_letterbox));
+ menu.add(0, 19, 0, res.getString(R.string.caches_filter_type_event));
+ menu.add(0, 20, 0, res.getString(R.string.caches_filter_type_mega));
+ menu.add(0, 21, 0, res.getString(R.string.caches_filter_type_earth));
+ menu.add(0, 22, 0, res.getString(R.string.caches_filter_type_cito));
+ menu.add(0, 23, 0, res.getString(R.string.caches_filter_type_webcam));
+ menu.add(0, 24, 0, res.getString(R.string.caches_filter_type_virtual));
+ menu.add(0, 25, 0, res.getString(R.string.caches_filter_type_wherigo));
+ menu.add(0, 26, 0, res.getString(R.string.caches_filter_type_lostfound));
+ menu.add(0, 27, 0, res.getString(R.string.caches_filter_type_ape));
+ menu.add(0, 28, 0, res.getString(R.string.caches_filter_type_gchq));
+ menu.add(0, 29, 0, res.getString(R.string.caches_filter_type_gps));
+ }
+ } else{
+ final cgCache cache = adapter.getItem(adapterInfo.position);
+
+ if (cache.name != null && cache.name.length() > 0) {
+ menu.setHeaderTitle(cache.name);
+ } else {
+ menu.setHeaderTitle(cache.geocode);
+ }
+
+ if (cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 1, 0, res.getString(R.string.cache_menu_compass));
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_radar));
+ menu.add(0, 3, 0, res.getString(R.string.cache_menu_map));
+ menu.add(0, 4, 0, res.getString(R.string.cache_menu_map_ext));
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_tbt));
+ menu.add(0, 6, 0, res.getString(R.string.cache_menu_visit));
+ menu.add(0, 7, 0, res.getString(R.string.cache_menu_details));
+ }
+ }
+
+ ArrayList<cgList> cacheLists = app.getLists();
+ int listCount = cacheLists.size();
+ if (listCount > 1) {
+ SubMenu submenu = menu.addSubMenu(0, 8, 0, res.getString(R.string.cache_menu_move_list));
+ for (int i = 0; i < listCount; i++) {
+ cgList list = cacheLists.get(i);
+ submenu.add(Menu.NONE, 100+list.id, Menu.NONE, list.title);
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+ ContextMenu.ContextMenuInfo info = item.getMenuInfo();
+
+ if (info == null) {
+ if(adapter != null){
+ if (id == 8) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_micro)));
+ } else if (id == 9) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_small)));
+ } else if (id == 10) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_regular)));
+ } else if (id == 11) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_large)));
+ } else if (id == 12) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_other)));
+ } else if (id == 13) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_virtual)));
+ } else if (id == 14) {
+ adapter.setFilter(new cgFilterBySize(res.getString(R.string.caches_filter_size_notchosen)));
+ } else if (id == 15) {
+ adapter.setFilter(new cgFilterByType("traditional"));
+ } else if (id == 16) {
+ adapter.setFilter(new cgFilterByType("multi"));
+ } else if (id == 17) {
+ adapter.setFilter(new cgFilterByType("mystery"));
+ } else if (id == 18) {
+ adapter.setFilter(new cgFilterByType("letterbox"));
+ } else if (id == 19) {
+ adapter.setFilter(new cgFilterByType("event"));
+ } else if (id == 20) {
+ adapter.setFilter(new cgFilterByType("mega"));
+ } else if (id == 21) {
+ adapter.setFilter(new cgFilterByType("earth"));
+ } else if (id == 22) {
+ adapter.setFilter(new cgFilterByType("cito"));
+ } else if (id == 23) {
+ adapter.setFilter(new cgFilterByType("webcam"));
+ } else if (id == 24) {
+ adapter.setFilter(new cgFilterByType("virtual"));
+ } else if (id == 25) {
+ adapter.setFilter(new cgFilterByType("wherigo"));
+ } else if (id == 26) {
+ adapter.setFilter(new cgFilterByType("lostfound"));
+ } else if (id == 27) {
+ adapter.setFilter(new cgFilterByType("ape"));
+ } else if (id == 28) {
+ adapter.setFilter(new cgFilterByType("gchq"));
+ } else if (id == 29) {
+ adapter.setFilter(new cgFilterByType("gps"));
+ } else {
+ return false;
+ }
+ return true;
+ } else {
+ // restore menu info for sub menu items, see https://code.google.com/p/android/issues/detail?id=7139
+ info = lastMenuInfo;
+ lastMenuInfo = null;
+ return false;
+ }
+ }
+
+ AdapterContextMenuInfo adapterInfo = null;
+ try {
+ adapterInfo = (AdapterContextMenuInfo) info;
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeocaches.onContextItemSelected: " + e.toString());
+ }
+
+ final int touchedPos = adapterInfo.position;
+ final cgCache cache = adapter.getItem(touchedPos);
+
+ if (id == 1) { // compass
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ activity.startActivity(navigateIntent);
+
+ return true;
+ } else if (id == 2) { // radar
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeocaches.onContextItemSelected.radar.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeocaches.onContextItemSelected.radar: " + e.toString());
+ }
+
+ return true;
+ } else if (id == 3) { // show on map
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("geocode", cache.geocode);
+
+ activity.startActivity(mapIntent);
+
+ return true;
+ } else if (id == 4) { // show on external map
+ base.runExternalMap(0, activity, res, warning, tracker, cache);
+
+ return true;
+ } else if (id == 5) { // turn-by-turn
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (id == 6) { // log visit
+ if (cache.cacheid == null || cache.cacheid.length() == 0) {
+ warning.showToast(res.getString(R.string.err_cannot_log_visit));
+ return true;
+ }
+
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+
+ activity.startActivity(logVisitIntent);
+
+ return true;
+ } else if (id == 7) { // cache details
+ Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ cachesIntent.putExtra("name", cache.name);
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 8) { // move to list (sub menu)
+ // we must remember the menu info for the sub menu, there is a bug in Android:
+ // https://code.google.com/p/android/issues/detail?id=7139
+ lastMenuInfo = info;
+ return true;
+ } else if (id >= 100) { // move to list
+ int newListId = id - 100;
+ app.moveToList(cache.geocode, newListId);
+ // refresh list by switching to the current list
+ switchListById(listId);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (adapter != null) {
+ if (adapter.resetChecks() == true) {
+ return;
+ } else if (adapter.getSelectMode() == true) {
+ adapter.setSelectMode(false, true);
+
+ return;
+ }
+
+ if (adapter.isFilter()) {
+ adapter.clearFilter();
+
+ return;
+ }
+ }
+
+ super.onBackPressed();
+
+ return;
+ }
+
+ private void setAdapter() {
+ if (listFooter == null) {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+ listFooter = inflater.inflate(R.layout.caches_footer, null);
+
+ listFooter.setClickable(true);
+ listFooter.setOnClickListener(new moreCachesListener());
+ }
+ if (listFooterText == null) {
+ listFooterText = (TextView) listFooter.findViewById(R.id.more_caches);
+ }
+
+ if (adapter == null) {
+ final ListView list = getListView();
+
+ registerForContextMenu(list);
+ list.setLongClickable(true);
+ list.addFooterView(listFooter);
+
+ adapter = new cgCacheListAdapter(activity, settings, cacheList, base);
+ setListAdapter(adapter);
+ } else {
+ adapter.notifyDataSetChanged();
+ }
+
+ if (adapter != null && geo != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ }
+ if (adapter != null && dir != null) {
+ adapter.setActualHeading(dir.directionNow);
+ }
+ }
+
+ private void setLoadingCaches() {
+ if (listFooter == null) {
+ return;
+ }
+ if (listFooterText == null) {
+ return;
+ }
+
+ listFooterText.setText(res.getString(R.string.caches_more_caches_loading));
+ listFooter.setClickable(false);
+ listFooter.setOnClickListener(null);
+ }
+
+ private void setMoreCaches(boolean more) {
+ if (listFooter == null) {
+ return;
+ }
+ if (listFooterText == null) {
+ return;
+ }
+
+ if (more == false) {
+ if (cacheList == null || cacheList.isEmpty()) {
+ listFooterText.setText(res.getString(R.string.caches_no_cache));
+ } else {
+ listFooterText.setText(res.getString(R.string.caches_more_caches_no));
+ }
+ listFooter.setClickable(false);
+ listFooter.setOnClickListener(null);
+ } else {
+ listFooterText.setText(res.getString(R.string.caches_more_caches));
+ listFooter.setClickable(true);
+ listFooter.setOnClickListener(new moreCachesListener());
+ }
+ }
+
+ private void init() {
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ if (cacheList != null) {
+ base.setTitle(activity, title);
+ }
+
+ if (cacheList != null && cacheList.isEmpty() == false) {
+ final Integer count = app.getTotal(searchId);
+ if (count != null && count > 0) {
+ base.setTitle(activity, title);
+ if (cacheList.size() < app.getTotal(searchId) && cacheList.size() < 1000) {
+ setMoreCaches(true);
+ } else {
+ setMoreCaches(false);
+ }
+ } else {
+ base.setTitle(activity, title);
+ setMoreCaches(false);
+ }
+ } else {
+ base.setTitle(activity, title);
+ }
+
+ setAdapter();
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+ }
+
+ private void showOnMap() {
+ if (searchId == null || searchId == 0 || cacheList == null || cacheList.isEmpty() == true) {
+ warning.showToast(res.getString(R.string.warn_no_cache_coord));
+
+ return;
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("searchid", searchId);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void showOnLocus() {
+ if (cacheList == null || cacheList.isEmpty() == true) {
+ return;
+ }
+
+ try {
+ final Intent intentTest = new Intent(Intent.ACTION_VIEW);
+ intentTest.setData(Uri.parse("menion.points:x"));
+
+ if (cgBase.isIntentAvailable(activity, intentTest) == false) {
+ return;
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ final ArrayList<cgCache> cacheListCoord = new ArrayList<cgCache>();
+ for (cgCache cache : cacheListTemp) {
+ if (cache.latitude != null && cache.longitude != null) {
+ cacheListCoord.add(cache);
+ }
+ }
+ cacheListTemp.clear();
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(baos);
+
+ dos.writeInt(1); // not used
+ dos.writeInt(cacheListCoord.size()); // cache and waypoints
+
+ // cache waypoints
+ if (cacheListCoord != null && cacheListCoord.isEmpty() == false) {
+ for (cgCache cache : cacheListCoord) {
+ final int wpIcon = base.getIcon(true, cache.type, cache.own, cache.found, cache.disabled);
+
+ if (wpIcon > 0) {
+ // load icon
+ Bitmap bitmap = BitmapFactory.decodeResource(res, wpIcon);
+ ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2);
+ byte[] image = baos2.toByteArray();
+
+ dos.writeInt(image.length);
+ dos.write(image);
+ } else {
+ // no icon
+ dos.writeInt(0); // no image
+ }
+
+ // name
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF(cache.geocode.toUpperCase());
+ } else {
+ dos.writeUTF("");
+ }
+
+ // description
+ if (cache != null && cache.name != null && cache.name.length() > 0) {
+ dos.writeUTF(cache.name);
+ } else {
+ dos.writeUTF("");
+ }
+
+ // additional data :: keyword, button title, package, activity, data name, data content
+ if (cache != null && cache.geocode != null && cache.geocode.length() > 0) {
+ dos.writeUTF("intent;c:geo;cgeo.geocaching;cgeo.geocaching.cgeodetail;geocode;" + cache.geocode);
+ } else {
+ dos.writeUTF("");
+ }
+
+ dos.writeDouble(cache.latitude); // latitude
+ dos.writeDouble(cache.longitude); // longitude
+ }
+ }
+
+ final Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse("menion.points:data"));
+ intent.putExtra("data", baos.toByteArray());
+
+ activity.startActivity(intent);
+
+ base.sendAnal(activity, tracker, "/external/locus");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ private void importGpx() {
+ final Intent intent = new Intent(activity, cgeogpxes.class);
+ intent.putExtra("list", listId);
+ activity.startActivity(intent);
+
+ finish();
+ }
+
+ public void refreshStored() {
+ if (adapter != null && adapter.getChecked() > 0) {
+ // there are some checked caches
+ detailTotal = adapter.getChecked();
+ } else {
+ // no checked caches, download everything (when already stored - refresh them)
+ detailTotal = cacheList.size();
+ }
+ detailProgress = 0;
+
+ base.showProgress(activity, false);
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadD != null) {
+ threadD.kill();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onOptionsItemSelected.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ int etaTime = (int) ((detailTotal * 25) / 60);
+ if (etaTime < 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime == 1) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + etaTime + " " + res.getString(R.string.caches_eta_mins));
+ }
+ waitDialog.setCancelable(true);
+ waitDialog.setMax(detailTotal);
+ waitDialog.show();
+
+ detailProgressTime = System.currentTimeMillis();
+
+ threadD = new geocachesLoadDetails(loadDetailsHandler, listId);
+ threadD.start();
+ }
+
+ public void importWeb() {
+ detailProgress = 0;
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ base.showProgress(activity, false);
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadW != null) {
+ threadW.kill();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.livelist == 1 && settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.importWeb.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ waitDialog.setMessage(res.getString(R.string.web_import_waiting));
+ waitDialog.setCancelable(true);
+ waitDialog.show();
+
+ threadW = new geocachesLoadFromWeb(downloadFromWebHandler, listId);
+ threadW.start();
+ }
+
+ public void dropStored() {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setCancelable(true);
+ dialog.setTitle(res.getString(R.string.caches_drop_stored));
+
+ if (adapter != null && adapter.getChecked() > 0) {
+ dialog.setMessage(res.getString(R.string.caches_drop_selected_ask));
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dropSelected();
+ dialog.cancel();
+ }
+ });
+ } else {
+ dialog.setMessage(res.getString(R.string.caches_drop_all_ask));
+ dialog.setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dropSelected();
+ dialog.cancel();
+ }
+ });
+ }
+ dialog.setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+
+ public void dropSelected() {
+ waitDialog = new ProgressDialog(this);
+ waitDialog.setMessage(res.getString(R.string.caches_drop_progress));
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (threadR != null) {
+ threadR.kill();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onOptionsItemSelected.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ waitDialog.setCancelable(true);
+ waitDialog.show();
+
+ threadR = new geocachesDropDetails(dropDetailsHandler);
+ threadR.start();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+ if (adapter == null) {
+ return;
+ }
+
+ try {
+ if (cacheList != null && geo.latitudeNow != null && geo.longitudeNow != null) {
+ adapter.setActualCoordinates(geo.latitudeNow, geo.longitudeNow);
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (settings.useCompass == 0) {
+ if (geo.bearingNow != null) {
+ adapter.setActualHeading(geo.bearingNow);
+ } else {
+ adapter.setActualHeading(new Double(0));
+ }
+ }
+ if (northHeading != null) {
+ adapter.setActualHeading(northHeading);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class updateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (settings.livelist == 0) {
+ return;
+ }
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ northHeading = dir.directionNow;
+ if (northHeading != null && adapter != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h) {
+ adapter.setActualHeading(northHeading);
+ }
+ }
+ }
+
+ private class geocachesLoadByOffline extends Thread {
+
+ private Handler handler = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private int listId = 1;
+
+ public geocachesLoadByOffline(Handler handlerIn, Double latitudeIn, Double longitudeIn, int listIdIn) {
+ handler = handlerIn;
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ listId = listIdIn;
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, Object> params = new HashMap<String, Object>();
+ if (latitude != null && longitude != null) {
+ params.put("latitude", latitude);
+ params.put("longitude", longitude);
+ params.put("cachetype", settings.cacheType);
+ params.put("list", listId);
+ }
+
+ searchId = base.searchByOffline(params);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByHistory extends Thread {
+
+ private Handler handler = null;
+
+ public geocachesLoadByHistory(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, Object> params = new HashMap<String, Object>();
+ if (latitude != null && longitude != null) {
+ params.put("cachetype", settings.cacheType);
+ }
+
+ searchId = base.searchByHistory(params);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadNextPage extends cgSearchThread {
+
+ private Handler handler = null;
+
+ public geocachesLoadNextPage(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ searchId = base.searchByNextPage(this, searchId, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByCoords extends cgSearchThread {
+
+ private Handler handler = null;
+ private Double latitude = null;
+ private Double longitude = null;
+ private String cachetype = null;
+
+ public geocachesLoadByCoords(Handler handlerIn, Double latitudeIn, Double longitudeIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ latitude = latitudeIn;
+ longitude = longitudeIn;
+ cachetype = cachetypeIn;
+
+ if (latitude == null || longitude == null) {
+ warning.showToast(res.getString(R.string.warn_no_coordinates));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("latitude", String.format((Locale) null, "%.6f", latitude));
+ params.put("longitude", String.format((Locale) null, "%.6f", longitude));
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByCoords(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByKeyword extends cgSearchThread {
+
+ private Handler handler = null;
+ private String keyword = null;
+ private String cachetype = null;
+
+ public geocachesLoadByKeyword(Handler handlerIn, String keywordIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ keyword = keywordIn;
+ cachetype = cachetypeIn;
+
+ if (keyword == null) {
+ warning.showToast(res.getString(R.string.warn_no_keyword));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("keyword", keyword);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByKeyword(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByUserName extends cgSearchThread {
+
+ private Handler handler = null;
+ private String username = null;
+ private String cachetype = null;
+
+ public geocachesLoadByUserName(Handler handlerIn, String usernameIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ username = usernameIn;
+ cachetype = cachetypeIn;
+
+ if (username == null || username.length() == 0) {
+ warning.showToast(res.getString(R.string.warn_no_username));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("username", username);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByUsername(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadByOwner extends cgSearchThread {
+
+ private Handler handler = null;
+ private String username = null;
+ private String cachetype = null;
+
+ public geocachesLoadByOwner(Handler handlerIn, String usernameIn, String cachetypeIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ username = usernameIn;
+ cachetype = cachetypeIn;
+
+ if (username == null || username.length() == 0) {
+ warning.showToast(res.getString(R.string.warn_no_username));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("username", username);
+ params.put("cachetype", cachetype);
+
+ searchId = base.searchByOwner(this, params, 0, settings.showCaptcha);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class geocachesLoadDetails extends Thread {
+
+ private Handler handler = null;
+ private int reason = 1;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+ private long last = 0l;
+
+ public geocachesLoadDetails(Handler handlerIn, int reasonIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ reason = reasonIn;
+
+ if (adapter != null) {
+ checked = adapter.getChecked();
+ }
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (checked > 0 && cache.statusChecked == false) {
+ handler.sendEmptyMessage(0);
+
+ yield();
+ continue;
+ }
+
+ try {
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+ break;
+ }
+
+ if ((System.currentTimeMillis() - last) < 1500) {
+ try {
+ int delay = 1000 + ((Double) (Math.random() * 1000)).intValue() - (int) (System.currentTimeMillis() - last);
+ if (delay < 0) {
+ delay = 500;
+ }
+
+ Log.i(cgSettings.tag, "Waiting for next cache " + delay + " ms");
+ sleep(delay);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadDetails.sleep: " + e.toString());
+ }
+ }
+
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+ break;
+ }
+
+ detailProgress++;
+ base.storeCache(app, activity, cache, null, reason, handler);
+
+ handler.sendEmptyMessage(cacheList.indexOf(cache));
+
+ yield();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadDetails: " + e.toString());
+ }
+
+ last = System.currentTimeMillis();
+ }
+ cacheListTemp.clear();
+
+ handler.sendEmptyMessage(-1);
+ }
+ }
+
+ //tg
+ private class geocachesLoadFromWeb extends Thread {
+
+ private Handler handler = null;
+ private int reason = 1;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+ private long last = 0l;
+
+ public geocachesLoadFromWeb(Handler handlerIn, int reasonIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+ reason = reasonIn;
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ int delay=-1;
+ int times=0;
+
+ while (times < 36) //3 minutes max
+ {
+ if (needToStop)
+ {
+ handler.sendEmptyMessage(-1);
+ break;
+ }
+
+ //download new code
+ String deviceCode = settings.webDeviceCode;
+ if (deviceCode==null) deviceCode="";
+ cgResponse responseFromWeb = base.request(false, "send2cgeo.carnero.cc", "/readCode.php", "GET", "d=" + cgBase.urlencode_rfc3986(deviceCode), 0, true);
+
+ if ((responseFromWeb.getStatusCode() == 200)&&(responseFromWeb.getData().length()>2)) {
+
+ String GCcode = responseFromWeb.getData();
+
+ delay=1;
+ Message mes = new Message();
+ mes.what=1;
+ mes.obj=GCcode;
+ handler.sendMessage(mes);
+ yield();
+
+ base.storeCache(app, activity, null, GCcode, reason, null);
+
+ Message mes1 = new Message();
+ mes1.what=2;
+ mes1.obj=GCcode;
+ handler.sendMessage(mes1);
+ yield();
+ } else {
+ delay=0;
+ handler.sendEmptyMessage(0);
+ yield();
+ }
+ if (responseFromWeb.getStatusCode() != 200) {
+ needToStop = true;
+ settings.setWebNameCode(null, null);
+ handler.sendEmptyMessage(-2);
+ return;
+ }
+
+ try {
+ yield();
+ if (delay==0)
+ {
+ sleep(5000); //No caches 5s
+ times++;
+ } else {
+ sleep(500); //Cache was loaded 0.5s
+ times=0;
+ }
+ } catch (InterruptedException e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesLoadFromWeb.sleep: " + e.toString());
+ }
+ }
+ handler.sendEmptyMessage(-1);
+ }
+ }
+ //tg
+
+ private class geocachesDropDetails extends Thread {
+
+ private Handler handler = null;
+ private volatile boolean needToStop = false;
+ private int checked = 0;
+
+ public geocachesDropDetails(Handler handlerIn) {
+ setPriority(Thread.MIN_PRIORITY);
+
+ handler = handlerIn;
+
+ if (adapter != null) {
+ checked = adapter.getChecked();
+ }
+ }
+
+ public void kill() {
+ needToStop = true;
+ }
+
+ @Override
+ public void run() {
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (checked > 0 && cache.statusChecked == false) {
+ handler.sendEmptyMessage(0);
+
+ yield();
+ continue;
+ }
+
+ try {
+ if (needToStop == true) {
+ Log.i(cgSettings.tag, "Stopped dropping process.");
+ break;
+ }
+
+ app.markDropped(cache.geocode);
+
+ handler.sendEmptyMessage(cacheList.indexOf(cache));
+
+ yield();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.geocachesDropDetails: " + e.toString());
+ }
+ }
+ cacheListTemp.clear();
+
+ handler.sendEmptyMessage(-1);
+ }
+ }
+
+ private class moreCachesListener implements View.OnClickListener {
+
+ @Override
+ public void onClick(View arg0) {
+ base.showProgress(activity, true);
+ setLoadingCaches();
+ listFooter.setOnClickListener(null);
+
+ geocachesLoadNextPage thread;
+ thread = new geocachesLoadNextPage(loadNextPageHandler);
+ thread.setRecaptchaHandler(new cgSearchHandler(activity, res, thread));
+ thread.start();
+ }
+ }
+
+ private void hideLoading() {
+ final ListView list = getListView();
+ final RelativeLayout loading = (RelativeLayout) findViewById(R.id.loading);
+
+ if (list.getVisibility() == View.GONE) {
+ list.setVisibility(View.VISIBLE);
+ loading.setVisibility(View.GONE);
+ }
+ }
+
+ public void selectList(View view) {
+ if (type.equals("offline") == false) {
+ return;
+ }
+
+ lists = app.getLists();
+
+ if (lists == null) {
+ return;
+ }
+
+ final ArrayList<CharSequence> listsTitle = new ArrayList<CharSequence>();
+ for (cgList list : lists) {
+ listsTitle.add(list.title);
+ }
+
+ final CharSequence[] items = new CharSequence[listsTitle.size()];
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(res.getString(R.string.list_title));
+ builder.setItems(listsTitle.toArray(items), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialogInterface, int item) {
+ switchListByOrder(item);
+
+ return;
+ }
+ });
+ builder.create().show();
+ }
+
+ public void switchListByOrder(int order) {
+ switchList(-1, order);
+ }
+
+ public void switchListById(int id) {
+ switchList(id, -1);
+ }
+
+ public void switchList(int id, int order) {
+ cgList list = null;
+
+ if (id >= 0) {
+ list = app.getList(id);
+ } else if (order >= 0) {
+ lists = app.getLists();
+ list = lists.get(order);
+ } else {
+ return;
+ }
+
+ if (list == null) {
+ return;
+ }
+
+ listId = list.id;
+ title = list.title;
+
+ settings.saveLastList(listId);
+
+ base.showProgress(activity, true);
+ setLoadingCaches();
+
+ Handler handlerMove = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Thread threadPure = new geocachesLoadByOffline(loadCachesHandler, latitude, longitude, msg.what);
+ threadPure.start();
+ }
+ };
+
+ (new moveCachesToList(listId, handlerMove)).start();
+ }
+
+ private class moveCachesToList extends Thread {
+ int listId = -1;
+ Handler handler = null;
+
+ public moveCachesToList(int listIdIn, Handler handlerIn) {
+ listId = listIdIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ int checked = adapter.getChecked();
+ if (checked > 0) {
+ final ArrayList<cgCache> cacheListTemp = (ArrayList<cgCache>) cacheList.clone();
+ for (cgCache cache : cacheListTemp) {
+ if (cache.statusChecked != false) {
+ app.moveToList(cache.geocode, listId);
+ }
+ }
+ }
+
+ handler.sendEmptyMessage(listId);
+ }
+ }
+
+ private void createList() {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(this);
+ final View view = inflater.inflate(R.layout.list_create_dialog, null);
+ final EditText input = (EditText) view.findViewById(R.id.text);
+
+ alert.setTitle(R.string.list_dialog_create_title);
+ alert.setView(view);
+ alert.setPositiveButton(R.string.list_dialog_create, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ String value = input.getText().toString();
+ // remove whitespaces added by autocompletion of Android keyboard
+ if (value != null) {
+ value = value.trim();
+ }
+
+ if (value != null && value.length() > 0) {
+ int newId = app.createList(value);
+
+ if (newId >= 10) {
+ warning.showToast(res.getString(R.string.list_dialog_create_ok));
+ } else {
+ warning.showToast(res.getString(R.string.list_dialog_create_err));
+ }
+ }
+ }
+ });
+ alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ dialog.dismiss();
+ }
+ });
+
+ alert.show();
+ }
+
+ private void removeList() {
+ final AlertDialog.Builder alert = new AlertDialog.Builder(this);
+
+ alert.setTitle(R.string.list_dialog_remove_title);
+ alert.setMessage(R.string.list_dialog_remove_description);
+ alert.setPositiveButton(R.string.list_dialog_remove, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ boolean status = app.removeList(listId);
+
+ if (status) {
+ warning.showToast(res.getString(R.string.list_dialog_remove_ok));
+ switchListById(1);
+ } else {
+ warning.showToast(res.getString(R.string.list_dialog_remove_err));
+ }
+ }
+ });
+ alert.setNegativeButton(res.getString(R.string.list_dialog_cancel), new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ dialog.dismiss();
+ }
+ });
+
+ alert.show();
+ }
+
+ public void goMap(View view) {
+ showOnMap();
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ if (type != null && type.equals("offline") == true) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-stored",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } else if (type != null && type.equals("history") == true) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-history",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } else {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-nearby",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeodate.java b/src/cgeo/geocaching/cgeodate.java
new file mode 100644
index 0000000..b0d5b5b
--- /dev/null
+++ b/src/cgeo/geocaching/cgeodate.java
@@ -0,0 +1,62 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.app.Dialog;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.widget.DatePicker;
+import java.util.Calendar;
+
+public class cgeodate extends Dialog {
+
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgLogForm parent = null;
+ private Calendar date = Calendar.getInstance();
+
+ public cgeodate(Activity contextIn, cgLogForm parentIn, Calendar dateIn) {
+ super(contextIn);
+
+ // init
+ settings = new cgSettings(contextIn, contextIn.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase((cgeoapplication) contextIn.getApplication(), settings, contextIn.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(contextIn);
+ date = dateIn;
+
+ parent = parentIn;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ setContentView(R.layout.date);
+
+ // google analytics
+ base.sendAnal(this.getContext(), "/date");
+
+ DatePicker picker = (DatePicker) findViewById(R.id.picker);
+ picker.init(date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DATE), new pickerListener());
+ }
+
+ public class pickerListener implements DatePicker.OnDateChangedListener {
+
+ @Override
+ public void onDateChanged(DatePicker picker, int year, int month, int day) {
+ if (parent != null) {
+ date.set(year, month, day);
+
+ parent.setDate(date);
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeodetail.java b/src/cgeo/geocaching/cgeodetail.java
new file mode 100644
index 0000000..a786cb3
--- /dev/null
+++ b/src/cgeo/geocaching/cgeodetail.java
@@ -0,0 +1,1902 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.ContentValues;
+import android.content.Context;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.widget.ScrollView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.ImageView;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.SubMenu;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+public class cgeodetail extends Activity {
+ public Long searchId = null;
+ public cgCache cache = null;
+ public String geocode = null;
+ public String name = null;
+ public String guid = null;
+ private GoogleAnalyticsTracker tracker = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private float pixelRatio = 1;
+ private TextView cacheDistance = null;
+ private String contextMenuUser = null;
+ private ProgressDialog waitDialog = null;
+ private ProgressDialog descDialog = null;
+ private Spanned longDesc = null;
+ private Boolean longDescDisplayed = false;
+ private loadCache threadCache = null;
+ private loadLongDesc threadLongDesc = null;
+ private Thread storeThread = null;
+ private Thread refreshThread = null;
+ private HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ private ProgressDialog storeDialog = null;
+ private ProgressDialog refreshDialog = null;
+ private ProgressDialog dropDialog = null;
+ private HashMap<Integer, String> calendars = new HashMap<Integer, String>();
+ private Handler storeCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ storeThread = null;
+
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_store_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.storeCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler refreshCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ refreshThread = null;
+
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_refresh_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.refreshCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler dropCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ cache = app.getCache(searchId); // reload cache details
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_drop_failed));
+
+ Log.e(cgSettings.tag, "cgeodetail.dropCacheHandler: " + e.toString());
+ }
+
+ setView();
+ }
+ };
+
+ private Handler loadCacheHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (searchId == null || searchId <= 0) {
+ warning.showToast(res.getString(R.string.err_dwld_details_failed));
+
+ finish();
+ return;
+ }
+
+ if (app.getError(searchId) != null) {
+ warning.showToast(res.getString(R.string.err_dwld_details_failed_reason) + " " + app.getError(searchId) + ".");
+
+ finish();
+ return;
+ }
+
+ setView();
+
+ if (settings.autoLoadDesc == 1) {
+ try {
+ loadLongDesc();
+ } catch (Exception e) {
+ // activity is not visible
+ }
+ }
+
+ (new loadMapPreview(cache, loadMapPreviewHandler)).start();
+ }
+ };
+
+ final Handler loadMapPreviewHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ ScrollView scroll = (ScrollView) findViewById(R.id.details_list_box);
+ ImageView view = (ImageView) findViewById(R.id.map_preview);
+
+ if (image != null && view != null) {
+ view.setImageDrawable(image);
+
+ if (scroll.getScrollY() == 0) {
+ scroll.scrollTo(0, (int) (80 * pixelRatio));
+ }
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+ };
+
+ private Handler loadDescriptionHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (longDesc == null && cache != null && cache.description != null) {
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ }
+
+ if (longDesc != null) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.description);
+ if (cache.description.length() > 0) {
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(longDesc, TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ else {
+ descView.setVisibility(View.GONE);
+ }
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.GONE);
+ showDesc.setOnTouchListener(null);
+ showDesc.setOnClickListener(null);
+ } else {
+ warning.showToast(res.getString(R.string.err_load_descr_failed));
+ }
+
+ if (descDialog != null && descDialog.isShowing()) {
+ descDialog.dismiss();
+ }
+
+ longDescDisplayed = true;
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.detail);
+ base.setTitle(activity, res.getString(R.string.cache));
+
+ init();
+
+ // get parameters
+ final Bundle extras = getIntent().getExtras();
+ final Uri uri = getIntent().getData();
+
+ // try to get data from extras
+ if (geocode == null && extras != null) {
+ geocode = extras.getString("geocode");
+ name = extras.getString("name");
+ guid = extras.getString("guid");
+ }
+
+ // try to get data from URI
+ if (geocode == null && guid == null && uri != null) {
+ String uriHost = uri.getHost().toLowerCase();
+ String uriPath = uri.getPath().toLowerCase();
+ String uriQuery = uri.getQuery();
+
+ if (uriQuery != null) {
+ Log.i(cgSettings.tag, "Opening URI: " + uriHost + uriPath + "?" + uriQuery);
+ } else {
+ Log.i(cgSettings.tag, "Opening URI: " + uriHost + uriPath);
+ }
+
+ if (uriHost.contains("geocaching.com") == true) {
+ geocode = uri.getQueryParameter("wp");
+ guid = uri.getQueryParameter("guid");
+
+ if (geocode != null && geocode.length() > 0) {
+ geocode = geocode.toUpperCase();
+ guid = null;
+ } else if (guid != null && guid.length() > 0) {
+ geocode = null;
+ guid = guid.toLowerCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ } else if (uriHost.contains("coord.info") == true) {
+ if (uriPath != null && uriPath.startsWith("/gc") == true) {
+ geocode = uriPath.substring(1).toUpperCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_detail_open));
+ finish();
+ return;
+ }
+ }
+ }
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ if (geocode != null) {
+ base.sendAnal(activity, tracker, "/cache/detail#" + geocode);
+ }
+
+ // no given data
+ if (geocode == null && guid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache));
+ finish();
+ return;
+ }
+
+ app.setAction(geocode);
+
+ try {
+ if (name != null && name.length() > 0) {
+ waitDialog = ProgressDialog.show(this, name, res.getString(R.string.cache_dialog_loading_details), true);
+ } else if (geocode != null && geocode.length() > 0) {
+ waitDialog = ProgressDialog.show(this, geocode.toUpperCase(), res.getString(R.string.cache_dialog_loading_details), true);
+ } else {
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.cache), res.getString(R.string.cache_dialog_loading_details), true);
+ }
+ waitDialog.setCancelable(true);
+ } catch (Exception e) {
+ // nothing, we lost the window
+ }
+
+ threadCache = new loadCache(loadCacheHandler, geocode, guid);
+ threadCache.start();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ setView();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ setView();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) tracker.stop();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.author || viewId == R.id.value) {
+ if (viewId == R.id.author) { // Author of a log entry
+ contextMenuUser = ((TextView)view).getText().toString();
+ } else if (viewId == R.id.value) { // The owner of the cache
+ if (cache.ownerReal != null && cache.ownerReal.length() > 0) {
+ contextMenuUser = cache.ownerReal;
+ } else {
+ contextMenuUser = cache.owner;
+ }
+ }
+
+ menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser);
+ menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden));
+ menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found));
+ menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser));
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+
+ if (group == R.id.author || group == R.id.value) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 2) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 3) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser))));
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 8, 0, res.getString(R.string.cache_menu_radar)); // radar
+ if (cache != null && cache.reason >= 1 && settings.storeOfflineMaps == 1) {
+ subMenu.add(1, 6, 0, res.getString(R.string.cache_menu_map_static)); // static maps
+ }
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 9, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+ }
+
+ if (cache != null && cache.hidden != null && (cache.type.equalsIgnoreCase("event") == true || cache.type.equalsIgnoreCase("mega") == true || cache.type.equalsIgnoreCase("cito") == true)) {
+ menu.add(1, 11, 0, res.getString(R.string.cache_menu_event)).setIcon(android.R.drawable.ic_menu_agenda); // add event to calendar
+ }
+ if (settings.isLogin() == true) {
+ menu.add(1, 3, 0, res.getString(R.string.cache_menu_visit)).setIcon(android.R.drawable.ic_menu_agenda); // log visit
+ }
+
+ if (cache != null && cache.spoilers != null && cache.spoilers.size() > 0) {
+ menu.add(1, 5, 0, res.getString(R.string.cache_menu_spoilers)).setIcon(android.R.drawable.ic_menu_gallery); // spoiler images
+ }
+
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.add(0, 10, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+ }
+
+ menu.add(1, 7, 0, res.getString(R.string.cache_menu_browser)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+ menu.add(0, 12, 0, res.getString(R.string.cache_menu_share)).setIcon(android.R.drawable.ic_menu_share); // share cache
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ logVisit();
+ return true;
+ } else if (menuItem == 5) {
+ showSpoilers();
+ return true;
+ } else if (menuItem == 6) {
+ showSmaps();
+ return true;
+ } else if (menuItem == 7) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.geocode)));
+ return true;
+ } else if (menuItem == 8) {
+ radarTo();
+ return true;
+ } else if (menuItem == 9) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (menuItem == 10) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 11) {
+ addToCalendar();
+ return true;
+ } else if (menuItem == 12) {
+ shareCache();
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, cache); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, cache); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, cache); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void init() {
+ final DisplayMetrics dm = getResources().getDisplayMetrics();
+ pixelRatio = dm.density;
+
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (searchId != null && searchId > 0) {
+ cache = app.getCache(searchId);
+ if (cache != null && cache.geocode != null) {
+ geocode = cache.geocode;
+ }
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ app.setAction(geocode);
+ }
+ }
+
+ private void setView() {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+
+ if (searchId == null) {
+ return;
+ }
+
+ cache = app.getCache(searchId);
+
+ if (cache == null) {
+ if (waitDialog != null && waitDialog.isShowing()) waitDialog.dismiss();
+
+ if (geocode != null && geocode.length() > 0) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find) + " " + geocode + ".");
+ } else {
+ geocode = null;
+ warning.showToast(res.getString(R.string.err_detail_cache_find_some));
+ }
+
+ finish();
+ return;
+ }
+
+ if (cache.reason >= 1) {
+ base.sendAnal(activity, tracker, "/cache/detail/stored");
+ } else {
+ base.sendAnal(activity, tracker, "/cache/detail/online");
+ }
+
+ try {
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", R.drawable.type_ape);
+ gcIcons.put("cito", R.drawable.type_cito);
+ gcIcons.put("earth", R.drawable.type_earth);
+ gcIcons.put("event", R.drawable.type_event);
+ gcIcons.put("letterbox", R.drawable.type_letterbox);
+ gcIcons.put("locationless", R.drawable.type_locationless);
+ gcIcons.put("mega", R.drawable.type_mega);
+ gcIcons.put("multi", R.drawable.type_multi);
+ gcIcons.put("traditional", R.drawable.type_traditional);
+ gcIcons.put("virtual", R.drawable.type_virtual);
+ gcIcons.put("webcam", R.drawable.type_webcam);
+ gcIcons.put("wherigo", R.drawable.type_wherigo);
+ gcIcons.put("gchq", R.drawable.type_hq);
+ gcIcons.put("mystery", R.drawable.type_mystery);
+ }
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, cache.name);
+ } else {
+ base.setTitle(activity, geocode.toUpperCase());
+ }
+
+ inflater = activity.getLayoutInflater();
+ geocode = cache.geocode.toUpperCase();
+
+ ScrollView scroll = (ScrollView) findViewById(R.id.details_list_box);
+ scroll.setVisibility(View.VISIBLE);
+
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+ detailsList.removeAllViews();
+
+ // actionbar icon
+ if (cache.type != null && gcIcons.containsKey(cache.type) == true) { // cache icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get(cache.type)), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get("mystery")), null, null, null);
+ }
+
+ // cache name (full name)
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_name));
+ itemValue.setText(Html.fromHtml(cache.name).toString());
+ detailsList.addView(itemLayout);
+
+ // cache type
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_type));
+
+ String size = null;
+ if (cache.size != null && cache.size.length() > 0) {
+ size = " (" + cache.size + ")";
+ } else {
+ size = "";
+ }
+
+ if (cgBase.cacheTypesInv.containsKey(cache.type) == true) { // cache icon
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type) + size);
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery") + size);
+ }
+ detailsList.addView(itemLayout);
+
+ // gc-code
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_geocode));
+ itemValue.setText(cache.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // cache state
+ if (cache.logOffline == true || cache.archived == true || cache.disabled == true || cache.members == true || cache.found == true) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_status));
+
+ StringBuilder state = new StringBuilder();
+ if (cache.logOffline == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_offline_log));
+ }
+ if (cache.found == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_found));
+ }
+ if (cache.archived == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_archived));
+ }
+ if (cache.disabled == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_disabled));
+ }
+ if (cache.members == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_premium));
+ }
+
+ itemValue.setText(state.toString());
+ detailsList.addView(itemLayout);
+
+ state = null;
+ }
+
+ // distance
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_distance));
+ if (cache.distance != null) {
+ itemValue.setText("~" + base.getHumanDistance(cache.distance));
+ } else {
+ itemValue.setText("--");
+ }
+ detailsList.addView(itemLayout);
+ cacheDistance = itemValue;
+
+ // difficulty
+ if (cache.difficulty != null && cache.difficulty > 0) {
+ addStarRating(detailsList, res.getString(R.string.cache_difficulty), cache.difficulty);
+ }
+
+ // terrain
+ if (cache.terrain != null && cache.terrain > 0) {
+ addStarRating(detailsList, res.getString(R.string.cache_terrain), cache.terrain);
+ }
+
+ // rating
+ if (cache.rating != null && cache.rating > 0) {
+ itemLayout = addStarRating(detailsList, res.getString(R.string.cache_rating), cache.rating);
+ if (cache.votes != null) {
+ final TextView itemAddition = (TextView)itemLayout.findViewById(R.id.addition);
+ itemAddition.setText("(" + cache.votes + ")");
+ itemAddition.setVisibility(View.VISIBLE);
+ }
+ }
+
+ // favourite count
+ if (cache.favouriteCnt != null) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_favourite));
+ itemValue.setText(String.format("%d", cache.favouriteCnt) + "×");
+ detailsList.addView(itemLayout);
+ }
+
+ // cache author
+ if ((cache.owner != null && cache.owner.length() > 0) || (cache.ownerReal != null && cache.ownerReal.length() > 0)) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_owner));
+ if (cache.owner != null && cache.owner.length() > 0) {
+ itemValue.setText(Html.fromHtml(cache.owner), TextView.BufferType.SPANNABLE);
+ } else if (cache.ownerReal != null && cache.ownerReal.length() > 0) {
+ itemValue.setText(Html.fromHtml(cache.ownerReal), TextView.BufferType.SPANNABLE);
+ }
+ itemValue.setOnClickListener(new userActions());
+ detailsList.addView(itemLayout);
+ }
+
+ // cache hidden
+ if (cache.hidden != null && cache.hidden.getTime() > 0) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ if (cache.type != null && (cache.type.equalsIgnoreCase("event") == true || cache.type.equalsIgnoreCase("mega") == true || cache.type.equalsIgnoreCase("cito") == true)) {
+ itemName.setText(res.getString(R.string.cache_event));
+ } else {
+ itemName.setText(res.getString(R.string.cache_hidden));
+ }
+ itemValue.setText(cgBase.dateOut.format(cache.hidden));
+ detailsList.addView(itemLayout);
+ }
+
+ // cache location
+ if (cache.location != null && cache.location.length() > 0) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_location));
+ itemValue.setText(cache.location);
+ detailsList.addView(itemLayout);
+ }
+
+ // cache coordinates
+ if (cache.latitude != null && cache.longitude != null) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_coordinates));
+ itemValue.setText(cache.latitudeString + " | " + cache.longitudeString);
+ detailsList.addView(itemLayout);
+ }
+
+ // cache attributes
+ if (cache.attributes != null && cache.attributes.size() > 0) {
+ final LinearLayout attribBox = (LinearLayout) findViewById(R.id.attributes_box);
+ final TextView attribView = (TextView) findViewById(R.id.attributes);
+
+ StringBuilder buffer = new StringBuilder();
+ String attribute;
+ for (int i = 0; i < cache.attributes.size(); i++) {
+ attribute = cache.attributes.get(i);
+
+ // dynamically search for a translation of the attribute
+ int id = res.getIdentifier("attribute_" + attribute, "string", base.context.getPackageName());
+ if (id > 0) {
+ String translated = res.getString(id);
+ if (translated != null && translated.length() > 0) {
+ attribute = translated;
+ }
+ }
+ if (buffer.length() > 0) {
+ buffer.append('\n');
+ }
+ buffer.append(attribute);
+ }
+
+ attribView.setText(buffer);
+ attribBox.setVisibility(View.VISIBLE);
+ }
+
+ // cache inventory
+ if (cache.inventory != null && cache.inventory.size() > 0) {
+ final LinearLayout inventBox = (LinearLayout) findViewById(R.id.inventory_box);
+ final TextView inventView = (TextView) findViewById(R.id.inventory);
+
+ StringBuilder inventoryString = new StringBuilder();
+ for (cgTrackable inventoryItem : cache.inventory) {
+ if (inventoryString.length() > 0) {
+ inventoryString.append("\n");
+ }
+ // avoid HTML parsing where possible
+ if (inventoryItem.name.indexOf('<') >= 0 || inventoryItem.name.indexOf('&') >= 0 ) {
+ inventoryString.append(Html.fromHtml(inventoryItem.name).toString());
+ }
+ else {
+ inventoryString.append(inventoryItem.name);
+ }
+ }
+ inventView.setText(inventoryString);
+ inventBox.setClickable(true);
+ inventBox.setOnClickListener(new selectTrackable());
+ inventBox.setVisibility(View.VISIBLE);
+ }
+
+ // offline use
+ final TextView offlineText = (TextView) findViewById(R.id.offline_text);
+ final Button offlineRefresh = (Button) findViewById(R.id.offline_refresh);
+ final Button offlineStore = (Button) findViewById(R.id.offline_store);
+
+ if (cache.reason >= 1) {
+ Long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.detailedUpdate / (60 * 1000)); // minutes
+
+ String ago = "";
+ if (diff < 15) {
+ ago = res.getString(R.string.cache_offline_time_mins_few);
+ } else if (diff < 50) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + diff + " " + res.getString(R.string.cache_offline_time_mins);
+ } else if (diff < 90) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + res.getString(R.string.cache_offline_time_hour);
+ } else if (diff < (48 * 60)) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / 60) + " " + res.getString(R.string.cache_offline_time_hours);
+ } else {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / (24 * 60)) + " " + res.getString(R.string.cache_offline_time_days);
+ }
+
+ offlineText.setText(res.getString(R.string.cache_offline_stored) + "\n" + ago);
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setClickable(true);
+ offlineRefresh.setOnClickListener(new storeCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_drop));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new dropCache());
+ } else {
+ offlineText.setText(res.getString(R.string.cache_offline_not_ready));
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setClickable(true);
+ offlineRefresh.setOnClickListener(new refreshCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_store));
+ offlineStore.setClickable(true);
+ offlineStore.setOnClickListener(new storeCache());
+ }
+
+ // cache short desc
+ if (cache.shortdesc != null && cache.shortdesc.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ TextView descView = (TextView) findViewById(R.id.shortdesc);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(cache.shortdesc.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // cache long desc
+ if (longDescDisplayed == true) {
+ if (longDesc == null && cache != null && cache.description != null) {
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ }
+
+ if (longDesc != null && longDesc.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ TextView descView = (TextView) findViewById(R.id.description);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(longDesc, TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.GONE);
+ showDesc.setOnTouchListener(null);
+ showDesc.setOnClickListener(null);
+ }
+ } else if (longDescDisplayed == false && cache.description != null && cache.description.length() > 0) {
+ ((LinearLayout) findViewById(R.id.desc_box)).setVisibility(View.VISIBLE);
+
+ Button showDesc = (Button) findViewById(R.id.show_description);
+ showDesc.setVisibility(View.VISIBLE);
+ showDesc.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ loadLongDesc();
+ }
+ });
+ }
+
+ // waypoints
+ LinearLayout waypoints = (LinearLayout) findViewById(R.id.waypoints);
+ waypoints.removeAllViews();
+
+ if (cache.waypoints != null && cache.waypoints.size() > 0) {
+ LinearLayout waypointView;
+
+ // sort waypoints: PP, Sx, FI, OWN
+ ArrayList<cgWaypoint> sortedWaypoints = new ArrayList<cgWaypoint>(cache.waypoints);
+ Collections.sort(sortedWaypoints, new Comparator<cgWaypoint>() {
+
+ @Override
+ public int compare(cgWaypoint wayPoint1, cgWaypoint wayPoint2) {
+
+ return order(wayPoint1) - order(wayPoint2);
+ }
+
+ private int order(cgWaypoint waypoint) {
+ if (waypoint.prefix == null || waypoint.prefix.length() == 0) {
+ return 0;
+ }
+ // check only the first character. sometimes there are inconsistencies like FI or FN for the FINAL
+ char firstLetter = Character.toUpperCase(waypoint.prefix.charAt(0));
+ switch (firstLetter) {
+ case 'P' : return -100; // parking
+ case 'S' : { // stage N
+ try {
+ Integer stageNumber = Integer.valueOf(waypoint.prefix.substring(1));
+ return stageNumber;
+ } catch (NumberFormatException e) {
+ // nothing
+ }
+ return 0;
+ }
+ case 'F' : return 1000; // final
+ case 'O' : return 10000; // own
+ }
+ return 0;
+ }});
+
+ for (cgWaypoint wpt : sortedWaypoints) {
+ waypointView = (LinearLayout) inflater.inflate(R.layout.waypoint_item, null);
+ final TextView identification = (TextView) waypointView.findViewById(R.id.identification);
+
+ ((TextView) waypointView.findViewById(R.id.type)).setText(cgBase.waypointTypes.get(wpt.type));
+ if (wpt.prefix.equalsIgnoreCase("OWN") == false) {
+ identification.setText(wpt.prefix.trim() + "/" + wpt.lookup.trim());
+ } else {
+ identification.setText(res.getString(R.string.waypoint_custom));
+ }
+
+ if (wpt.name.trim().length() == 0) {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(base.formatCoordinate(wpt.latitude, "lat", true) + " | " + base.formatCoordinate(wpt.longitude, "lon", true));
+ } else {
+ // avoid HTML parsing
+ if (wpt.name.indexOf('<') >= 0 || wpt.name.indexOf('&') >= 0) {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(Html.fromHtml(wpt.name.trim()), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) waypointView.findViewById(R.id.name)).setText(wpt.name.trim());
+ }
+ }
+ // avoid HTML parsing
+ if (wpt.note.indexOf('<') >= 0 || wpt.note.indexOf('&') >= 0) {
+ ((TextView) waypointView.findViewById(R.id.note)).setText(Html.fromHtml(wpt.note.trim()), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) waypointView.findViewById(R.id.note)).setText(wpt.note.trim());
+ }
+
+ waypointView.setOnClickListener(new waypointInfo(wpt.id));
+
+ waypoints.addView(waypointView);
+ }
+ }
+
+ Button addWaypoint = (Button) findViewById(R.id.add_waypoint);
+ addWaypoint.setClickable(true);
+ addWaypoint.setOnClickListener(new addWaypoint());
+
+ // cache hint
+ if (cache.hint != null && cache.hint.length() > 0) {
+ ((LinearLayout) findViewById(R.id.hint_box)).setVisibility(View.VISIBLE);
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setText(cgBase.rot13(cache.hint.trim()));
+ hintView.setClickable(true);
+ hintView.setOnClickListener(new codeHint());
+ } else {
+ ((LinearLayout) findViewById(R.id.hint_box)).setVisibility(View.GONE);
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setClickable(false);
+ hintView.setOnClickListener(null);
+ }
+
+ if (geo != null && geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ cacheDistance.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ cacheDistance.bringToFront();
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.setView: " + e.toString());
+ }
+
+ if (waitDialog != null && waitDialog.isShowing()) waitDialog.dismiss();
+ if (storeDialog != null && storeDialog.isShowing()) storeDialog.dismiss();
+ if (dropDialog != null && dropDialog.isShowing()) dropDialog.dismiss();
+ if (refreshDialog != null && refreshDialog.isShowing()) refreshDialog.dismiss();
+
+ displayLogs();
+
+ if (geo != null) geoUpdate.updateLoc(geo);
+ }
+
+ private RelativeLayout addStarRating(final LinearLayout detailsList, final String name, final float value) {
+ RelativeLayout itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
+ TextView itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ LinearLayout itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(name);
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", value) + ' ' + res.getString(R.string.cache_rating_of) + " 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((value - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((value - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star, (1 + i));
+ }
+ detailsList.addView(itemLayout);
+ return itemLayout;
+ }
+
+ private void displayLogs() {
+ // cache logs
+ TextView textView = (TextView) findViewById(R.id.logcount);
+ int logCounter = 0;
+ if (cache != null && cache.logCounts != null) {
+ final StringBuffer buff = new StringBuffer();
+ buff.append(res.getString(R.string.cache_log_types));
+ buff.append(": ");
+
+ // sort the log counts by type id ascending. that way the FOUND, DNF log types are the first and most visible ones
+ ArrayList<Entry<Integer, Integer>> sortedLogCounts = new ArrayList<Entry<Integer,Integer>>();
+ sortedLogCounts.addAll(cache.logCounts.entrySet());
+ Collections.sort(sortedLogCounts, new Comparator<Entry<Integer, Integer>>() {
+
+ @Override
+ public int compare(Entry<Integer, Integer> logCountItem1,
+ Entry<Integer, Integer> logCountItem2) {
+ return logCountItem1.getKey().compareTo(logCountItem2.getKey());
+ }});
+ for (Entry<Integer, Integer> pair : sortedLogCounts) {
+ int logTypeId = pair.getKey().intValue();
+ String logTypeLabel = cgBase.logTypes1.get(logTypeId);
+ // it may happen that the label is unknown -> then avoid any output for this type
+ if (logTypeLabel != null) {
+ if (logCounter > 0) {
+ buff.append(", ");
+ }
+ buff.append(pair.getValue().intValue());
+ buff.append("× ");
+ buff.append(logTypeLabel);
+ }
+ logCounter ++;
+ }
+ textView.setText(buff.toString());
+ }
+ // it may happen, that the logCounts map is available, but every log type has zero counts,
+ // therefore check again for the number of counted logs
+ if (logCounter > 0) {
+ textView.setVisibility(View.VISIBLE);
+ } else {
+ textView.setVisibility(View.GONE);
+ }
+
+ // cache logs
+ LinearLayout listView = (LinearLayout) findViewById(R.id.log_list);
+ listView.removeAllViews();
+
+ RelativeLayout rowView;
+
+ if (cache != null && cache.logs != null) {
+ for (cgLog log : cache.logs) {
+ rowView = (RelativeLayout) inflater.inflate(R.layout.log_item, null);
+
+ if (log.date > 0) {
+ final Date logDate = new Date(log.date);
+ ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.dateOutShort.format(logDate));
+ }
+
+ if (cgBase.logTypes1.containsKey(log.type) == true) {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(log.type));
+ } else {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(4)); // note if type is unknown
+ }
+ // avoid parsing HTML if not necessary
+ if (log.author.indexOf('<') >= 0 || log.author.indexOf('&') >= 0) {
+ ((TextView) rowView.findViewById(R.id.author)).setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) rowView.findViewById(R.id.author)).setText(log.author);
+ }
+
+ if (log.found == -1) {
+ ((TextView) rowView.findViewById(R.id.count)).setVisibility(View.GONE);
+ } else if (log.found == 0) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_no));
+ } else if (log.found == 1) {
+ ((TextView) rowView.findViewById(R.id.count)).setText(res.getString(R.string.cache_count_one));
+ } else {
+ ((TextView) rowView.findViewById(R.id.count)).setText(log.found + " " + res.getString(R.string.cache_count_more));
+ }
+ // avoid parsing HTML if not necessary
+ if (log.log.indexOf('<') >= 0 || log.log.indexOf('&') >= 0) {
+ ((TextView) rowView.findViewById(R.id.log)).setText(Html.fromHtml(log.log, new cgHtmlImg(activity, settings, null, false, cache.reason, false), null), TextView.BufferType.SPANNABLE);
+ }
+ else {
+ ((TextView) rowView.findViewById(R.id.log)).setText(log.log);
+ }
+
+ final ImageView markFound = (ImageView) rowView.findViewById(R.id.found_mark);
+ final ImageView markDNF = (ImageView) rowView.findViewById(R.id.dnf_mark);
+ final ImageView markDisabled = (ImageView) rowView.findViewById(R.id.disabled_mark);
+ if (log.type == 2 || log.type == 9 || log.type == 10) { // found, will attend, attended
+ markFound.setVisibility(View.VISIBLE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.GONE);
+ } else if (log.type == 3) { // did not find
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.VISIBLE);
+ markDisabled.setVisibility(View.GONE);
+ } else if (log.type == 7 || log.type == 8) { // disabled, archived
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.VISIBLE);
+ } else {
+ markFound.setVisibility(View.GONE);
+ markDNF.setVisibility(View.GONE);
+ markDisabled.setVisibility(View.GONE);
+ }
+
+ ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new userActions());
+ ((TextView) rowView.findViewById(R.id.log)).setOnClickListener(new decryptLog());
+
+ listView.addView(rowView);
+ }
+
+ if (cache.logs.size() > 0) {
+ ((LinearLayout) findViewById(R.id.log_box)).setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ private class loadCache extends Thread {
+
+ private Handler handler = null;
+ private String geocode = null;
+ private String guid = null;
+
+ public loadCache(Handler handlerIn, String geocodeIn, String guidIn) {
+ handler = handlerIn;
+ geocode = geocodeIn;
+ guid = guidIn;
+
+ if (geocode == null && guid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("geocode", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else {
+ return;
+ }
+
+ searchId = base.searchByGeocode(params, 0, false);
+
+ handler.sendMessage(new Message());
+ }
+ }
+
+ private class loadMapPreview extends Thread {
+ private cgCache cache = null;
+ private Handler handler = null;
+
+ public loadMapPreview(cgCache cacheIn, Handler handlerIn) {
+ cache = cacheIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ return;
+ }
+
+ BitmapDrawable image = null;
+
+ try {
+ final String latlonMap = String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude);
+ final Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+
+ int width = display.getWidth();
+ int height = (int) (90 * pixelRatio);
+
+ String markerUrl = cgBase.urlencode_rfc3986("http://cgeo.carnero.cc/_markers/my_location_mdpi.png");
+
+ cgHtmlImg mapGetter = new cgHtmlImg(activity, settings, cache.geocode, false, 0, false);
+ image = mapGetter.getDrawable("http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=15&size=" + width + "x" + height + "&maptype=terrain&markers=icon%3A" + markerUrl + "%7C" + latlonMap + "&sensor=false");
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeodetail.loadMapPreview.run: " + e.toString());
+ }
+ }
+ }
+
+ public void loadLongDesc() {
+ if (activity != null && (waitDialog == null || waitDialog.isShowing() == false)) {
+ descDialog = ProgressDialog.show(activity, null, res.getString(R.string.cache_dialog_loading_description), true);
+ descDialog.setCancelable(true);
+ }
+
+ threadLongDesc = new loadLongDesc(loadDescriptionHandler);
+ threadLongDesc.start();
+ }
+
+ private class loadLongDesc extends Thread {
+ private Handler handler = null;
+
+ public loadLongDesc(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (cache == null || cache.description == null || handler == null) {
+ return;
+ }
+
+ longDesc = Html.fromHtml(cache.description.trim(), new cgHtmlImg(activity, settings, geocode, true, cache.reason, false), null);
+ handler.sendMessage(new Message());
+ }
+ }
+
+ public ArrayList<cgCoord> getCoordinates() {
+ cgCoord coords = null;
+ ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+
+ try {
+ // cache
+ coords = new cgCoord();
+ coords.type = "cache";
+ if (name != null && name.length() > 0) {
+ coords.name = name;
+ } else {
+ coords.name = geocode.toUpperCase();
+ }
+ coords.latitude = cache.latitude;
+ coords.longitude = cache.longitude;
+ coordinates.add(coords);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.getCoordinates (cache): " + e.toString());
+ }
+
+ try {
+ // waypoints
+ for (cgWaypoint waypoint : cache.waypoints) {
+ if (waypoint.latitude == null || waypoint.longitude == null) {
+ continue;
+ }
+
+ coords = new cgCoord();
+ coords.type = "waypoint";
+ coords.name = waypoint.name;
+ coords.latitude = waypoint.latitude;
+ coords.longitude = waypoint.longitude;
+ coordinates.add(coords);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.getCoordinates (waypoint): " + e.toString());
+ }
+
+ return coordinates;
+ }
+
+ private void showOnMap() {
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", true);
+ mapIntent.putExtra("searchid", searchId);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void cachesAround() {
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", cache.latitude);
+ cachesIntent.putExtra("longitude", cache.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private void addToCalendar() {
+ String[] projection = new String[] { "_id", "displayName" };
+ Uri calendarProvider = null;
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) {
+ calendarProvider = Uri.parse("content://com.android.calendar/calendars");
+ } else {
+ calendarProvider = Uri.parse("content://calendar/calendars");
+ }
+
+ Cursor cursor = managedQuery(calendarProvider, projection, "selected=1", null, null);
+
+ calendars.clear();
+ int cnt = 0;
+ if (cursor != null) {
+ cnt = cursor.getCount();
+
+ if (cnt > 0) {
+ cursor.moveToFirst();
+
+ int calId = 0;
+ String calIdPre = null;
+ String calName = null;
+ int calIdIn = cursor.getColumnIndex("_id");
+ int calNameIn = cursor.getColumnIndex("displayName");
+
+ do {
+ calIdPre = cursor.getString(calIdIn);
+ if (calIdPre != null) {
+ calId = new Integer(calIdPre);
+ }
+ calName = cursor.getString(calNameIn);
+
+ if (calId > 0 && calName != null) {
+ calendars.put(calId, calName);
+ }
+ } while (cursor.moveToNext() == true);
+ }
+ }
+
+ final CharSequence[] items = calendars.values().toArray(new CharSequence[calendars.size()]);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(R.string.cache_calendars);
+ builder.setItems(items, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ addToCalendarFn(item);
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+ private void addToCalendarFn(int index) {
+ if (calendars == null || calendars.isEmpty() == true) {
+ return;
+ }
+
+ try {
+ Uri calendarProvider = null;
+ final int sdk = new Integer(Build.VERSION.SDK).intValue();
+ if (sdk >= 8) {
+ calendarProvider = Uri.parse("content://com.android.calendar/events");
+ } else {
+ calendarProvider = Uri.parse("content://calendar/events");
+ }
+
+ final Integer[] keys = calendars.keySet().toArray(new Integer[calendars.size()]);
+ final Integer calId = keys[index];
+
+ final Date eventDate = cache.hidden;
+ eventDate.setHours(0);
+ eventDate.setMinutes(0);
+ eventDate.setSeconds(0);
+
+ StringBuilder description = new StringBuilder();
+ description.append("http://coord.info/");
+ description.append(cache.geocode.toUpperCase());
+ description.append("\n\n");
+ if (cache.shortdesc != null && cache.shortdesc.length() > 0) {
+ description.append(Html.fromHtml(cache.shortdesc).toString());
+ }
+
+ ContentValues event = new ContentValues();
+ event.put("calendar_id", calId);
+ event.put("dtstart", eventDate.getTime() + 43200000); // noon
+ event.put("dtend", eventDate.getTime() + 43200000 + 3600000); // + one hour
+ event.put("eventTimezone", "UTC");
+ event.put("title", Html.fromHtml(cache.name).toString());
+ event.put("description", description.toString());
+ String location = "";
+ if (cache.latitudeString != null && cache.latitudeString.length() > 0 && cache.longitudeString != null && cache.longitudeString.length() > 0) {
+ location += cache.latitudeString + " " + cache.longitudeString;
+ }
+ if (cache.location != null && cache.location.length() > 0) {
+ boolean addParenteses = false;
+ if (location.length() > 0) {
+ addParenteses = true;
+ location += " (";
+ }
+
+ location += Html.fromHtml(cache.location).toString();
+ if (addParenteses) {
+ location += ")";
+ }
+ }
+ if (location.length() > 0) {
+ event.put("eventLocation", location);
+ }
+ event.put("allDay", 1);
+ event.put("hasAlarm", 0);
+
+ getContentResolver().insert(calendarProvider, event);
+
+ warning.showToast(res.getString(R.string.event_success));
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.event_fail));
+
+ Log.e(cgSettings.tag, "cgeodetail.addToCalendarFn: " + e.toString());
+ }
+ }
+
+ private void navigateTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = getCoordinates();
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeodetail.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeodetail.radarTo: " + e.toString());
+ }
+ }
+
+ public void shareCache() {
+ if (geocode == null && cache == null) {
+ return;
+ }
+
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
+
+ if (cache != null && cache.geocode != null) {
+ String subject = cache.geocode.toUpperCase();
+ if (cache.name != null && cache.name.length() > 0){
+ subject = subject + " - " + cache.name;
+ }
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Geocache " + subject);
+ intent.putExtra(Intent.EXTRA_TEXT, "http://coord.info/" + cache.geocode.toUpperCase());
+ } else if (geocode != null) {
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Geocache " + geocode.toUpperCase());
+ intent.putExtra(Intent.EXTRA_TEXT, "http://coord.info/" + geocode.toUpperCase());
+ }
+
+ startActivity(Intent.createChooser(intent, res.getText(R.string.action_bar_share_title)));
+ }
+
+ private class waypointInfo implements View.OnClickListener {
+ private int id = -1;
+
+ public waypointInfo(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent waypointIntent = new Intent(activity, cgeowaypoint.class);
+ waypointIntent.putExtra("waypoint", id);
+ waypointIntent.putExtra("geocode", cache.geocode);
+ activity.startActivity(waypointIntent);
+ }
+ }
+
+ private void logVisit() {
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+ logVisitIntent.putExtra("found", cache.found);
+ activity.startActivity(logVisitIntent);
+ }
+
+ private void showSpoilers() {
+ if (cache == null || cache.spoilers == null || cache.spoilers.isEmpty() == true) {
+ warning.showToast(res.getString(R.string.err_detail_no_spoiler));
+ }
+
+ Intent spoilersIntent = new Intent(activity, cgeospoilers.class);
+ spoilersIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(spoilersIntent);
+ }
+
+ private void showSmaps() {
+ if (cache == null || cache.reason == 0) {
+ warning.showToast(res.getString(R.string.err_detail_no_map_static));
+ }
+
+ Intent smapsIntent = new Intent(activity, cgeosmaps.class);
+ smapsIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(smapsIntent);
+ }
+
+ public class codeHint implements View.OnClickListener {
+ public void onClick(View arg0) {
+ // code hint
+ TextView hintView = ((TextView) findViewById(R.id.hint));
+ hintView.setText(cgBase.rot13(hintView.getText().toString()));
+
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ StringBuilder dist = new StringBuilder();
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ dist.append(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ }
+
+ if (cache.elevation != null) {
+ Double diff = null;
+ if (geo.altitudeNow != null) {
+ diff = (cache.elevation - geo.altitudeNow);
+ }
+
+ if (diff != null && diff >= 0) {
+ dist.append(" ↗");
+ if (settings.units == cgSettings.unitsImperial) {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff) * 3.2808399)));
+ dist.append(" ft");
+ } else {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff))));
+ dist.append(" m");
+ }
+ } else if (diff != null && diff < 0) {
+ dist.append(" ↘");
+ if (settings.units == cgSettings.unitsImperial) {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff) * 3.2808399)));
+ dist.append(" ft");
+ } else {
+ dist.append(String.format(Locale.getDefault(), "%.0f", (Math.abs(diff))));
+ dist.append(" m");
+ }
+ }
+ }
+
+ cacheDistance.setText(dist.toString());
+ cacheDistance.bringToFront();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class selectTrackable implements View.OnClickListener {
+ public void onClick(View arg0) {
+ // show list of trackables
+ try {
+ Intent trackablesIntent = new Intent(activity, cgeotrackables.class);
+ trackablesIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(trackablesIntent);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeodetail.selectTrackable: " + e.toString());
+ }
+ }
+ }
+
+ private class storeCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_removing));
+ return;
+ }
+ if (refreshDialog != null && refreshDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_refreshing));
+ return;
+ }
+
+ storeDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true);
+ storeDialog.setCancelable(true);
+
+ if (storeThread != null) {
+ storeThread.interrupt();
+ }
+
+ storeThread = new storeCacheThread(storeCacheHandler);
+ storeThread.start();
+ }
+ }
+
+ private class refreshCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_removing));
+ return;
+ }
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_saving));
+ return;
+ }
+
+ refreshDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_refresh_title), res.getString(R.string.cache_dialog_refresh_message), true);
+ refreshDialog.setCancelable(true);
+
+ if (refreshThread != null) {
+ refreshThread.interrupt();
+ }
+
+ refreshThread = new refreshCacheThread(refreshCacheHandler);
+ refreshThread.start();
+ }
+ }
+
+ private class storeCacheThread extends Thread {
+ private Handler handler = null;
+
+ public storeCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ int reason = 1;
+ if (cache.reason > 1) {
+ reason = cache.reason;
+ }
+ base.storeCache(app, activity, cache, null, reason, handler);
+ }
+ }
+
+ private class refreshCacheThread extends Thread {
+ private Handler handler = null;
+
+ public refreshCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ app.removeCacheFromCache(geocode);
+
+ final HashMap<String, String> params = new HashMap<String, String>();
+ params.put("geocode", cache.geocode);
+ searchId = base.searchByGeocode(params, 0, true);
+
+ handler.sendEmptyMessage(0);
+ }
+ }
+
+ private class dropCache implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_saving));
+ return;
+ }
+ if (refreshDialog != null && refreshDialog.isShowing() == true) {
+ warning.showToast(res.getString(R.string.err_detail_still_refreshing));
+ return;
+ }
+
+ dropDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true);
+ dropDialog.setCancelable(false);
+ Thread thread = new dropCacheThread(dropCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class dropCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public dropCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.dropCache(app, activity, cache, handler);
+ }
+ }
+
+ private class addWaypoint implements View.OnClickListener {
+
+ public void onClick(View view) {
+ Intent addWptIntent = new Intent(activity, cgeowaypointadd.class);
+
+ addWptIntent.putExtra("geocode", geocode);
+ int wpCount = 0;
+ if (cache.waypoints != null) {
+ wpCount = cache.waypoints.size();
+ }
+ addWptIntent.putExtra("count", wpCount);
+
+ activity.startActivity(addWptIntent);
+ }
+ }
+
+ private class decryptLog implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ final TextView logView = (TextView)view;
+ Spannable span = (Spannable) logView.getText();
+
+ // I needed to re-implement the base.rot13() encryption here because we must work on
+ // a SpannableStringBuilder instead of the pure text and we must replace each character inline.
+ // Otherwise we loose all the images, colors and so on...
+ SpannableStringBuilder buffer = new SpannableStringBuilder(span);
+ boolean plaintext = false;
+
+ int length = span.length();
+ for (int index = 0; index < length; index++) {
+ int c = span.charAt(index);
+ if (c == '[') {
+ plaintext = true;
+ } else if (c == ']') {
+ plaintext = false;
+ } else if (!plaintext) {
+ int capitalized = c & 32;
+ c &= ~capitalized;
+ c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c)
+ | capitalized;
+ }
+ buffer.replace(index, index + 1, String.valueOf((char) c));
+ }
+ logView.setText(buffer);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ private class userActions implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ registerForContextMenu(view);
+ openContextMenu(view);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goCompass(View view) {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.cache_coordinates_no));
+
+ return;
+ }
+
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = getCoordinates();
+ activity.startActivity(navigateIntent);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-cache-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeogpxes.java b/src/cgeo/geocaching/cgeogpxes.java
new file mode 100644
index 0000000..f64100d
--- /dev/null
+++ b/src/cgeo/geocaching/cgeogpxes.java
@@ -0,0 +1,292 @@
+package cgeo.geocaching;
+
+import android.app.Activity;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import java.io.File;
+import java.util.ArrayList;
+
+public class cgeogpxes extends ListActivity {
+
+ private ArrayList<File> files = new ArrayList<File>();
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private cgGPXListAdapter adapter = null;
+ private ProgressDialog waitDialog = null;
+ private ProgressDialog parseDialog = null;
+ private Resources res = null;
+ private loadFiles searchingThread = null;
+ private boolean endSearching = false;
+ private int listId = 1;
+ private int imported = 0;
+ final private Handler changeWaitDialogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.obj != null && waitDialog != null) {
+ waitDialog.setMessage(res.getString(R.string.gpx_import_searching_in) + " " + (String) msg.obj);
+ }
+ }
+ };
+ final private Handler changeParseDialogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.obj != null && parseDialog != null) {
+ parseDialog.setMessage(res.getString(R.string.gpx_import_loading_stored) + " " + (Integer) msg.obj);
+ }
+ }
+ };
+ final private Handler loadFilesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (files == null || files.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.gpx_import_no_files));
+
+ finish();
+ return;
+ } else {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeogpxes.loadFilesHandler: " + e.toString());
+ }
+ }
+ };
+ final private Handler loadCachesHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (parseDialog != null) {
+ parseDialog.dismiss();
+ }
+
+ warning.helpDialog(res.getString(R.string.gpx_import_title_caches_imported), imported + " " + res.getString(R.string.gpx_import_caches_imported));
+ imported = 0;
+ } catch (Exception e) {
+ if (parseDialog != null) {
+ parseDialog.dismiss();
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.gpx);
+ base.setTitle(activity, res.getString(R.string.gpx_import_title));
+
+ // google analytics
+ base.sendAnal(activity, "/gpx-import");
+
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ listId = extras.getInt("list");
+ }
+ if (listId <= 0) {
+ listId = 1;
+ }
+
+ setAdapter();
+
+ waitDialog = ProgressDialog.show(
+ this,
+ res.getString(R.string.gpx_import_title_searching),
+ res.getString(R.string.gpx_import_searching),
+ true,
+ true,
+ new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface arg0) {
+ if (searchingThread != null && searchingThread.isAlive()) {
+ searchingThread.notifyEnd();
+ }
+ if (files.isEmpty() == true) {
+ finish();
+ }
+ }
+ }
+ );
+
+ endSearching = false;
+ searchingThread = new loadFiles();
+ searchingThread.start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private void setAdapter() {
+ if (adapter == null) {
+ adapter = new cgGPXListAdapter(this, settings, files);
+ setListAdapter(adapter);
+ }
+ }
+
+ private class loadFiles extends Thread {
+ public void notifyEnd() {
+ endSearching = true;
+ }
+
+ @Override
+ public void run() {
+ ArrayList<File> list = new ArrayList<File>();
+
+ try {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) == true) {
+ final File gpx = new File(Environment.getExternalStorageDirectory().toString() + "/gpx");
+
+ if (gpx.exists() && gpx.isDirectory()) {
+ listDir(list, gpx);
+ } else {
+ listDir(list, Environment.getExternalStorageDirectory());
+ }
+ } else {
+ Log.w(cgSettings.tag, "No external media mounted.");
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeogpxes.loadFiles.run: " + e.toString());
+ }
+
+ final Message msg = new Message();
+ msg.obj = "loaded directories";
+ changeWaitDialogHandler.sendMessage(msg);
+
+ files.addAll(list);
+ list.clear();
+
+ loadFilesHandler.sendMessage(new Message());
+ }
+ }
+
+ private void listDir(ArrayList<File> list, File directory) {
+ if (directory == null || directory.isDirectory() == false || directory.canRead() == false) {
+ return;
+ }
+
+ final File[] listPre = directory.listFiles();
+
+ if (listPre != null && listPre.length > 0) {
+ final int listCnt = listPre.length;
+
+ for (int i = 0; i < listCnt; i++) {
+ if (endSearching == true) {
+ return;
+ }
+
+ if (listPre[i].canRead() == true && listPre[i].isFile() == true) {
+ final String[] nameParts = listPre[i].getName().split("\\.");
+ if (nameParts.length > 1) {
+ final String extension = nameParts[(nameParts.length - 1)].toLowerCase();
+
+ if (extension.equals("gpx") == false) {
+ continue;
+ }
+ } else {
+ continue; // file has no extension
+ }
+
+ list.add(listPre[i]); // add file to list
+ } else if (listPre[i].canRead() == true && listPre[i].isDirectory() == true) {
+ final Message msg = new Message();
+ String name = listPre[i].getName();
+ if (name.substring(0, 1).equals(".") == true) {
+ continue; // skip hidden directories
+ }
+ if (name.length() > 16) {
+ name = name.substring(0, 14) + "...";
+ }
+ msg.obj = name;
+ changeWaitDialogHandler.sendMessage(msg);
+
+ listDir(list, listPre[i]); // go deeper
+ }
+ }
+ }
+
+ return;
+ }
+
+ public void loadGPX(File file) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ parseDialog = ProgressDialog.show(
+ activity,
+ res.getString(R.string.gpx_import_title_reading_file),
+ res.getString(R.string.gpx_import_loading),
+ true,
+ false);
+
+ new loadCaches(file).start();
+ }
+
+ private class loadCaches extends Thread {
+
+ File file = null;
+
+ public loadCaches(File fileIn) {
+ file = fileIn;
+ }
+
+ @Override
+ public void run() {
+ final long searchId = base.parseGPX(app, file, listId, changeParseDialogHandler);
+
+ imported = app.getCount(searchId);
+
+ loadCachesHandler.sendMessage(new Message());
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeohelpers.java b/src/cgeo/geocaching/cgeohelpers.java
new file mode 100644
index 0000000..cb38b64
--- /dev/null
+++ b/src/cgeo/geocaching/cgeohelpers.java
@@ -0,0 +1,107 @@
+package cgeo.geocaching;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.content.Intent;
+import android.view.View;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.net.Uri;
+import java.util.Locale;
+
+public class cgeohelpers extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.helpers);
+ base.setTitle(activity, res.getString(R.string.helpers));
+
+ // google analytics
+ base.sendAnal(activity, "/helpers");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ public void installManual(View view) {
+ final Locale loc = Locale.getDefault();
+ final String lng = loc.getLanguage();
+
+ try {
+ if (lng.equalsIgnoreCase("de")) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:gnu.android.app.cgeomanual.de")));
+ } else {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:gnu.android.app.cgeomanual.en")));
+ }
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+
+ finish();
+ }
+
+ public void installLocus(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:menion.android.locus")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+
+ finish();
+ }
+
+ public void installGpsStatus(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+ finish();
+ }
+
+ public void installBluetoothGps(View view) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:googoo.android.btgps")));
+ } catch (Exception e) {
+ // market not available in standard emulator
+ }
+
+ finish();
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeoinit.java b/src/cgeo/geocaching/cgeoinit.java
new file mode 100644
index 0000000..0be2093
--- /dev/null
+++ b/src/cgeo/geocaching/cgeoinit.java
@@ -0,0 +1,965 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.view.View;
+import android.widget.EditText;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.util.Log;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+import java.io.File;
+
+import cgeo.geocaching.cgSettings.mapSourceEnum;
+
+public class cgeoinit extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private SharedPreferences prefs = null;
+ private ProgressDialog loginDialog = null;
+ private ProgressDialog webDialog = null;
+ private Handler logInHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (loginDialog != null && loginDialog.isShowing() == true) {
+ loginDialog.dismiss();
+ }
+
+ if (msg.what == 1) {
+ warning.helpDialog(res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_ok));
+ } else {
+ if (cgBase.errorRetrieve.containsKey(msg.what) == true) {
+ warning.helpDialog(res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_failed_reason) + " " + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.helpDialog(res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_failed));
+ }
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_login_failed));
+
+ Log.e(cgSettings.tag, "cgeoinit.logInHandler: " + e.toString());
+ }
+
+ if (loginDialog != null && loginDialog.isShowing() == true) {
+ loginDialog.dismiss();
+ }
+
+ init();
+ }
+ };
+
+ private Handler webAuthHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (webDialog != null && webDialog.isShowing() == true) {
+ webDialog.dismiss();
+ }
+
+ if (msg.what > 0) {
+ warning.helpDialog(res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_register_ok).replace("####", ""+msg.what));
+ } else {
+ warning.helpDialog(res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_register_fail));
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.init_sendToCgeo_register_fail));
+
+ Log.e(cgSettings.tag, "cgeoinit.webHandler: " + e.toString());
+ }
+
+ if (webDialog != null && webDialog.isShowing() == true) {
+ webDialog.dismiss();
+ }
+
+ init();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ settings = new cgSettings(this, prefs);
+ base = new cgBase(app, settings, prefs);
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.init);
+ base.setTitle(activity, res.getString(R.string.settings));
+
+ // google analytics
+ base.sendAnal(activity, "/init");
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onPause() {
+ saveValues();
+ super.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ saveValues();
+ super.onStop();
+ }
+
+ @Override
+ public void onDestroy() {
+ saveValues();
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 0, 0, res.getString(R.string.init_clear)).setIcon(android.R.drawable.ic_menu_delete);
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == 0) {
+ boolean status = false;
+
+ ((EditText) findViewById(R.id.username)).setText("");
+ ((EditText) findViewById(R.id.password)).setText("");
+ ((EditText) findViewById(R.id.passvote)).setText("");
+
+ status = saveValues();
+ if (status == true) {
+ warning.showToast(res.getString(R.string.init_cleared));
+ } else {
+ warning.showToast(res.getString(R.string.err_init_cleared));
+ }
+
+ finish();
+ }
+
+ return false;
+ }
+
+ public void init() {
+
+ // geocaching.com settings
+ String usernameNow = prefs.getString("username", null);
+ if (usernameNow != null) {
+ ((EditText) findViewById(R.id.username)).setText(usernameNow);
+ }
+ String passwordNow = prefs.getString("password", null);
+ if (usernameNow != null) {
+ ((EditText) findViewById(R.id.password)).setText(passwordNow);
+ }
+
+ Button logMeIn = (Button) findViewById(R.id.log_me_in);
+ logMeIn.setOnClickListener(new logIn());
+
+ TextView legalNote = (TextView) findViewById(R.id.legal_note);
+ legalNote.setClickable(true);
+ legalNote.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/about/termsofuse.aspx")));
+ }
+ });
+
+ // gcvote settings
+ String passvoteNow = prefs.getString("pass-vote", null);
+ if (passvoteNow != null) {
+ ((EditText) findViewById(R.id.passvote)).setText(passvoteNow);
+ }
+
+ // go4cache settings
+ TextView go4cache = (TextView) findViewById(R.id.about_go4cache);
+ go4cache.setClickable(true);
+ go4cache.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://go4cache.com/")));
+ }
+ });
+
+ CheckBox publicButton = (CheckBox) findViewById(R.id.publicloc);
+ if (prefs.getInt("publicloc", 0) == 0) {
+ publicButton.setChecked(false);
+ } else {
+ publicButton.setChecked(true);
+ }
+ publicButton.setOnClickListener(new cgeoChangePublic());
+
+ // Twitter settings
+ Button authorizeTwitter = (Button) findViewById(R.id.authorize_twitter);
+ authorizeTwitter.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ Intent authIntent = new Intent(activity, cgeoauth.class);
+ activity.startActivity(authIntent);
+ }
+ });
+
+ CheckBox twitterButton = (CheckBox) findViewById(R.id.twitter_option);
+ if (prefs.getInt("twitter", 0) == 0 || settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0) {
+ twitterButton.setChecked(false);
+ } else {
+ twitterButton.setChecked(true);
+ }
+ twitterButton.setOnClickListener(new cgeoChangeTwitter());
+
+ // Signature settings
+ EditText sigEdit = (EditText) findViewById(R.id.signature);
+ if (sigEdit.getText().length() == 0) {
+ sigEdit.setText(settings.getSignature());
+ }
+ Button sigBtn = (Button) findViewById(R.id.signature_help);
+ sigBtn.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ warning.helpDialog(res.getString(R.string.init_signature_help_title), res.getString(R.string.init_signature_help_text));
+ }
+ });
+
+ // Other settings
+ CheckBox skinButton = (CheckBox) findViewById(R.id.skin);
+ if (prefs.getInt("skin", 0) == 0) {
+ skinButton.setChecked(false);
+ } else {
+ skinButton.setChecked(true);
+ }
+ skinButton.setOnClickListener(new cgeoChangeSkin());
+
+ CheckBox addressButton = (CheckBox) findViewById(R.id.address);
+ if (prefs.getInt("showaddress", 1) == 0) {
+ addressButton.setChecked(false);
+ } else {
+ addressButton.setChecked(true);
+ }
+ addressButton.setOnClickListener(new cgeoChangeAddress());
+
+ CheckBox captchaButton = (CheckBox) findViewById(R.id.captcha);
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ captchaButton.setChecked(false);
+ } else {
+ captchaButton.setChecked(true);
+ }
+ captchaButton.setOnClickListener(new cgeoChangeCaptcha());
+
+ CheckBox useEnglishButton = (CheckBox) findViewById(R.id.useenglish);
+ if (prefs.getBoolean("useenglish", false) == false) {
+ useEnglishButton.setChecked(false);
+ } else {
+ useEnglishButton.setChecked(true);
+ }
+ useEnglishButton.setOnClickListener(new cgeoChangeUseEnglish());
+
+ CheckBox excludeButton = (CheckBox) findViewById(R.id.exclude);
+ if (prefs.getInt("excludemine", 0) == 0) {
+ excludeButton.setChecked(false);
+ } else {
+ excludeButton.setChecked(true);
+ }
+ excludeButton.setOnClickListener(new cgeoChangeExclude());
+
+ CheckBox disabledButton = (CheckBox) findViewById(R.id.disabled);
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ disabledButton.setChecked(false);
+ } else {
+ disabledButton.setChecked(true);
+ }
+ disabledButton.setOnClickListener(new cgeoChangeDisabled());
+
+ CheckBox offlineButton = (CheckBox) findViewById(R.id.offline);
+ if (prefs.getInt("offlinemaps", 1) == 0) {
+ offlineButton.setChecked(false);
+ } else {
+ offlineButton.setChecked(true);
+ }
+ offlineButton.setOnClickListener(new cgeoChangeOffline());
+
+ CheckBox autoloadButton = (CheckBox) findViewById(R.id.autoload);
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ autoloadButton.setChecked(false);
+ } else {
+ autoloadButton.setChecked(true);
+ }
+ autoloadButton.setOnClickListener(new cgeoChangeAutoload());
+
+ CheckBox livelistButton = (CheckBox) findViewById(R.id.livelist);
+ if (prefs.getInt("livelist", 1) == 0) {
+ livelistButton.setChecked(false);
+ } else {
+ livelistButton.setChecked(true);
+ }
+ livelistButton.setOnClickListener(new cgeoChangeLivelist());
+
+ CheckBox unitsButton = (CheckBox) findViewById(R.id.units);
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ unitsButton.setChecked(false);
+ } else {
+ unitsButton.setChecked(true);
+ }
+ unitsButton.setOnClickListener(new cgeoChangeUnits());
+
+ CheckBox gnavButton = (CheckBox) findViewById(R.id.gnav);
+ if (prefs.getInt("usegnav", 1) == 1) {
+ gnavButton.setChecked(true);
+ } else {
+ gnavButton.setChecked(false);
+ }
+ gnavButton.setOnClickListener(new cgeoChangeGNav());
+
+ CheckBox browserButton = (CheckBox) findViewById(R.id.browser);
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ browserButton.setChecked(false);
+ } else {
+ browserButton.setChecked(true);
+ }
+ browserButton.setOnClickListener(new cgeoChangeBrowser());
+
+ // Altitude settings
+ EditText altitudeEdit = (EditText) findViewById(R.id.altitude);
+ altitudeEdit.setText("" + prefs.getInt("altcorrection", 0));
+
+ //Send2cgeo settings
+ String webDeviceName = prefs.getString("webDeviceName", null);
+
+ if ((webDeviceName != null) &&(webDeviceName.length() > 0)) {
+ ((EditText) findViewById(R.id.webDeviceName)).setText(webDeviceName);
+ } else {
+ String s = android.os.Build.MODEL;
+ ((EditText) findViewById(R.id.webDeviceName)).setText(s);
+ }
+
+ Button webAuth = (Button) findViewById(R.id.sendToCgeo_register);
+ webAuth.setOnClickListener(new webAuth());
+
+ /*TextView webText = (TextView) findViewById(R.id.sendToCgeo);
+ webText.setClickable(true);
+ webText.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://send2cgeo.carnero.cc/")));
+ }
+ });*/
+
+ // Map source settings
+ Spinner mapSourceSelector = (Spinner) findViewById(R.id.mapsource);
+ ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
+ this, R.array.map_sources, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mapSourceSelector.setAdapter(adapter);
+ int mapsource = prefs.getInt("mapsource", 0);
+ mapSourceSelector.setSelection(mapsource);
+ mapSourceSelector.setOnItemSelectedListener(new cgeoChangeMapSource());
+
+ EditText mfmapFileEdit = (EditText) findViewById(R.id.mapfile);
+ mfmapFileEdit.setText(prefs.getString("mfmapfile", ""));
+
+ setMapFileEditState();
+
+ // Cache db backup
+ TextView lastBackup = (TextView) findViewById(R.id.backup_last);
+ File lastBackupFile = app.isRestoreFile();
+ if (lastBackupFile != null) {
+ lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.timeOut.format(lastBackupFile.lastModified()) + ", " + cgBase.dateOut.format(lastBackupFile.lastModified()));
+ } else {
+ lastBackup.setText(res.getString(R.string.init_backup_last_no));
+ }
+
+ }
+
+ public void backup(View view) {
+ final String file = app.backupDatabase();
+
+ if (file != null) {
+ warning.helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_success) + "\n" + file);
+ } else {
+ warning.helpDialog(res.getString(R.string.init_backup_backup), res.getString(R.string.init_backup_failed));
+ }
+
+ TextView lastBackup = (TextView) findViewById(R.id.backup_last);
+ File lastBackupFile = app.isRestoreFile();
+ if (lastBackupFile != null) {
+ lastBackup.setText(res.getString(R.string.init_backup_last) + " " + cgBase.timeOut.format(lastBackupFile.lastModified()) + ", " + cgBase.dateOut.format(lastBackupFile.lastModified()));
+ } else {
+ lastBackup.setText(res.getString(R.string.init_backup_last_no));
+ }
+ }
+
+ public void restore(View view) {
+ final boolean status = app.restoreDatabase();
+
+ if (status) {
+ warning.helpDialog(res.getString(R.string.init_backup_restore), res.getString(R.string.init_restore_success));
+ } else {
+ warning.helpDialog(res.getString(R.string.init_backup_restore), res.getString(R.string.init_restore_failed));
+ }
+ }
+
+ private void setMapFileEditState() {
+ EditText mapFileEdit = (EditText) findViewById(R.id.mapfile);
+ if (settings.mapProvider == mapSourceEnum.mapsforgeOffline) {
+ mapFileEdit.setVisibility(View.VISIBLE);
+ } else {
+ mapFileEdit.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ public boolean saveValues() {
+ String usernameNew = ((EditText) findViewById(R.id.username)).getText().toString();
+ String passwordNew = ((EditText) findViewById(R.id.password)).getText().toString();
+ String passvoteNew = ((EditText) findViewById(R.id.passvote)).getText().toString();
+ String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString();
+ String altitudeNew = ((EditText) findViewById(R.id.altitude)).getText().toString();
+ String mfmapFileNew = ((EditText) findViewById(R.id.mapfile)).getText().toString();
+
+ if (usernameNew == null) {
+ usernameNew = "";
+ }
+ if (passwordNew == null) {
+ passwordNew = "";
+ }
+ if (passvoteNew == null) {
+ passvoteNew = "";
+ }
+ if (signatureNew == null) {
+ signatureNew = "";
+ }
+
+ int altitudeNewInt = 0;
+ if (altitudeNew == null) {
+ altitudeNewInt = 0;
+ } else {
+ altitudeNewInt = new Integer(altitudeNew);
+ }
+
+ if (mfmapFileNew == null) {
+ mfmapFileNew = "";
+ }
+
+ final boolean status1 = settings.setLogin(usernameNew, passwordNew);
+ final boolean status2 = settings.setGCvoteLogin(passvoteNew);
+ final boolean status3 = settings.setSignature(signatureNew);
+ final boolean status4 = settings.setAltCorrection(altitudeNewInt);
+ final boolean status5 = settings.setMapFile(mfmapFileNew);
+
+ if (status1 && status2 && status3 && status4 && status5) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private class cgeoChangeTwitter implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ CheckBox twitterButton = (CheckBox) findViewById(R.id.twitter_option);
+
+ if (twitterButton.isChecked() == true) {
+ settings.reloadTwitterTokens();
+
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("twitter", 0) == 0) {
+ edit.putInt("twitter", 1);
+ settings.twitter = 1;
+ } else {
+ edit.putInt("twitter", 0);
+ settings.twitter = 0;
+ }
+ edit.commit();
+
+ if (settings.twitter == 1 && (settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0)) {
+ Intent authIntent = new Intent(activity, cgeoauth.class);
+ activity.startActivity(authIntent);
+ }
+
+ if (prefs.getInt("twitter", 0) == 0) {
+ twitterButton.setChecked(false);
+ } else {
+ twitterButton.setChecked(true);
+ }
+ } else {
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("twitter", 0);
+ settings.twitter = 0;
+ edit.commit();
+
+ twitterButton.setChecked(false);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeSkin implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("skin", 0) == 0) {
+ edit.putInt("skin", 1);
+ settings.setSkin(1);
+ } else {
+ edit.putInt("skin", 0);
+ settings.setSkin(0);
+ }
+ edit.commit();
+
+ CheckBox skinButton = (CheckBox) findViewById(R.id.skin);
+ if (prefs.getInt("skin", 0) == 0) {
+ skinButton.setChecked(false);
+ } else {
+ skinButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeAddress implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("showaddress", 1) == 0) {
+ edit.putInt("showaddress", 1);
+ } else {
+ edit.putInt("showaddress", 0);
+ }
+ edit.commit();
+
+ CheckBox transparentButton = (CheckBox) findViewById(R.id.address);
+ if (prefs.getInt("showaddress", 1) == 0) {
+ transparentButton.setChecked(false);
+ } else {
+ transparentButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangePublic implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("publicloc", 0) == 0) {
+ edit.putInt("publicloc", 1);
+ settings.publicLoc = 1;
+ } else {
+ edit.putInt("publicloc", 0);
+ settings.publicLoc = 0;
+ }
+ edit.commit();
+
+ CheckBox publicloc = (CheckBox) findViewById(R.id.publicloc);
+ if (prefs.getInt("publicloc", 0) == 0) {
+ publicloc.setChecked(false);
+ } else {
+ publicloc.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeCaptcha implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ edit.putBoolean("showcaptcha", true);
+ settings.showCaptcha = true;
+ } else {
+ edit.putBoolean("showcaptcha", false);
+ settings.showCaptcha = false;
+ }
+ edit.commit();
+
+ CheckBox captchaButton = (CheckBox) findViewById(R.id.captcha);
+ if (prefs.getBoolean("showcaptcha", false) == false) {
+ captchaButton.setChecked(false);
+ } else {
+ captchaButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeUseEnglish implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getBoolean("useenglish", false) == false) {
+ edit.putBoolean("useenglish", true);
+ settings.useEnglish = true;
+ settings.setLanguage(true);
+ } else {
+ edit.putBoolean("useenglish", false);
+ settings.useEnglish = false;
+ settings.setLanguage(false);
+ }
+ edit.commit();
+
+ CheckBox useEnglishButton = (CheckBox) findViewById(R.id.useenglish);
+ if (prefs.getBoolean("useenglish", false) == false) {
+ useEnglishButton.setChecked(false);
+ } else {
+ useEnglishButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeExclude implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("excludemine", 0) == 0) {
+ edit.putInt("excludemine", 1);
+ settings.excludeMine = 1;
+ } else {
+ edit.putInt("excludemine", 0);
+ settings.excludeMine = 0;
+ }
+ edit.commit();
+
+ CheckBox excludeButton = (CheckBox) findViewById(R.id.exclude);
+ if (prefs.getInt("excludemine", 0) == 0) {
+ excludeButton.setChecked(false);
+ } else {
+ excludeButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeDisabled implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ edit.putInt("excludedisabled", 1);
+ settings.excludeDisabled = 1;
+ } else {
+ edit.putInt("excludedisabled", 0);
+ settings.excludeDisabled = 0;
+ }
+ edit.commit();
+
+ CheckBox disabledButton = (CheckBox) findViewById(R.id.disabled);
+ if (prefs.getInt("excludedisabled", 0) == 0) {
+ disabledButton.setChecked(false);
+ } else {
+ disabledButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeOffline implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("offlinemaps", 1) == 0) {
+ edit.putInt("offlinemaps", 1);
+ settings.excludeDisabled = 1;
+ } else {
+ edit.putInt("offlinemaps", 0);
+ settings.excludeDisabled = 0;
+ }
+ edit.commit();
+
+ CheckBox offlineButton = (CheckBox) findViewById(R.id.offline);
+ if (prefs.getInt("offlinemaps", 0) == 0) {
+ offlineButton.setChecked(false);
+ } else {
+ offlineButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeLivelist implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("livelist", 1) == 0) {
+ edit.putInt("livelist", 1);
+ settings.livelist = 1;
+ } else {
+ edit.putInt("livelist", 0);
+ settings.livelist = 0;
+ }
+ edit.commit();
+
+ CheckBox livelistButton = (CheckBox) findViewById(R.id.livelist);
+ if (prefs.getInt("livelist", 1) == 0) {
+ livelistButton.setChecked(false);
+ } else {
+ livelistButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeAutoload implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ edit.putInt("autoloaddesc", 1);
+ settings.autoLoadDesc = 1;
+ } else {
+ edit.putInt("autoloaddesc", 0);
+ settings.autoLoadDesc = 0;
+ }
+ edit.commit();
+
+ CheckBox autoloadButton = (CheckBox) findViewById(R.id.autoload);
+ if (prefs.getInt("autoloaddesc", 0) == 0) {
+ autoloadButton.setChecked(false);
+ } else {
+ autoloadButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeUnits implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ edit.putInt("units", cgSettings.unitsImperial);
+ settings.units = cgSettings.unitsImperial;
+ } else {
+ edit.putInt("units", cgSettings.unitsMetric);
+ settings.units = cgSettings.unitsMetric;
+ }
+ edit.commit();
+
+ CheckBox unitsButton = (CheckBox) findViewById(R.id.units);
+ if (prefs.getInt("units", cgSettings.unitsMetric) == cgSettings.unitsMetric) {
+ unitsButton.setChecked(false);
+ } else {
+ unitsButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeGNav implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("usegnav", 1) == 1) {
+ edit.putInt("usegnav", 0);
+ settings.useGNavigation = 0;
+ } else {
+ edit.putInt("usegnav", 1);
+ settings.useGNavigation = 1;
+ }
+ edit.commit();
+
+ CheckBox gnavButton = (CheckBox) findViewById(R.id.gnav);
+ if (prefs.getInt("usegnav", 1) == 1) {
+ gnavButton.setChecked(true);
+ } else {
+ gnavButton.setChecked(false);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeBrowser implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ SharedPreferences.Editor edit = prefs.edit();
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ edit.putInt("asbrowser", 1);
+ settings.asBrowser = 1;
+ } else {
+ edit.putInt("asbrowser", 0);
+ settings.asBrowser = 0;
+ }
+ edit.commit();
+
+ CheckBox browserButton = (CheckBox) findViewById(R.id.browser);
+ if (prefs.getInt("asbrowser", 1) == 0) {
+ browserButton.setChecked(false);
+ } else {
+ browserButton.setChecked(true);
+ }
+
+ return;
+ }
+ }
+
+ private class cgeoChangeMapSource implements OnItemSelectedListener {
+
+ @Override
+ public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
+ long arg3) {
+ settings.mapProvider = mapSourceEnum.fromInt(arg2);
+ SharedPreferences.Editor edit = prefs.edit();
+ edit.putInt("mapsource", arg2);
+ edit.commit();
+ setMapFileEditState();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> arg0) {
+ arg0.setSelection(settings.mapProvider.ordinal());
+ setMapFileEditState();
+ }
+ }
+
+ private class logIn implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final String username = ((EditText) findViewById(R.id.username)).getText().toString();
+ final String password = ((EditText) findViewById(R.id.password)).getText().toString();
+
+ if (username == null || username.length() == 0 || password == null || password.length() == 0) {
+ warning.showToast(res.getString(R.string.err_missing_auth));
+ return;
+ }
+
+ loginDialog = ProgressDialog.show(activity, res.getString(R.string.init_login_popup), res.getString(R.string.init_login_popup_working), true);
+ loginDialog.setCancelable(false);
+
+ settings.setLogin(username, password);
+ settings.deleteCookies();
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ logInHandler.sendEmptyMessage(base.login());
+ }
+ }).start();
+ }
+ }
+
+ private class webAuth implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ final String deviceName = ((EditText) findViewById(R.id.webDeviceName)).getText().toString();
+ final String deviceCode = prefs.getString("webDeviceCode", null);
+
+
+ if (deviceName == null || deviceName.length() == 0) {
+ warning.showToast(res.getString(R.string.err_missing_device_name));
+ return;
+ }
+
+ webDialog = ProgressDialog.show(activity, res.getString(R.string.init_sendToCgeo), res.getString(R.string.init_sendToCgeo_registering), true);
+ webDialog.setCancelable(false);
+
+ (new Thread() {
+
+ @Override
+ public void run() {
+ int pin = 0;
+
+ String nam = deviceName==null?"":deviceName;
+ String cod = deviceCode==null?"":deviceCode;
+
+ String params = "name="+cgBase.urlencode_rfc3986(nam)+"&code="+cgBase.urlencode_rfc3986(cod);
+
+ cgResponse response = base.request(false, "send2cgeo.carnero.cc", "/authDev.php", "GET", params, 0, true);
+
+ if (response.getStatusCode() == 200)
+ {
+ //response was OK
+ String[] strings = response.getData().split(",");
+ try {
+ pin=Integer.parseInt(strings[1].trim());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "webDialog: " + e.toString());
+ }
+ String code = strings[0];
+ settings.setWebNameCode(nam, code);
+ }
+
+ webAuthHandler.sendEmptyMessage(pin);
+ }
+ }).start();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-configuration",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeonavigate.java b/src/cgeo/geocaching/cgeonavigate.java
new file mode 100644
index 0000000..65afa17
--- /dev/null
+++ b/src/cgeo/geocaching/cgeonavigate.java
@@ -0,0 +1,503 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.util.Log;
+import android.app.Activity;
+import android.view.Menu;
+import android.view.SubMenu;
+import android.view.MenuItem;
+import android.widget.TextView;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.WindowManager;
+import java.util.HashMap;
+import java.util.Locale;
+
+
+public class cgeonavigate extends Activity {
+
+ public static ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private PowerManager pm = null;
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private cgUpdateDir dirUpdate = new updateDir();
+ private Double dstLatitude = null;
+ private Double dstLongitude = null;
+ private Double cacheHeading = new Double(0);
+ private Double northHeading = new Double(0);
+ private String title = null;
+ private String name = null;
+ private TextView navType = null;
+ private TextView navAccuracy = null;
+ private TextView navSatellites = null;
+ private TextView navLocation = null;
+ private TextView distanceView = null;
+ private TextView headingView = null;
+ private cgCompass compassView = null;
+ private updaterThread updater = null;
+ private Handler updaterHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (compassView != null) {
+ compassView.updateNorth(northHeading, cacheHeading);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeonavigate.updaterHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // class init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.navigate);
+ base.setTitle(activity, res.getString(R.string.compass_title));
+
+ // google analytics
+ base.sendAnal(activity, "/navigate");
+
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ title = extras.getString("geocode");
+ name = extras.getString("name");
+ dstLatitude = extras.getDouble("latitude");
+ dstLongitude = extras.getDouble("longitude");
+
+ if (name != null && name.length() > 0) {
+ if (title != null && title.length() > 0) {
+ title = title + ": " + name;
+ } else {
+ title = name;
+ }
+ }
+ } else {
+ Intent pointIntent = new Intent(activity, cgeopoint.class);
+ activity.startActivity(pointIntent);
+
+ finish();
+ return;
+ }
+
+ if (title != null && title.length() > 0) {
+ app.setAction(title);
+ } else if (name != null && name.length() > 0) {
+ app.setAction(name);
+ }
+
+ // set header
+ setTitle();
+ setDestCoords();
+
+ // get textviews once
+ compassView = (cgCompass) findViewById(R.id.rose);
+
+ // start updater thread
+ updater = new updaterThread(updaterHandler);
+ updater.start();
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (title != null && title.length() > 0) {
+ app.setAction(title);
+ } else if (name != null && name.length() > 0) {
+ app.setAction(name);
+ }
+
+ // sensor & geolocation manager
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ // keep backlight on
+ if (pm == null) {
+ pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ }
+
+ // updater thread
+ if (updater == null) {
+ updater = new updaterThread(updaterHandler);
+ updater.start();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ compassView.destroyDrawingCache();
+ compassView = null;
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ if (settings.useCompass == 1) {
+ menu.add(0, 1, 0, res.getString(R.string.use_gps)).setIcon(android.R.drawable.ic_menu_compass);
+ } else {
+ menu.add(0, 1, 0, res.getString(R.string.use_compass)).setIcon(android.R.drawable.ic_menu_compass);
+ }
+ menu.add(0, 0, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ menu.add(0, 2, 0, res.getString(R.string.destination_set)).setIcon(android.R.drawable.ic_menu_edit);
+ if (coordinates != null && coordinates.size() > 1) {
+ SubMenu subMenu = menu.addSubMenu(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces);
+
+ int cnt = 4;
+ for (cgCoord coordinate : coordinates) {
+ subMenu.add(0, cnt, 0, coordinate.name + " (" + coordinate.type + ")");
+ cnt++;
+ }
+
+ return true;
+ } else {
+ menu.add(0, 3, 0, res.getString(R.string.destination_select)).setIcon(android.R.drawable.ic_menu_myplaces).setEnabled(false);
+
+ return true;
+ }
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ item = menu.findItem(1);
+ if (settings.useCompass == 1) {
+ item.setTitle(res.getString(R.string.use_gps));
+ } else {
+ item.setTitle(res.getString(R.string.use_compass));
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ if (id == 0) {
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("detail", false);
+ mapIntent.putExtra("latitude", dstLatitude);
+ mapIntent.putExtra("longitude", dstLongitude);
+
+ activity.startActivity(mapIntent);
+ } else if (id == 1) {
+ if (settings.useCompass == 1) {
+ settings.useCompass = 0;
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+
+ SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putInt("usecompass", settings.useCompass);
+ prefsEdit.commit();
+ } else {
+ settings.useCompass = 1;
+
+ if (dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ SharedPreferences.Editor prefsEdit = getSharedPreferences(cgSettings.preferences, 0).edit();
+ prefsEdit.putInt("usecompass", settings.useCompass);
+ prefsEdit.commit();
+ }
+ } else if (id == 2) {
+ Intent pointIntent = new Intent(activity, cgeopoint.class);
+ activity.startActivity(pointIntent);
+
+ finish();
+ return true;
+ } else if (id > 3 && coordinates != null && coordinates.get(id - 4) != null) {
+ cgCoord coordinate = coordinates.get(id - 4);
+
+ title = coordinate.name;
+ dstLatitude = coordinate.latitude;
+ dstLongitude = coordinate.longitude;
+ setTitle();
+ setDestCoords();
+ updateDistanceInfo();
+
+ Log.d(cgSettings.tag, "destination set: " + title + " (" + String.format(Locale.getDefault(), "%.8f", dstLatitude) + " | " + String.format(Locale.getDefault(), "%.8f", dstLatitude) + ")");
+ return true;
+ }
+
+ return false;
+ }
+
+ private void setTitle() {
+ if (title != null && title.length() > 0) {
+ base.setTitle(activity, title);
+ } else {
+ base.setTitle(activity, res.getString(R.string.navigation));
+ }
+ }
+
+ private void setDestCoords() {
+ if (dstLatitude == null || dstLatitude == null) {
+ return;
+ }
+
+ ((TextView) findViewById(R.id.destination)).setText(base.formatCoordinate(dstLatitude, "lat", true) + " | " + base.formatCoordinate(dstLongitude, "lon", true));
+ }
+
+ public void setDest(Double lat, Double lon) {
+ if (lat == null || lon == null) {
+ return;
+ }
+
+ title = "some place";
+ setTitle();
+ setDestCoords();
+
+ dstLatitude = lat;
+ dstLongitude = lon;
+ updateDistanceInfo();
+ }
+
+ public HashMap<String, Double> getCoordinatesNow() {
+ HashMap<String, Double> coordsNow = new HashMap<String, Double>();
+ if (geo != null) {
+ coordsNow.put("latitude", geo.latitudeNow);
+ coordsNow.put("longitude", geo.longitudeNow);
+ }
+ return coordsNow;
+ }
+
+ private void updateDistanceInfo() {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null || dstLatitude == null || dstLongitude == null) {
+ return;
+ }
+
+ if (distanceView == null) {
+ distanceView = (TextView) findViewById(R.id.distance);
+ }
+ if (headingView == null) {
+ headingView = (TextView) findViewById(R.id.heading);
+ }
+
+ cacheHeading = cgBase.getHeading(geo.latitudeNow, geo.longitudeNow, dstLatitude, dstLongitude);
+ distanceView.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, dstLatitude, dstLongitude)));
+ headingView.setText(String.format(Locale.getDefault(), "%.0f", cacheHeading) + "°");
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (navType == null || navLocation == null || navAccuracy == null) {
+ navType = (TextView) findViewById(R.id.nav_type);
+ navAccuracy = (TextView) findViewById(R.id.nav_accuracy);
+ navSatellites = (TextView) findViewById(R.id.nav_satellites);
+ navLocation = (TextView) findViewById(R.id.nav_location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ String satellites = null;
+ if (geo.satellitesVisible != null && geo.satellitesFixed != null && geo.satellitesFixed > 0) {
+ satellites = res.getString(R.string.loc_sat) + ": " + geo.satellitesFixed + "/" + geo.satellitesVisible;
+ } else if (geo.satellitesVisible != null) {
+ satellites = res.getString(R.string.loc_sat) + ": 0/" + geo.satellitesVisible;
+ } else {
+ satellites = "";
+ }
+ navSatellites.setText(satellites);
+
+ if (geo.gps == -1) {
+ navType.setText(res.getString(R.string.loc_last));
+ } else if (geo.gps == 0) {
+ navType.setText(res.getString(R.string.loc_net));
+ } else {
+ navType.setText(res.getString(R.string.loc_gps));
+ }
+
+ if (geo.accuracyNow != null) {
+ if (settings.units == cgSettings.unitsImperial) {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", (geo.accuracyNow * 3.2808399)) + " ft");
+ } else {
+ navAccuracy.setText("±" + String.format(Locale.getDefault(), "%.0f", geo.accuracyNow) + " m");
+ }
+ } else {
+ navAccuracy.setText(null);
+ }
+
+ if (geo.altitudeNow != null) {
+ String humanAlt;
+ if (settings.units == cgSettings.unitsImperial) {
+ humanAlt = String.format("%.0f", (geo.altitudeNow * 3.2808399)) + " ft";
+ } else {
+ humanAlt = String.format("%.0f", geo.altitudeNow) + " m";
+ }
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true) + " | " + humanAlt);
+ } else {
+ navLocation.setText(base.formatCoordinate(geo.latitudeNow, "lat", true) + " | " + base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+
+ updateDistanceInfo();
+ } else {
+ navType.setText(null);
+ navAccuracy.setText(null);
+ navLocation.setText(res.getString(R.string.loc_trying));
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo != null && geo.bearingNow != null) {
+ northHeading = geo.bearingNow;
+ } else {
+ northHeading = new Double(0);
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class updateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ if (geo == null || geo.speedNow == null || geo.speedNow <= 5) { // use compass when speed is lower than 18 km/h
+ northHeading = dir.directionNow;
+ }
+ }
+ }
+
+ private class updaterThread extends Thread {
+
+ private Handler handler = null;
+
+ public updaterThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ if (handler != null) {
+ handler.sendMessage(new Message());
+ }
+
+ try {
+ Thread.sleep(20);
+ } catch (Exception e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-compass",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeopoint.java b/src/cgeo/geocaching/cgeopoint.java
new file mode 100644
index 0000000..142bf53
--- /dev/null
+++ b/src/cgeo/geocaching/cgeopoint.java
@@ -0,0 +1,535 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeopoint extends Activity {
+
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private SharedPreferences prefs = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private GoogleAnalyticsTracker tracker = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private boolean changed = false;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ app = (cgeoapplication) this.getApplication();
+ res = this.getResources();
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ prefs = getSharedPreferences(cgSettings.preferences, 0);
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.point);
+ base.setTitle(activity, res.getString(R.string.search_destination));
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/point");
+
+ init();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private void init() {
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ EditText latitudeEdit = (EditText) findViewById(R.id.latitude);
+ latitudeEdit.setOnKeyListener(new View.OnKeyListener() {
+
+ public boolean onKey(View v, int i, KeyEvent k) {
+ changed = true;
+
+ return false;
+ }
+ });
+
+ EditText longitudeEdit = (EditText) findViewById(R.id.longitude);
+ longitudeEdit.setOnKeyListener(new View.OnKeyListener() {
+
+ public boolean onKey(View v, int i, KeyEvent k) {
+ changed = true;
+
+ return false;
+ }
+ });
+
+ if (prefs.contains("anylatitude") == true && prefs.contains("anylongitude") == true) {
+ latitudeEdit.setText(base.formatCoordinate(new Double(prefs.getFloat("anylatitude", 0f)), "lat", true));
+ longitudeEdit.setText(base.formatCoordinate(new Double(prefs.getFloat("anylongitude", 0f)), "lon", true));
+ }
+
+ Button buttonCurrent = (Button) findViewById(R.id.current);
+ buttonCurrent.setOnClickListener(new currentListener());
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 3, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 4, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords != null && coords.get(0) != null && coords.get(1) != null) {
+ menu.findItem(0).setVisible(true);
+ menu.findItem(2).setVisible(true);
+ menu.findItem(5).setVisible(true);
+ } else {
+ menu.findItem(0).setVisible(false);
+ menu.findItem(2).setVisible(false);
+ menu.findItem(5).setVisible(false);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ ArrayList<Double> coords = getDestination();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ radarTo();
+ return true;
+ } else if (menuItem == 4) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, coords.get(0), coords.get(1), geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, coords.get(0), coords.get(1));
+ }
+
+ return true;
+ } else if (menuItem == 5) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, coords.get(0), coords.get(1)); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, coords.get(0), coords.get(1)); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, coords.get(0), coords.get(1)); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void showOnMap() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+
+ mapIntent.putExtra("latitude", coords.get(0));
+ mapIntent.putExtra("longitude", coords.get(1));
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void navigateTo() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coords.get(0));
+ navigateIntent.putExtra("longitude", coords.get(1));
+ navigateIntent.putExtra("geocode", "");
+ navigateIntent.putExtra("name", "Some destination");
+
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(coords.get(0)));
+ radarIntent.putExtra("longitude", new Float(coords.get(1)));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ ArrayList<Double> coords = getDestination();
+
+ if (coords == null || coords.get(0) == null || coords.get(1) == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", coords.get(0));
+ cachesIntent.putExtra("longitude", coords.get(1));
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class currentListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_unknown_position));
+ return;
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+
+ changed = false;
+ }
+ }
+
+ private ArrayList<Double> getDestination() {
+ ArrayList<Double> coords = new ArrayList<Double>();
+ Double latitude = null;
+ Double longitude = null;
+
+ String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString();
+ String latText = ((EditText) findViewById(R.id.latitude)).getText().toString();
+ String lonText = ((EditText) findViewById(R.id.longitude)).getText().toString();
+
+ if ((bearingText == null || bearingText.length() == 0) && (distanceText == null || distanceText.length() == 0)
+ && (latText == null || latText.length() == 0) && (lonText == null || lonText.length() == 0)) {
+ warning.helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given));
+ return null;
+ }
+
+ if (latText != null && latText.length() > 0 && lonText != null && lonText.length() > 0) {
+ // latitude & longitude
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return null;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return null;
+ }
+
+ latitude = (Double) latParsed.get("coordinate");
+ longitude = (Double) lonParsed.get("coordinate");
+ } else {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_curr_position_unavailable));
+ return null;
+ }
+
+ latitude = geo.latitudeNow;
+ longitude = geo.longitudeNow;
+ }
+
+ if (bearingText != null && bearingText.length() > 0 && distanceText != null && distanceText.length() > 0) {
+ // bearing & distance
+ Double bearing = null;
+ try {
+ bearing = new Double(bearingText);
+ } catch (Exception e) {
+ // probably not a number
+ }
+ if (bearing == null) {
+ warning.helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ return null;
+ }
+
+ Double distance = null; // km
+
+ final Pattern patternA = Pattern.compile("^([0-9\\.\\,]+)[ ]*m$", Pattern.CASE_INSENSITIVE); // m
+ final Pattern patternB = Pattern.compile("^([0-9\\.\\,]+)[ ]*km$", Pattern.CASE_INSENSITIVE); // km
+ final Pattern patternC = Pattern.compile("^([0-9\\.\\,]+)[ ]*ft$", Pattern.CASE_INSENSITIVE); // ft - 0.3048m
+ final Pattern patternD = Pattern.compile("^([0-9\\.\\,]+)[ ]*yd$", Pattern.CASE_INSENSITIVE); // yd - 0.9144m
+ final Pattern patternE = Pattern.compile("^([0-9\\.\\,]+)[ ]*mi$", Pattern.CASE_INSENSITIVE); // mi - 1609.344m
+
+ Matcher matcherA = patternA.matcher(distanceText);
+ Matcher matcherB = patternB.matcher(distanceText);
+ Matcher matcherC = patternC.matcher(distanceText);
+ Matcher matcherD = patternD.matcher(distanceText);
+ Matcher matcherE = patternE.matcher(distanceText);
+
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ distance = (new Double(matcherA.group(1))) * 0.001;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ distance = new Double(matcherB.group(1));
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ distance = (new Double(matcherC.group(1))) * 0.0003048;
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ distance = (new Double(matcherD.group(1))) * 0.0009144;
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ distance = (new Double(matcherE.group(1))) * 1.609344;
+ } else {
+ try {
+ if (settings.units == cgSettings.unitsImperial) {
+ distance = (new Double(distanceText)) * 0.0003048; // considering it feet
+ } else {
+ distance = (new Double(distanceText)) * 0.001; // considering it meters
+ }
+ } catch (Exception e) {
+ // probably not a number
+ }
+ }
+
+ if (distance == null) {
+ warning.showToast(res.getString(R.string.err_parse_dist));
+ return null;
+ }
+
+ Double latParsed = null;
+ Double lonParsed = null;
+
+ HashMap<String, Double> coordsDst = base.getRadialDistance(latitude, longitude, bearing, distance);
+
+ latParsed = coordsDst.get("latitude");
+ lonParsed = coordsDst.get("longitude");
+
+ if (latParsed == null || lonParsed == null) {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return null;
+ }
+
+ coords.add(0, (Double) latParsed);
+ coords.add(1, (Double) lonParsed);
+ } else if (latitude != null && longitude != null) {
+ coords.add(0, latitude);
+ coords.add(1, longitude);
+ } else {
+ return null;
+ }
+
+ saveCoords(coords.get(0), coords.get(1));
+
+ return coords;
+ }
+
+ private void saveCoords(Double latitude, Double longitude) {
+ if (changed == true && latitude == null || longitude == null) {
+ SharedPreferences.Editor edit = prefs.edit();
+
+ edit.putFloat("anylatitude", new Float(latitude));
+ edit.putFloat("anylongitude", new Float(longitude));
+
+ edit.commit();
+ } else {
+ SharedPreferences.Editor edit = prefs.edit();
+
+ edit.remove("anylatitude");
+ edit.remove("anylongitude");
+
+ edit.commit();
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-navigate-any",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeopopup.java b/src/cgeo/geocaching/cgeopopup.java
new file mode 100644
index 0000000..92d1338
--- /dev/null
+++ b/src/cgeo/geocaching/cgeopopup.java
@@ -0,0 +1,834 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.HashMap;
+import java.util.Locale;
+
+public class cgeopopup extends Activity {
+
+ private GoogleAnalyticsTracker tracker = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Boolean fromDetail = false;
+ private LayoutInflater inflater = null;
+ private String geocode = null;
+ private cgCache cache = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private ProgressDialog storeDialog = null;
+ private ProgressDialog dropDialog = null;
+ private TextView cacheDistance = null;
+ private HashMap<String, Integer> gcIcons = new HashMap<String, Integer>();
+ private Handler ratingHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ final Bundle data = msg.getData();
+
+ setRating(data.getFloat("rating"), data.getInt("votes"));
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ };
+ private Handler storeCacheHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (storeDialog != null) {
+ storeDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_store));
+
+ Log.e(cgSettings.tag, "cgeopopup.storeCacheHandler: " + e.toString());
+ }
+
+ if (storeDialog != null) {
+ storeDialog.dismiss();
+ }
+ init();
+ }
+ };
+ private Handler dropCacheHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (dropDialog != null) {
+ dropDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_drop));
+
+ Log.e(cgSettings.tag, "cgeopopup.dropCacheHandler: " + e.toString());
+ }
+
+ if (dropDialog != null) {
+ dropDialog.dismiss();
+ }
+ init();
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ setTheme(R.style.transparent);
+ setContentView(R.layout.popup);
+ base.setTitle(activity, res.getString(R.string.detail));
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/popup");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ fromDetail = extras.getBoolean("fromdetail");
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null || geocode.length() == 0) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 2, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, 3, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, 1, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, 20, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, 21, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, 23, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, 4, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, 6, 0, res.getString(R.string.cache_menu_visit)).setIcon(android.R.drawable.ic_menu_agenda); // log visit
+ menu.add(0, 5, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+ menu.add(0, 7, 0, res.getString(R.string.cache_menu_browser)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ if (cache != null && cache.latitude != null && cache.longitude != null) {
+ menu.findItem(0).setVisible(true);
+ menu.findItem(2).setVisible(true);
+ menu.findItem(5).setVisible(true);
+ } else {
+ menu.findItem(0).setVisible(false);
+ menu.findItem(2).setVisible(false);
+ menu.findItem(5).setVisible(false);
+ }
+
+ if (fromDetail == false && settings.isLogin() == true) {
+ menu.findItem(6).setEnabled(true);
+ } else {
+ menu.findItem(6).setEnabled(false);
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == 1) {
+ showOnMap();
+ return true;
+ } else if (menuItem == 2) {
+ navigateTo();
+ return true;
+ } else if (menuItem == 3) {
+ radarTo();
+ return true;
+ } else if (menuItem == 4) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, cache.latitude, cache.longitude);
+ }
+
+ return true;
+ } else if (menuItem == 5) {
+ cachesAround();
+ return true;
+ } else if (menuItem == 6) {
+ if (cache.cacheid == null || cache.cacheid.length() == 0) {
+ warning.showToast(res.getString(R.string.err_cannot_log_visit));
+ return false;
+ }
+
+ Intent logVisitIntent = new Intent(activity, cgeovisit.class);
+ logVisitIntent.putExtra("id", cache.cacheid);
+ logVisitIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ logVisitIntent.putExtra("type", cache.type.toLowerCase());
+ activity.startActivity(logVisitIntent);
+
+ activity.finish();
+
+ return true;
+ } else if (menuItem == 7) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/seek/cache_details.aspx?wp=" + cache.geocode)));
+ return true;
+ } else if (menuItem == 20) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, cache.latitude, cache.longitude); // locus
+ return true;
+ } else if (menuItem == 21) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, cache.latitude, cache.longitude); // rmaps
+ return true;
+ } else if (menuItem == 23) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, cache.latitude, cache.longitude); // rmaps
+ return true;
+ }
+
+ return false;
+ }
+
+ private void init() {
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ app.setAction(geocode);
+
+ cache = app.getCacheByGeocode(geocode);
+
+ if (cache == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_find));
+
+ finish();
+ return;
+ }
+
+ try {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+ LinearLayout itemStars;
+
+ if (gcIcons == null || gcIcons.isEmpty()) {
+ gcIcons.put("ape", R.drawable.type_ape);
+ gcIcons.put("cito", R.drawable.type_cito);
+ gcIcons.put("earth", R.drawable.type_earth);
+ gcIcons.put("event", R.drawable.type_event);
+ gcIcons.put("letterbox", R.drawable.type_letterbox);
+ gcIcons.put("locationless", R.drawable.type_locationless);
+ gcIcons.put("mega", R.drawable.type_mega);
+ gcIcons.put("multi", R.drawable.type_multi);
+ gcIcons.put("traditional", R.drawable.type_traditional);
+ gcIcons.put("virtual", R.drawable.type_virtual);
+ gcIcons.put("webcam", R.drawable.type_webcam);
+ gcIcons.put("wherigo", R.drawable.type_wherigo);
+ gcIcons.put("mystery", R.drawable.type_mystery);
+ gcIcons.put("gchq", R.drawable.type_hq);
+ }
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, cache.name);
+ } else {
+ base.setTitle(activity, geocode.toUpperCase());
+ }
+
+ inflater = activity.getLayoutInflater();
+ geocode = cache.geocode.toUpperCase();
+
+ ((ScrollView) findViewById(R.id.details_list_box)).setVisibility(View.VISIBLE);
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+ detailsList.removeAllViews();
+
+ // actionbar icon
+ if (cache.type != null && gcIcons.containsKey(cache.type) == true) { // cache icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get(cache.type)), null, null, null);
+ } else { // unknown cache type, "mystery" icon
+ ((TextView) findViewById(R.id.actionbar_title)).setCompoundDrawablesWithIntrinsicBounds((Drawable) activity.getResources().getDrawable(gcIcons.get("mystery")), null, null, null);
+ }
+
+ // cache type
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_type));
+ if (cgBase.cacheTypesInv.containsKey(cache.type) == true) { // cache icon
+ if (cache.size != null && cache.size.length() > 0) {
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type) + " (" + cache.size + ")");
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get(cache.type));
+ }
+ } else {
+ if (cache.size != null && cache.size.length() > 0) {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery") + " (" + cache.size + ")");
+ } else {
+ itemValue.setText(cgBase.cacheTypesInv.get("mystery"));
+ }
+ }
+ detailsList.addView(itemLayout);
+
+ // gc-code
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_geocode));
+ itemValue.setText(cache.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // cache state
+ if (cache.archived == true || cache.disabled == true || cache.members == true || cache.found == true) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_status));
+
+ StringBuilder state = new StringBuilder();
+ if (cache.found == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_found));
+ }
+ if (cache.archived == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_archived));
+ }
+ if (cache.disabled == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_disabled));
+ }
+ if (cache.members == true) {
+ if (state.length() > 0) {
+ state.append(", ");
+ }
+ state.append(res.getString(R.string.cache_status_premium));
+ }
+
+ itemValue.setText(state.toString());
+ detailsList.addView(itemLayout);
+
+ state = null;
+ }
+
+ // distance
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.cache_distance));
+ itemValue.setText("--");
+ detailsList.addView(itemLayout);
+ cacheDistance = itemValue;
+
+ // difficulty
+ if (cache.difficulty > 0f) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_difficulty));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", cache.difficulty) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((cache.difficulty - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((cache.difficulty - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ // terrain
+ if (cache.terrain > 0f) {
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_terrain));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", cache.terrain) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((cache.terrain - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((cache.terrain - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ // rating
+ if (cache.rating != null && cache.rating > 0) {
+ setRating(cache.rating, cache.votes);
+ } else {
+ (new Thread() {
+
+ public void run() {
+ cgRating rating = base.getRating(cache.guid, geocode);
+
+ Message msg = new Message();
+ Bundle bundle = new Bundle();
+
+ if (rating == null || rating.rating == null) {
+ return;
+ }
+
+ bundle.putFloat("rating", rating.rating);
+ bundle.putInt("votes", rating.votes);
+ msg.setData(bundle);
+
+ ratingHandler.sendMessage(msg);
+ }
+ }).start();
+ }
+
+ // more details
+ if (fromDetail == false) {
+ ((LinearLayout) findViewById(R.id.more_details_box)).setVisibility(View.VISIBLE);
+
+ Button buttonMore = (Button) findViewById(R.id.more_details);
+ buttonMore.setOnClickListener(new OnClickListener() {
+
+ public void onClick(View arg0) {
+ Intent cachesIntent = new Intent(activity, cgeodetail.class);
+ cachesIntent.putExtra("geocode", geocode.toUpperCase());
+ activity.startActivity(cachesIntent);
+
+ activity.finish();
+ return;
+ }
+ });
+ } else {
+ ((LinearLayout) findViewById(R.id.more_details_box)).setVisibility(View.GONE);
+ }
+
+ if (fromDetail == false) {
+ ((LinearLayout) findViewById(R.id.offline_box)).setVisibility(View.VISIBLE);
+
+ // offline use
+ final TextView offlineText = (TextView) findViewById(R.id.offline_text);
+ final Button offlineRefresh = (Button) findViewById(R.id.offline_refresh);
+ final Button offlineStore = (Button) findViewById(R.id.offline_store);
+
+ if (cache.reason > 0) {
+ Long diff = (System.currentTimeMillis() / (60 * 1000)) - (cache.detailedUpdate / (60 * 1000)); // minutes
+
+ String ago = "";
+ if (diff < 15) {
+ ago = res.getString(R.string.cache_offline_time_mins_few);
+ } else if (diff < 50) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + diff + " " + res.getString(R.string.cache_offline_time_mins);
+ } else if (diff < 90) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + res.getString(R.string.cache_offline_time_hour);
+ } else if (diff < (48 * 60)) {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / 60) + " " + res.getString(R.string.cache_offline_time_hours);
+ } else {
+ ago = res.getString(R.string.cache_offline_time_about) + " " + (diff / (24 * 60)) + " " + res.getString(R.string.cache_offline_time_days);
+ }
+
+ offlineText.setText(res.getString(R.string.cache_offline_stored) + "\n" + ago);
+
+ offlineRefresh.setVisibility(View.VISIBLE);
+ offlineRefresh.setEnabled(true);
+ offlineRefresh.setOnClickListener(new storeCache());
+
+ offlineStore.setText(res.getString(R.string.cache_offline_drop));
+ offlineStore.setEnabled(true);
+ offlineStore.setOnClickListener(new dropCache());
+ } else {
+ offlineText.setText(res.getString(R.string.cache_offline_not_ready));
+
+ offlineRefresh.setVisibility(View.GONE);
+ offlineRefresh.setEnabled(false);
+ offlineRefresh.setOnTouchListener(null);
+ offlineRefresh.setOnClickListener(null);
+
+ offlineStore.setText(res.getString(R.string.cache_offline_store));
+ offlineStore.setEnabled(true);
+ offlineStore.setOnClickListener(new storeCache());
+ }
+ } else {
+ ((LinearLayout) findViewById(R.id.offline_box)).setVisibility(View.GONE);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeopopup.init: " + e.toString());
+ }
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (geo.latitudeNow != null && geo.longitudeNow != null && cache != null && cache.latitude != null && cache.longitude != null) {
+ cacheDistance.setText(base.getHumanDistance(cgBase.getDistance(geo.latitudeNow, geo.longitudeNow, cache.latitude, cache.longitude)));
+ cacheDistance.bringToFront();
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private void showOnMap() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+
+ mapIntent.putExtra("latitude", cache.latitude);
+ mapIntent.putExtra("longitude", cache.longitude);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void navigateTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", "");
+ navigateIntent.putExtra("name", "Some destination");
+
+ activity.startActivity(navigateIntent);
+ }
+
+ private void radarTo() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(cache.latitude));
+ radarIntent.putExtra("longitude", new Float(cache.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeopoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", cache.latitude);
+ cachesIntent.putExtra("longitude", cache.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class storeCache implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (dropDialog != null && dropDialog.isShowing() == true) {
+ warning.showToast("Still removing this cache.");
+ return;
+ }
+
+ storeDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_save_title), res.getString(R.string.cache_dialog_offline_save_message), true);
+ storeDialog.setCancelable(false);
+ Thread thread = new storeCacheThread(storeCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class storeCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public storeCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.storeCache(app, activity, cache, null, 1, handler);
+ }
+ }
+
+ private class dropCache implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (storeDialog != null && storeDialog.isShowing() == true) {
+ warning.showToast("Still saving this cache.");
+ return;
+ }
+
+ dropDialog = ProgressDialog.show(activity, res.getString(R.string.cache_dialog_offline_drop_title), res.getString(R.string.cache_dialog_offline_drop_message), true);
+ dropDialog.setCancelable(false);
+ Thread thread = new dropCacheThread(dropCacheHandler);
+ thread.start();
+ }
+ }
+
+ private class dropCacheThread extends Thread {
+
+ private Handler handler = null;
+
+ public dropCacheThread(Handler handlerIn) {
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ base.dropCache(app, activity, cache, handler);
+ }
+ }
+
+ private void setRating(Float rating, Integer votes) {
+ if (rating == null || rating <= 0) {
+ return;
+ }
+
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+ LinearLayout itemStars;
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+
+ itemLayout = (RelativeLayout) inflater.inflate(R.layout.cache_layout, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+ itemStars = (LinearLayout) itemLayout.findViewById(R.id.stars);
+
+ itemName.setText(res.getString(R.string.cache_rating));
+ itemValue.setText(String.format(Locale.getDefault(), "%.1f", rating) + " of 5");
+ for (int i = 0; i <= 4; i++) {
+ ImageView star = (ImageView) inflater.inflate(R.layout.star, null);
+ if ((rating - i) >= 1.0) {
+ star.setImageResource(R.drawable.star_on);
+ } else if ((rating - i) > 0.0) {
+ star.setImageResource(R.drawable.star_half);
+ } else {
+ star.setImageResource(R.drawable.star_off);
+ }
+ itemStars.addView(star, (1 + i));
+ }
+ if (votes != null) {
+ final TextView itemAddition = (TextView) itemLayout.findViewById(R.id.addition);
+ itemAddition.setText("(" + votes + ")");
+ itemAddition.setVisibility(View.VISIBLE);
+ }
+ detailsList.addView(itemLayout);
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goCompass(View view) {
+ if (cache == null || cache.latitude == null || cache.longitude == null) {
+ warning.showToast(res.getString(R.string.cache_coordinates_no));
+
+ return;
+ }
+
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ Intent navigateIntent = new Intent(activity, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", cache.latitude);
+ navigateIntent.putExtra("longitude", cache.longitude);
+ navigateIntent.putExtra("geocode", cache.geocode.toUpperCase());
+ navigateIntent.putExtra("name", cache.name);
+
+ activity.startActivity(navigateIntent);
+
+ finish();
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-cache-info",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+
+ finish();
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeosmaps.java b/src/cgeo/geocaching/cgeosmaps.java
new file mode 100644
index 0000000..9979ab5
--- /dev/null
+++ b/src/cgeo/geocaching/cgeosmaps.java
@@ -0,0 +1,172 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+public class cgeosmaps extends Activity {
+
+ private ArrayList<Bitmap> maps = new ArrayList<Bitmap>();
+ private String geocode = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private ProgressDialog waitDialog = null;
+ private LinearLayout smapsView = null;
+ private BitmapFactory factory = null;
+ private Handler loadMapsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (maps == null || maps.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast(res.getString(R.string.err_detail_not_load_map_static));
+
+ finish();
+ return;
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ if (smapsView == null) {
+ smapsView = (LinearLayout) findViewById(R.id.maps_list);
+ }
+ smapsView.removeAllViews();
+
+ int cnt = 1;
+ for (Bitmap image : maps) {
+ if (image != null) {
+ final ImageView map = (ImageView) inflater.inflate(R.layout.map_static_item, null);
+ map.setImageBitmap(image);
+ smapsView.addView(map);
+
+ cnt++;
+ }
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeosmaps.loadMapsHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.map_static);
+ base.setTitle(activity, res.getString(R.string.map_static_title));
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load static maps.");
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.map_static_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadMaps()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadMaps extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ if (factory == null) {
+ factory = new BitmapFactory();
+ }
+
+ for (int level = 1; level <= 5; level++) {
+ try {
+ Bitmap image = BitmapFactory.decodeFile(settings.getStorage() + geocode + "/map_" + level);
+ if (image != null) {
+ maps.add(image);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run.1: " + e.toString());
+ }
+ }
+
+ if (maps.isEmpty() == true) {
+ for (int level = 1; level <= 5; level++) {
+ try {
+ Bitmap image = BitmapFactory.decodeFile(settings.getStorageSec() + geocode + "/map_" + level);
+ if (image != null) {
+ maps.add(image);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run.2: " + e.toString());
+ }
+ }
+ }
+
+ loadMapsHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeosmaps.loadMaps.run: " + e.toString());
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeospoilers.java b/src/cgeo/geocaching/cgeospoilers.java
new file mode 100644
index 0000000..4d2bd58
--- /dev/null
+++ b/src/cgeo/geocaching/cgeospoilers.java
@@ -0,0 +1,231 @@
+package cgeo.geocaching;
+
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.net.Uri;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.util.Log;
+import android.text.Html;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.view.ViewGroup.LayoutParams;
+
+public class cgeospoilers extends Activity {
+ private ArrayList<cgSpoiler> spoilers = new ArrayList<cgSpoiler>();
+ private Resources res = null;
+ private String geocode = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private LayoutInflater inflater = null;
+ private ProgressDialog progressDialog = null;
+ private ProgressDialog waitDialog = null;
+ private LinearLayout spoilerView = null;
+ private int offline = 0;
+ private int count = 0;
+ private int countDone = 0;
+ private Handler loadSpoilersHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (spoilers.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast("Sorry, c:geo failed to load spoiler images.");
+
+ finish();
+ return;
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (app.isOffline(geocode, null) == true) {
+ offline = 1;
+ } else {
+ offline = 0;
+ }
+
+ count = spoilers.size();
+ progressDialog = new ProgressDialog(activity);
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setMessage(res.getString(R.string.cache_spoiler_images_loading));
+ progressDialog.setCancelable(true);
+ progressDialog.setMax(count);
+ progressDialog.show();
+
+ LinearLayout rowView = null;
+ for (final cgSpoiler spl : spoilers) {
+ rowView = (LinearLayout) inflater.inflate(R.layout.spoiler_item, null);
+
+ ((TextView) rowView.findViewById(R.id.title)).setText(Html.fromHtml(spl.title));
+
+ if (spl.description != null && spl.description.length() > 0) {
+ final TextView descView = (TextView) rowView.findViewById(R.id.description);
+ descView.setText(Html.fromHtml(spl.description), TextView.BufferType.SPANNABLE);
+ descView.setVisibility(View.VISIBLE);
+ }
+
+ final Handler handler = new onLoadHandler(rowView, spl);
+
+ new Thread() {
+
+ @Override
+ public void run() {
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, geocode, true, offline, false);
+
+ image = imgGetter.getDrawable(spl.url);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString());
+ }
+
+ }
+ }.start();
+
+ spoilerView.addView(rowView);
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeospoilers.loadSpoilersHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.spoilers);
+ base.setTitle(activity, res.getString(R.string.cache_spoiler_images_title));
+
+ // google analytics
+ base.sendAnal(activity, "/spoilers");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load spoiler images.");
+ finish();
+ return;
+ }
+
+ inflater = activity.getLayoutInflater();
+ if (spoilerView == null) {
+ spoilerView = (LinearLayout) findViewById(R.id.spoiler_list);
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.cache_spoiler_images_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadSpoilers()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadSpoilers extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ spoilers = app.loadSpoilers(geocode);
+
+ loadSpoilersHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.loadSpoilers.run: " + e.toString());
+ }
+ }
+ }
+
+ private class onLoadHandler extends Handler {
+
+ LinearLayout view = null;
+ cgSpoiler spoiler = null;
+
+ public onLoadHandler(LinearLayout view, cgSpoiler spoiler) {
+ this.view = view;
+ this.spoiler = spoiler;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null) {
+ ImageView spoilerImage = null;
+ spoilerImage = (ImageView) inflater.inflate(R.layout.image_item, null);
+
+ Rect bounds = image.getBounds();
+
+ spoilerImage.setImageResource(R.drawable.image_not_loaded);
+ spoilerImage.setClickable(true);
+ spoilerImage.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(spoiler.url)));
+ }
+ });
+ spoilerImage.setImageDrawable((BitmapDrawable) message.obj);
+ spoilerImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ spoilerImage.setLayoutParams(new LayoutParams(bounds.width(), bounds.height()));
+
+ view.addView(spoilerImage);
+ }
+
+ countDone++;
+ progressDialog.setProgress(countDone);
+ if (progressDialog.getProgress() >= count) {
+ progressDialog.dismiss();
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+}
diff --git a/src/cgeo/geocaching/cgeotouch.java b/src/cgeo/geocaching/cgeotouch.java
new file mode 100644
index 0000000..07f83d5
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotouch.java
@@ -0,0 +1,487 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class cgeotouch extends cgLogForm {
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private LayoutInflater inflater = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private cgWarning warning = null;
+ private cgTrackable trackable = null;
+ private ArrayList<Integer> types = new ArrayList<Integer>();
+ private ProgressDialog waitDialog = null;
+ private String guid = null;
+ private String geocode = null;
+ private String text = null;
+ private String viewstate = null;
+ private String viewstate1 = null;
+ private Boolean gettingViewstate = true;
+ private Calendar date = Calendar.getInstance();
+ private int typeSelected = -1;
+ private int attempts = 0;
+ private CheckBox tweetCheck = null;
+ private LinearLayout tweetBox = null;
+
+ private Handler showProgressHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ base.showProgress(activity, true);
+ }
+ };
+
+ private Handler loadDataHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if ((viewstate == null || viewstate.length() == 0) && attempts < 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data_again));
+
+ loadData thread;
+ thread = new loadData(guid);
+ thread.start();
+
+ return;
+ } else if ((viewstate == null || viewstate.length() == 0) && attempts >= 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data));
+ base.showProgress(activity, false);
+
+ return;
+ }
+
+ gettingViewstate = false; // we're done, user can post log
+
+ Button buttonPost = (Button)findViewById(R.id.post);
+ buttonPost.setEnabled(true);
+ buttonPost.setOnClickListener(new postListener());
+
+ base.showProgress(activity, false);
+ }
+ };
+
+ private Handler postLogHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.info_log_posted));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ finish();
+ return;
+ } else if (msg.what >= 1000) {
+ if (msg.what == 1001) {
+ warning.showToast(res.getString(R.string.warn_log_text_fill));
+ } else if(msg.what == 1002) {
+ warning.showToast(res.getString(R.string.err_log_failed_server));
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ } else {
+ if (cgBase.errorRetrieve.get(msg.what) != null) {
+ warning.showToast(res.getString(R.string.err_log_post_failed_because) + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication)this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.touch);
+ base.setTitle(activity, res.getString(R.string.trackable_touch));
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/touch");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ guid = extras.getString("guid");
+ text = extras.getString("text");
+ }
+
+ trackable = app.getTrackableByGeocode("logging trackable");
+
+ if (trackable.name != null && trackable.name.length() > 0) {
+ base.setTitle(activity, res.getString(R.string.trackable_touch) + trackable.name);
+ } else {
+ base.setTitle(activity, res.getString(R.string.trackable_touch) + trackable.geocode.toUpperCase());
+ }
+
+ app.setAction("logging trackable");
+
+ if (trackable == null || guid == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot_saw));
+
+ finish();
+ return;
+ }
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenu = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add);
+
+ subMenu.add(0, 0x6, 0, res.getString(R.string.log_date_time));
+ subMenu.add(0, 0x4, 0, res.getString(R.string.log_date));
+ subMenu.add(0, 0x2, 0, res.getString(R.string.log_time));
+ subMenu.add(0, 0x1, 0, res.getString(R.string.init_signature));
+ subMenu.add(0, 0x7, 0, res.getString(R.string.log_date_time) + " & " + res.getString(R.string.init_signature));
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ if (settings.getSignature() == null) {
+ menu.findItem(0x1).setVisible(false);
+ menu.findItem(0x7).setVisible(false);
+ } else {
+ menu.findItem(0x1).setVisible(true);
+ menu.findItem(0x7).setVisible(true);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ EditText text = null;
+ String textContent = null;
+ String dateString = null;
+ String timeString = null;
+ String addText = "";
+
+ if ((id >= 0x1 && id <= 0x7)) {
+ text = (EditText) findViewById(R.id.log);
+ textContent = text.getText().toString();
+ dateString = cgBase.dateOut.format(new Date());
+ timeString = cgBase.timeOut.format(new Date());
+
+ if ((id & 0x4) == 0x4) {
+ addText += dateString;
+ if ((id & 0x2) == 0x2) {
+ addText += " | ";
+ }
+ }
+ if ((id & 0x2) == 0x2) {
+ addText += timeString;
+ }
+ if ((id & 0x1) == 0x1 && settings.getSignature() != null) {
+ if (addText.length() > 0) {
+ addText += "\n";
+ }
+ addText += settings.getSignature()
+ .replaceAll("\\[DATE\\]", dateString)
+ .replaceAll("\\[TIME\\]", timeString)
+ .replaceAll("\\[USER\\]", settings.getUsername())
+ .replaceAll("\\[NUMBER\\]", "");
+ }
+ if (textContent.length() > 0 && addText.length() > 0 ) {
+ addText = "\n" + addText;
+ }
+ text.setText(textContent + addText, TextView.BufferType.NORMAL);
+ text.setSelection(text.getText().toString().length());
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.type) {
+ for (final int typeOne : types) menu.add(viewId, typeOne, 0, cgBase.logTypes2.get(typeOne));
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+ final int id = item.getItemId();
+
+ if (group == R.id.type) {
+ setType(id);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public void init() {
+ if (geocode != null) app.setAction("logging trackable");
+
+ types.clear();
+ types.add(cgBase.LOG_RETRIEVED_IT);
+ types.add(cgBase.LOG_GRABBED_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_DISCOVERED_IT);
+
+ if (typeSelected < 0 && cgBase.logTypes2.get(typeSelected) == null) typeSelected = types.get(2);
+ setType(typeSelected);
+
+ Button typeButton = (Button)findViewById(R.id.type);
+ registerForContextMenu(typeButton);
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+ typeButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ Button dateButton = (Button)findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeotouchDateListener());
+
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (tweetCheck == null) tweetCheck = (CheckBox)findViewById(R.id.tweet);
+ tweetCheck.setChecked(true);
+
+ Button buttonPost = (Button)findViewById(R.id.post);
+ if (viewstate == null || viewstate.length() == 0) {
+ buttonPost.setEnabled(false);
+ buttonPost.setOnTouchListener(null);
+ buttonPost.setOnClickListener(null);
+
+ loadData thread;
+ thread = new loadData(guid);
+ thread.start();
+ } else {
+ buttonPost.setEnabled(true);
+ buttonPost.setOnClickListener(new postListener());
+ }
+ }
+
+ public void setDate(Calendar dateIn) {
+ date = dateIn;
+
+ final Button dateButton = (Button)findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ }
+
+ public void setType(int type) {
+ final Button typeButton = (Button)findViewById(R.id.type);
+
+ if (cgBase.logTypes2.get(type) != null) typeSelected = type;
+ if (cgBase.logTypes2.get(typeSelected) == null) typeSelected = 0;
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (settings.twitter == 1) tweetBox.setVisibility(View.VISIBLE);
+ else tweetBox.setVisibility(View.GONE);
+ }
+
+ private class cgeotouchDateListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ Dialog dateDialog = new cgeodate(activity, (cgeotouch)activity, date);
+ dateDialog.setCancelable(true);
+ dateDialog.show();
+ }
+ }
+
+ private class postListener implements View.OnClickListener {
+ public void onClick(View arg0) {
+ if (gettingViewstate == false) {
+ waitDialog = ProgressDialog.show(activity, null, res.getString(R.string.log_saving), true);
+ waitDialog.setCancelable(true);
+
+ String tracking = ((EditText)findViewById(R.id.tracking)).getText().toString();
+ String log = ((EditText)findViewById(R.id.log)).getText().toString();
+ Thread thread = new postLog(postLogHandler, tracking, log);
+ thread.start();
+ } else {
+ warning.showToast(res.getString(R.string.err_log_load_data_still));
+ }
+ }
+ }
+
+ private class loadData extends Thread {
+ private String guid = null;
+
+ public loadData(String guidIn) {
+ guid = guidIn;
+
+ if (guid == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot_saw));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ showProgressHandler.sendEmptyMessage(0);
+ gettingViewstate = true;
+ attempts ++;
+
+ try {
+ if (guid != null && guid.length() > 0) {
+ params.put("wid", guid);
+ } else {
+ loadDataHandler.sendEmptyMessage(0);
+ return;
+ }
+
+ final String page = base.request(false, "www.geocaching.com", "/track/log.aspx", "GET", params, false, false, false).getData();
+
+ viewstate = base.findViewstate(page, 0);
+ viewstate1 = base.findViewstate(page, 1);
+
+ final ArrayList<Integer> typesPre = base.parseTypes(page);
+ if (typesPre.size() > 0) {
+ types.clear();
+ types.addAll(typesPre);
+ }
+ typesPre.clear();
+
+ if (types.contains(typeSelected) == false) {
+ typeSelected = types.get(0);
+ setType(typeSelected);
+ warning.showToast(res.getString(R.string.info_log_type_changed));
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotouch.loadData.run: " + e.toString());
+ }
+
+ loadDataHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class postLog extends Thread {
+ Handler handler = null;
+ String tracking = null;
+ String log = null;
+
+ public postLog(Handler handlerIn, String trackingIn, String logIn) {
+ handler = handlerIn;
+ tracking = trackingIn;
+ log = logIn;
+ }
+
+ @Override
+ public void run() {
+ int ret = -1;
+
+ ret = postLogFn(tracking, log);
+
+ handler.sendEmptyMessage(ret);
+ }
+ }
+
+ public int postLogFn(String tracking, String log) {
+ int status = -1;
+
+ try {
+ if (tweetBox == null) tweetBox = (LinearLayout)findViewById(R.id.tweet_box);
+ if (tweetCheck == null) tweetCheck = (CheckBox)findViewById(R.id.tweet);
+
+ status = base.postLogTrackable(guid, tracking, viewstate, viewstate1, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH ) + 1), date.get(Calendar.DATE), log);
+
+ if (
+ status == 1 && settings.twitter == 1 &&
+ settings.tokenPublic != null && settings.tokenPublic.length() > 0 && settings.tokenSecret != null && settings.tokenSecret.length() > 0 &&
+ tweetCheck.isChecked() == true && tweetBox.getVisibility() == View.VISIBLE
+ ) {
+ base.postTweetTrackable(app, settings, geocode);
+ }
+
+ return status;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotouch.postLogFn: " + e.toString());
+ }
+
+ return 1000;
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-log-trackable",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeotrackable.java b/src/cgeo/geocaching/cgeotrackable.java
new file mode 100644
index 0000000..98b8cbc
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotrackable.java
@@ -0,0 +1,671 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.net.URLEncoder;
+import java.util.Date;
+import java.util.HashMap;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.text.Html;
+import android.text.method.LinkMovementMethod;
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.widget.ScrollView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.widget.ImageView;
+
+public class cgeotrackable extends Activity {
+ public cgTrackable trackable = null;
+ public String geocode = null;
+ public String name = null;
+ public String guid = null;
+ public String id = null;
+ private String contextMenuUser = null;
+ private Resources res = null;
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadTrackableHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ RelativeLayout itemLayout;
+ TextView itemName;
+ TextView itemValue;
+
+ if (trackable != null && trackable.errorRetrieve != 0) {
+ warning.showToast(res.getString(R.string.err_tb_details_download) + " " + cgBase.errorRetrieve.get(trackable.errorRetrieve) + ".");
+
+ finish();
+ return;
+ }
+
+ if (trackable != null && trackable.error.length() > 0) {
+ warning.showToast(res.getString(R.string.err_tb_details_download) + " " + trackable.error + ".");
+
+ finish();
+ return;
+ }
+
+ if (trackable == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ if (geocode != null && geocode.length() > 0) {
+ warning.showToast(res.getString(R.string.err_tb_find) + " " + geocode + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_find_that));
+ }
+
+ finish();
+ return;
+ }
+
+ try {
+ inflater = activity.getLayoutInflater();
+ geocode = trackable.geocode.toUpperCase();
+
+ if (trackable.name != null && trackable.name.length() > 0) {
+ base.setTitle(activity, Html.fromHtml(trackable.name).toString());
+ } else {
+ base.setTitle(activity, trackable.name.toUpperCase());
+ }
+
+ ((ScrollView) findViewById(R.id.details_list_box)).setVisibility(View.VISIBLE);
+ LinearLayout detailsList = (LinearLayout) findViewById(R.id.details_list);
+
+ // actiobar icon
+ if (trackable.iconUrl != null && trackable.iconUrl.length() > 0) {
+ final tbIconHandler iconHandler = new tbIconHandler(((TextView) findViewById(R.id.actionbar_title)));
+ final tbIconThread iconThread = new tbIconThread(trackable.iconUrl, iconHandler);
+ iconThread.start();
+ }
+
+ // trackable name
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_name));
+ if (trackable.name != null) {
+ itemValue.setText(Html.fromHtml(trackable.name).toString());
+ } else {
+ itemValue.setText(res.getString(R.string.trackable_unknown));
+ }
+ detailsList.addView(itemLayout);
+
+ // trackable type
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ String tbType = null;
+ if (trackable.type != null && trackable.type.length() > 0) {
+ tbType = Html.fromHtml(trackable.type).toString();
+ } else {
+ tbType = res.getString(R.string.trackable_unknown);
+ }
+ itemName.setText(res.getString(R.string.trackable_type));
+ itemValue.setText(tbType);
+ detailsList.addView(itemLayout);
+
+ // trackable geocode
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_code));
+ itemValue.setText(trackable.geocode.toUpperCase());
+ detailsList.addView(itemLayout);
+
+ // trackable owner
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_owner));
+ if (trackable.owner != null) {
+ itemValue.setText(Html.fromHtml(trackable.owner), TextView.BufferType.SPANNABLE);
+ itemLayout.setOnClickListener(new userActions());
+ } else {
+ itemValue.setText(res.getString(R.string.trackable_unknown));
+ }
+ detailsList.addView(itemLayout);
+
+ // trackable spotted
+ if (
+ (trackable.spottedName != null && trackable.spottedName.length() > 0) ||
+ trackable.spottedType == cgTrackable.SPOTTED_UNKNOWN ||
+ trackable.spottedType == cgTrackable.SPOTTED_OWNER
+ ) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_spotted));
+ String text = null;
+
+ if (trackable.spottedType == cgTrackable.SPOTTED_CACHE) {
+ text = res.getString(R.string.trackable_spotted_in_cache) + " " + Html.fromHtml(trackable.spottedName).toString();
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_USER) {
+ text = res.getString(R.string.trackable_spotted_at_user) + " " + Html.fromHtml(trackable.spottedName).toString();
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_UNKNOWN) {
+ text = res.getString(R.string.trackable_spotted_unknown_location);
+ } else if (trackable.spottedType == cgTrackable.SPOTTED_OWNER) {
+ text = res.getString(R.string.trackable_spotted_owner);
+ } else {
+ text = "N/A";
+ }
+
+ itemValue.setText(text);
+ itemLayout.setClickable(true);
+ if (cgTrackable.SPOTTED_CACHE == trackable.spottedType) {
+ itemLayout.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ Intent cacheIntent = new Intent(activity, cgeodetail.class);
+ cacheIntent.putExtra("guid", (String) trackable.spottedGuid);
+ cacheIntent.putExtra("name", (String) trackable.spottedName);
+ activity.startActivity(cacheIntent);
+ }
+ });
+ } else if (cgTrackable.SPOTTED_USER == trackable.spottedType) {
+ itemLayout.setOnClickListener(new userActions());
+ //activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?guid=" + trackable.spottedGuid)));
+ }
+
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable origin
+ if (trackable.origin != null && trackable.origin.length() > 0) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_origin));
+ itemValue.setText(Html.fromHtml(trackable.origin), TextView.BufferType.SPANNABLE);
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable released
+ if (trackable.released != null) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_released));
+ itemValue.setText(cgBase.dateOut.format(trackable.released));
+ detailsList.addView(itemLayout);
+ }
+
+ // trackable distance
+ if (trackable.distance != null) {
+ itemLayout = (RelativeLayout)inflater.inflate(R.layout.cache_item, null);
+ itemName = (TextView) itemLayout.findViewById(R.id.name);
+ itemValue = (TextView) itemLayout.findViewById(R.id.value);
+
+ itemName.setText(res.getString(R.string.trackable_distance));
+ itemValue.setText(base.getHumanDistance(trackable.distance));
+ detailsList.addView(itemLayout);
+ }
+
+
+ // trackable goal
+ if (trackable.goal != null && trackable.goal.length() > 0) {
+ ((LinearLayout) findViewById(R.id.goal_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.goal);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(trackable.goal, new cgHtmlImg(activity, settings, geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // trackable details
+ if (trackable.details != null && trackable.details.length() > 0) {
+ ((LinearLayout) findViewById(R.id.details_box)).setVisibility(View.VISIBLE);
+ TextView descView = (TextView) findViewById(R.id.details);
+ descView.setVisibility(View.VISIBLE);
+ descView.setText(Html.fromHtml(trackable.details, new cgHtmlImg(activity, settings, geocode, true, 0, false), null), TextView.BufferType.SPANNABLE);
+ descView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ // trackable image
+ if (trackable.image != null && trackable.image.length() > 0) {
+ ((LinearLayout) findViewById(R.id.image_box)).setVisibility(View.VISIBLE);
+ LinearLayout imgView = (LinearLayout) findViewById(R.id.image);
+
+ final ImageView trackableImage = (ImageView) inflater.inflate(R.layout.trackable_image, null);
+
+ trackableImage.setImageResource(R.drawable.image_not_loaded);
+ trackableImage.setClickable(true);
+ trackableImage.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View arg0) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(trackable.image)));
+ }
+ });
+
+ // try to load image
+ final Handler handler = new Handler() {
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null) {
+ trackableImage.setImageDrawable((BitmapDrawable) message.obj);
+ }
+ }
+ };
+
+ new Thread() {
+
+ @Override
+ public void run() {
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, geocode, true, 0, false);
+
+ image = imgGetter.getDrawable(trackable.image);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeospoilers.onCreate.onClick.run: " + e.toString());
+ }
+ }
+ }.start();
+
+ imgView.addView(trackableImage);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackable.loadTrackableHandler: " + e.toString() + e.getStackTrace());
+ }
+
+ displayLogs();
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.trackable_detail);
+ base.setTitle(activity, res.getString(R.string.trackable));
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/detail");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ Uri uri = getIntent().getData();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ name = extras.getString("name");
+ guid = extras.getString("guid");
+ id = extras.getString("id");
+ }
+
+ // try to get data from URI
+ if (geocode == null && guid == null && id == null && uri != null) {
+ String uriHost = uri.getHost().toLowerCase();
+ if (uriHost.contains("geocaching.com") == true) {
+ geocode = uri.getQueryParameter("tracker");
+ guid = uri.getQueryParameter("guid");
+ id = uri.getQueryParameter("id");
+
+ if (geocode != null && geocode.length() > 0) {
+ geocode = geocode.toUpperCase();
+ guid = null;
+ id = null;
+ } else if (guid != null && guid.length() > 0) {
+ geocode = null;
+ guid = guid.toLowerCase();
+ id = null;
+ } else if (id != null && id.length() > 0) {
+ geocode = null;
+ guid = null;
+ id = id.toLowerCase();
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_details_open));
+ finish();
+ return;
+ }
+ } else if (uriHost.contains("coord.info") == true) {
+ String uriPath = uri.getPath().toLowerCase();
+ if (uriPath != null && uriPath.startsWith("/tb") == true) {
+ geocode = uriPath.substring(1).toUpperCase();
+ guid = null;
+ id = null;
+ } else {
+ warning.showToast(res.getString(R.string.err_tb_details_open));
+ finish();
+ return;
+ }
+ }
+ }
+
+ // no given data
+ if (geocode == null && guid == null && id == null) {
+ warning.showToast(res.getString(R.string.err_tb_display));
+ finish();
+ return;
+ }
+
+ if (name != null && name.length() > 0) {
+ waitDialog = ProgressDialog.show(this, Html.fromHtml(name).toString(), res.getString(R.string.trackable_details_loading), true);
+ } else if (geocode != null && geocode.length() > 0) {
+ waitDialog = ProgressDialog.show(this, geocode.toUpperCase(), res.getString(R.string.trackable_details_loading), true);
+ } else {
+ waitDialog = ProgressDialog.show(this, res.getString(R.string.trackable), res.getString(R.string.trackable_details_loading), true);
+ }
+ waitDialog.setCancelable(true);
+
+ loadTrackable thread;
+ thread = new loadTrackable(loadTrackableHandler, geocode, guid, id);
+ thread.start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.author) { // Log item author
+ contextMenuUser = ((TextView)view).getText().toString();
+ } else { // Trackable owner, and user holding trackable now
+ RelativeLayout itemLayout = (RelativeLayout)view;
+ TextView itemName = (TextView) itemLayout.findViewById(R.id.name);
+
+ String selectedName = itemName.getText().toString();
+ if (selectedName.equals(res.getString(R.string.trackable_owner))) {
+ contextMenuUser = trackable.owner;
+ } else if (selectedName.equals(res.getString(R.string.trackable_spotted))) {
+ contextMenuUser = trackable.spottedName;
+ }
+ }
+
+ menu.setHeaderTitle(res.getString(R.string.user_menu_title) + " " + contextMenuUser);
+ menu.add(viewId, 1, 0, res.getString(R.string.user_menu_view_hidden));
+ menu.add(viewId, 2, 0, res.getString(R.string.user_menu_view_found));
+ menu.add(viewId, 3, 0, res.getString(R.string.user_menu_open_browser));
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "owner");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 2) {
+ final Intent cachesIntent = new Intent(activity, cgeocaches.class);
+
+ cachesIntent.putExtra("type", "username");
+ cachesIntent.putExtra("username", contextMenuUser);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ return true;
+ } else if (id == 3) {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + URLEncoder.encode(contextMenuUser))));
+
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 1, 0, res.getString(R.string.trackable_log_touch)).setIcon(android.R.drawable.ic_menu_agenda); // log touch
+
+ menu.add(0, 2, 0, res.getString(R.string.trackable_browser_open)).setIcon(android.R.drawable.ic_menu_info_details); // browser
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case 1:
+ logTouch();
+ return true;
+ case 2:
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/track/details.aspx?tracker=" + trackable.geocode)));
+ return true;
+ }
+
+ return false;
+ }
+
+ private class loadTrackable extends Thread {
+
+ private Handler handler = null;
+ private String geocode = null;
+ private String guid = null;
+ private String id = null;
+
+ public loadTrackable(Handler handlerIn, String geocodeIn, String guidIn, String idIn) {
+ handler = handlerIn;
+ geocode = geocodeIn;
+ guid = guidIn;
+ id = idIn;
+
+ if (geocode == null && guid == null && id == null) {
+ warning.showToast(res.getString(R.string.err_tb_forgot));
+
+ stop();
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ loadTrackableFn(geocode, guid, id);
+ handler.sendMessage(new Message());
+ }
+ }
+
+ public void loadTrackableFn(String geocode, String guid, String id) {
+ HashMap<String, String> params = new HashMap<String, String>();
+ if (geocode != null && geocode.length() > 0) {
+ params.put("geocode", geocode);
+ } else if (guid != null && guid.length() > 0) {
+ params.put("guid", guid);
+ } else if (id != null && id.length() > 0) {
+ params.put("id", id);
+ } else {
+ return;
+ }
+
+ trackable = base.searchTrackable(params);
+ }
+
+ private void displayLogs() {
+ // trackable logs
+ LinearLayout listView = (LinearLayout) findViewById(R.id.log_list);
+ listView.removeAllViews();
+
+ RelativeLayout rowView;
+
+ if (trackable != null && trackable.logs != null) {
+ for (cgLog log : trackable.logs) {
+ rowView = (RelativeLayout) inflater.inflate(R.layout.trackable_logitem, null);
+
+ if (log.date > 0) {
+ final Date logDate = new Date(log.date);
+ ((TextView) rowView.findViewById(R.id.added)).setText(cgBase.dateOutShort.format(logDate));
+ }
+
+
+ if (cgBase.logTypes1.containsKey(log.type) == true) {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(log.type));
+ } else {
+ ((TextView) rowView.findViewById(R.id.type)).setText(cgBase.logTypes1.get(4)); // note if type is unknown
+ }
+ ((TextView) rowView.findViewById(R.id.author)).setText(Html.fromHtml(log.author), TextView.BufferType.SPANNABLE);
+
+ if (log.cacheName == null || log.cacheName.length() == 0) {
+ ((TextView) rowView.findViewById(R.id.location)).setVisibility(View.GONE);
+ } else {
+ ((TextView) rowView.findViewById(R.id.location)).setText(Html.fromHtml(log.cacheName));
+ final String cacheGuid = log.cacheGuid;
+ final String cacheName = log.cacheName;
+ ((TextView) rowView.findViewById(R.id.location)).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View arg0) {
+ Intent cacheIntent = new Intent(activity, cgeodetail.class);
+ cacheIntent.putExtra("guid", (String) cacheGuid);
+ cacheIntent.putExtra("name", (String) Html.fromHtml(cacheName).toString());
+ activity.startActivity(cacheIntent);
+ }
+ });
+ }
+
+ ((TextView) rowView.findViewById(R.id.log)).setText(Html.fromHtml(log.log, new cgHtmlImg(activity, settings, null, false, 0, false), null), TextView.BufferType.SPANNABLE);
+
+ ((TextView) rowView.findViewById(R.id.author)).setOnClickListener(new userActions());
+ listView.addView(rowView);
+ }
+
+ if (trackable.logs.size() > 0) {
+ ((LinearLayout) findViewById(R.id.log_box)).setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ private class userActions implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (view == null) {
+ return;
+ }
+
+ try {
+ registerForContextMenu(view);
+ openContextMenu(view);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+ }
+
+ private void logTouch() {
+ Intent logTouchIntent = new Intent(activity, cgeotouch.class);
+ logTouchIntent.putExtra("geocode", trackable.geocode.toUpperCase());
+ logTouchIntent.putExtra("guid", trackable.guid);
+ activity.startActivity(logTouchIntent);
+ }
+
+ private class tbIconThread extends Thread {
+ String url = null;
+ Handler handler = null;
+
+ public tbIconThread(String urlIn, Handler handlerIn) {
+ url = urlIn;
+ handler = handlerIn;
+ }
+
+ @Override
+ public void run() {
+ if (url == null || handler == null) {
+ return;
+ }
+
+ BitmapDrawable image = null;
+ try {
+ cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, trackable.geocode, false, 0, false);
+
+ image = imgGetter.getDrawable(url);
+ Message message = handler.obtainMessage(0, image);
+ handler.sendMessage(message);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackable.tbIconThread.run: " + e.toString());
+ }
+ }
+ }
+
+ private class tbIconHandler extends Handler {
+ TextView view = null;
+
+ public tbIconHandler(TextView viewIn) {
+ view = viewIn;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ BitmapDrawable image = (BitmapDrawable) message.obj;
+ if (image != null && view != null) {
+ view.setCompoundDrawablesWithIntrinsicBounds((Drawable) image, null, null, null);
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-trackable-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/cgeotrackables.java b/src/cgeo/geocaching/cgeotrackables.java
new file mode 100644
index 0000000..d414e16
--- /dev/null
+++ b/src/cgeo/geocaching/cgeotrackables.java
@@ -0,0 +1,186 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import java.util.ArrayList;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+public class cgeotrackables extends Activity {
+ private ArrayList<cgTrackable> trackables = new ArrayList<cgTrackable>();
+ private String geocode = null;
+ private cgeoapplication app = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private LayoutInflater inflater = null;
+ private LinearLayout addList = null;
+ private ProgressDialog waitDialog = null;
+ private Handler loadInventoryHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ if (addList == null) {
+ addList = (LinearLayout) findViewById(R.id.trackable_list);
+ }
+
+ if (trackables.isEmpty()) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ warning.showToast("Sorry, c:geo failed to load cache inventory.");
+
+ finish();
+ return;
+ } else {
+ LinearLayout oneTbPre = null;
+ for (cgTrackable trackable : trackables) {
+ oneTbPre = (LinearLayout) inflater.inflate(R.layout.trackable_button, null);
+
+ Button oneTb = (Button) oneTbPre.findViewById(R.id.button);
+
+ if (trackable.name != null) {
+ oneTb.setText(Html.fromHtml(trackable.name).toString());
+ } else {
+ oneTb.setText("some trackable");
+ }
+ oneTb.setClickable(true);
+ oneTb.setOnClickListener(new buttonListener(trackable.guid, trackable.geocode, trackable.name));
+ addList.addView(oneTbPre);
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ Log.e(cgSettings.tag, "cgeotrackables.loadInventoryHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.trackables);
+ base.setTitle(activity, "Trackables");
+
+ // google analytics
+ base.sendAnal(activity, "/trackable/list");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ }
+
+ if (geocode == null) {
+ warning.showToast("Sorry, c:geo forgot for what cache you want to load trackables.");
+ finish();
+ return;
+ }
+
+ waitDialog = ProgressDialog.show(this, null, "loading cache inventory...", true);
+ waitDialog.setCancelable(true);
+
+ (new loadInventory()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ private class loadInventory extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ trackables = app.loadInventory(geocode);
+
+ loadInventoryHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeotrackables.loadInventory.run: " + e.toString());
+ }
+ }
+ }
+
+ private class buttonListener implements View.OnClickListener {
+
+ private String guid = null;
+ private String geocode = null;
+ private String name = null;
+
+ public buttonListener(String guidIn, String geocodeIn, String nameIn) {
+ guid = guidIn;
+ geocode = geocodeIn;
+ name = nameIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent trackableIntent = new Intent(activity, cgeotrackable.class);
+ trackableIntent.putExtra("guid", guid);
+ trackableIntent.putExtra("geocode", geocode);
+ trackableIntent.putExtra("name", name);
+ activity.startActivity(trackableIntent);
+
+ finish();
+ return;
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-trackable-list",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeovisit.java b/src/cgeo/geocaching/cgeovisit.java
new file mode 100644
index 0000000..d99b581
--- /dev/null
+++ b/src/cgeo/geocaching/cgeovisit.java
@@ -0,0 +1,912 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+
+public class cgeovisit extends cgLogForm {
+ private cgeoapplication app = null;
+ private Activity activity = null;
+ private Resources res = null;
+ private LayoutInflater inflater = null;
+ private cgBase base = null;
+ private cgSettings settings = null;
+ private cgWarning warning = null;
+ private cgCache cache = null;
+ private ArrayList<Integer> types = new ArrayList<Integer>();
+ private ProgressDialog waitDialog = null;
+ private String cacheid = null;
+ private String geocode = null;
+ private String text = null;
+ private boolean alreadyFound = false;
+ private String viewstate = null;
+ private String viewstate1 = null;
+ private Boolean gettingViewstate = true;
+ private ArrayList<cgTrackableLog> trackables = null;
+ private Calendar date = Calendar.getInstance();
+ private int typeSelected = 1;
+ private int attempts = 0;
+ private boolean progressBar = false;
+ private Button post = null;
+ private Button save = null;
+ private Button clear = null;
+ private CheckBox tweetCheck = null;
+ private LinearLayout tweetBox = null;
+ private int rating = 0;
+ private boolean tbChanged = false;
+ // constants
+ private final static int LOG_SIGNATURE = 0x1;
+ private final static int LOG_TIME = 0x2;
+ private final static int LOG_DATE = 0x4;
+ private final static int LOG_DATE_TIME = 0x6;
+ private final static int LOG_SIGNATURE_DATE_TIME = 0x7;
+ // handlers
+ private Handler showProgressHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (progressBar == true) {
+ base.showProgress(activity, true);
+ }
+ }
+ };
+ private Handler loadDataHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (types.contains(typeSelected) == false) {
+ typeSelected = types.get(0);
+ setType(typeSelected);
+
+ warning.showToast(res.getString(R.string.info_log_type_changed));
+ }
+
+ if ((viewstate == null || viewstate.length() == 0) && attempts < 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data_again));
+
+ loadData thread;
+ thread = new loadData(cacheid);
+ thread.start();
+
+ return;
+ } else if ((viewstate == null || viewstate.length() == 0) && attempts >= 2) {
+ warning.showToast(res.getString(R.string.err_log_load_data));
+ base.showProgress(activity, false);
+
+ return;
+ }
+
+ gettingViewstate = false; // we're done, user can post log
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ post.setEnabled(true);
+ post.setOnClickListener(new postListener());
+
+ // add trackables
+ if (trackables != null && trackables.isEmpty() == false) {
+ if (inflater == null) {
+ inflater = activity.getLayoutInflater();
+ }
+
+ final LinearLayout inventoryView = (LinearLayout) findViewById(R.id.inventory);
+ inventoryView.removeAllViews();
+
+ for (cgTrackableLog tb : trackables) {
+ LinearLayout inventoryItem = (LinearLayout) inflater.inflate(R.layout.visit_trackable, null);
+
+ ((TextView) inventoryItem.findViewById(R.id.trackcode)).setText(tb.trackCode);
+ ((TextView) inventoryItem.findViewById(R.id.name)).setText(tb.name);
+ ((TextView) inventoryItem.findViewById(R.id.action)).setText(cgBase.logTypesTrackable.get(0));
+
+ inventoryItem.setId(tb.id);
+ final String tbCode = tb.trackCode;
+ inventoryItem.setClickable(true);
+ registerForContextMenu(inventoryItem);
+ inventoryItem.findViewById(R.id.info).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ final Intent trackablesIntent = new Intent(activity, cgeotrackable.class);
+ trackablesIntent.putExtra("geocode", tbCode);
+ activity.startActivity(trackablesIntent);
+ }
+ });
+ inventoryItem.findViewById(R.id.action).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ inventoryView.addView(inventoryItem);
+ }
+
+ if (inventoryView.getChildCount() > 0) {
+ ((LinearLayout) findViewById(R.id.inventory_box)).setVisibility(View.VISIBLE);
+ }
+ if (inventoryView.getChildCount() > 1 && inventoryView.getChildCount() <= 20) {
+ final LinearLayout inventoryChangeAllView = (LinearLayout) findViewById(R.id.inventory_changeall);
+
+ Button changeButton = (Button) inventoryChangeAllView.findViewById(R.id.changebutton);
+ registerForContextMenu(changeButton);
+ changeButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ ((LinearLayout) findViewById(R.id.inventory_changeall)).setVisibility(View.VISIBLE);
+ }
+ }
+
+ base.showProgress(activity, false);
+ }
+ };
+
+ private Handler postLogHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 1) {
+ warning.showToast(res.getString(R.string.info_log_posted));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } else if (msg.what == 2) {
+ warning.showToast(res.getString(R.string.info_log_saved));
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+
+ finish();
+ return;
+ } else if (msg.what >= 1000) {
+ if (msg.what == 1001) {
+ warning.showToast(res.getString(R.string.warn_log_text_fill));
+ } else if (msg.what == 1002) {
+ warning.showToast(res.getString(R.string.err_log_failed_server));
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ } else {
+ if (cgBase.errorRetrieve.get(msg.what) != null) {
+ warning.showToast(res.getString(R.string.err_log_post_failed_because) + " " + cgBase.errorRetrieve.get(msg.what) + ".");
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.visit);
+ base.setTitle(activity, res.getString(R.string.log_new_log));
+
+ // google analytics
+ base.sendAnal(activity, "/visit");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ cacheid = extras.getString("id");
+ geocode = extras.getString("geocode");
+ text = extras.getString("text");
+ alreadyFound = extras.getBoolean("found");
+ }
+
+ if ((cacheid == null || cacheid.length() == 0) && geocode != null && geocode.length() > 0) {
+ cacheid = app.getCacheid(geocode);
+ }
+ if ((geocode == null || geocode.length() == 0) && cacheid != null && cacheid.length() > 0) {
+ geocode = app.getGeocode(cacheid);
+ }
+
+ cache = app.getCacheByGeocode(geocode);
+
+ if (cache.name != null && cache.name.length() > 0) {
+ base.setTitle(activity, res.getString(R.string.log_new_log) + " " + cache.name);
+ } else {
+ base.setTitle(activity, res.getString(R.string.log_new_log) + " " + cache.geocode.toUpperCase());
+ }
+
+ app.setAction(geocode);
+
+ if (cache == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot_visit));
+
+ finish();
+ return;
+ }
+
+ init();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+
+ init();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ SubMenu subMenu = null;
+
+ subMenu = menu.addSubMenu(0, 0, 0, res.getString(R.string.log_add)).setIcon(android.R.drawable.ic_menu_add);
+ subMenu.add(0, LOG_DATE_TIME, 0, res.getString(R.string.log_date_time));
+ subMenu.add(0, LOG_DATE, 0, res.getString(R.string.log_date));
+ subMenu.add(0, LOG_TIME, 0, res.getString(R.string.log_time));
+ subMenu.add(0, LOG_SIGNATURE, 0, res.getString(R.string.init_signature));
+ subMenu.add(0, LOG_SIGNATURE_DATE_TIME, 0, res.getString(R.string.log_date_time) + " & " + res.getString(R.string.init_signature));
+
+ subMenu = menu.addSubMenu(0, 9, 0, res.getString(R.string.log_rating)).setIcon(android.R.drawable.ic_menu_sort_by_size);
+ subMenu.add(0, 10, 0, res.getString(R.string.log_no_rating));
+ subMenu.add(0, 15, 0, res.getString(R.string.log_stars_5));
+ subMenu.add(0, 14, 0, res.getString(R.string.log_stars_4));
+ subMenu.add(0, 13, 0, res.getString(R.string.log_stars_3));
+ subMenu.add(0, 12, 0, res.getString(R.string.log_stars_2));
+ subMenu.add(0, 11, 0, res.getString(R.string.log_stars_1));
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ if (settings.getSignature() == null) {
+ menu.findItem(LOG_SIGNATURE).setVisible(false);
+ menu.findItem(LOG_SIGNATURE_DATE_TIME).setVisible(false);
+ } else {
+ menu.findItem(LOG_SIGNATURE).setVisible(true);
+ menu.findItem(LOG_SIGNATURE_DATE_TIME).setVisible(true);
+ }
+
+ if (settings.isGCvoteLogin() && typeSelected == cgBase.LOG_FOUND_IT && cache.guid != null && cache.guid.length() > 0) {
+ menu.findItem(9).setVisible(true);
+ } else {
+ menu.findItem(9).setVisible(false);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+
+ if ((id >= LOG_SIGNATURE && id <= LOG_SIGNATURE_DATE_TIME)) {
+ addSignature(id);
+
+ return true;
+ } else if (id >= 10 && id <= 15) {
+ rating = id - 10;
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ if (rating == 0) {
+ post.setText(res.getString(R.string.log_post_no_rate));
+ } else {
+ post.setText(res.getString(R.string.log_post_rate) + " " + rating + "*");
+ }
+ }
+
+ return false;
+ }
+
+ public void addSignature(int id) {
+ EditText text = null;
+ String textContent = null;
+ String dateString = null;
+ String timeString = null;
+ StringBuilder addText = new StringBuilder();
+
+ text = (EditText) findViewById(R.id.log);
+ textContent = text.getText().toString();
+ dateString = cgBase.dateOut.format(new Date());
+ timeString = cgBase.timeOut.format(new Date());
+
+ if ((id & LOG_DATE) == LOG_DATE) {
+ addText.append(dateString);
+ if ((id & LOG_TIME) == LOG_TIME) {
+ addText.append(" | ");
+ }
+ }
+
+ if ((id & LOG_TIME) == LOG_TIME) {
+ addText.append(timeString);
+ }
+
+ if ((id & LOG_SIGNATURE) == LOG_SIGNATURE && settings.getSignature() != null) {
+ String findCount = "";
+ if (addText.length() > 0) {
+ addText.append("\n");
+ }
+
+ if (settings.getSignature().contains("[NUMBER]") == true) {
+ final HashMap<String, String> params = new HashMap<String, String>();
+ final String page = base.request(false, "www.geocaching.com", "/my/", "GET", params, false, false, false).getData();
+ int current = base.parseFindCount(page);
+
+ if (current >= 0) {
+ findCount = "" + (current + 1);
+ }
+ }
+
+ String signature = settings.getSignature()
+ .replaceAll("\\[DATE\\]", dateString)
+ .replaceAll("\\[TIME\\]", timeString)
+ .replaceAll("\\[USER\\]", settings.getUsername())
+ .replaceAll("\\[NUMBER\\]", findCount);
+
+ addText.append(signature);
+ }
+
+ final String addTextDone;
+ if (textContent.length() > 0 && addText.length() > 0 ) {
+ addTextDone = textContent + "\n" + addText.toString();
+ } else {
+ addTextDone = textContent + addText.toString();
+ }
+
+ text.setText(addTextDone, TextView.BufferType.NORMAL);
+ text.setSelection(text.getText().toString().length());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info) {
+ super.onCreateContextMenu(menu, view, info);
+ final int viewId = view.getId();
+
+ if (viewId == R.id.type) {
+ for (final int typeOne : types) {
+ menu.add(viewId, typeOne, 0, cgBase.logTypes2.get(typeOne));
+ Log.w(cgSettings.tag, "Addig " + typeOne + " " + cgBase.logTypes2.get(typeOne));
+ }
+ } else if (viewId == R.id.changebutton) {
+ final int textId = ((TextView) findViewById(viewId)).getId();
+
+ menu.setHeaderTitle(res.getString(R.string.log_tb_changeall));
+ for (final int logTbAction : cgBase.logTypesTrackable.keySet()) {
+ menu.add(textId, logTbAction, 0, cgBase.logTypesTrackable.get(logTbAction));
+ }
+ } else {
+ final int realViewId = ((LinearLayout) findViewById(viewId)).getId();
+
+ for (final cgTrackableLog tb : trackables) {
+ if (tb.id == realViewId) {
+ menu.setHeaderTitle(tb.name);
+ }
+ }
+ for (final int logTbAction : cgBase.logTypesTrackable.keySet()) {
+ menu.add(realViewId, logTbAction, 0, cgBase.logTypesTrackable.get(logTbAction));
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ final int group = item.getGroupId();
+ final int id = item.getItemId();
+
+ if (group == R.id.type) {
+ setType(id);
+
+ return true;
+ } else if (group == R.id.changebutton) {
+ try {
+ final String logTbAction = cgBase.logTypesTrackable.get(id);
+ if (logTbAction != null) {
+ final LinearLayout inventView = (LinearLayout) findViewById(R.id.inventory);
+ for (int count = 0; count < inventView.getChildCount(); count++) {
+ final LinearLayout tbView = (LinearLayout) inventView.getChildAt(count);
+ if (tbView == null) {
+ return false;
+ }
+
+ final TextView tbText = (TextView) tbView.findViewById(R.id.action);
+ if (tbText == null) {
+ return false;
+ }
+ tbText.setText(logTbAction);
+ }
+ for (cgTrackableLog tb : trackables) {
+ tb.action = id;
+ }
+ tbChanged = true;
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.onContextItemSelected: " + e.toString());
+ }
+ } else {
+ try {
+ final String logTbAction = cgBase.logTypesTrackable.get(id);
+ if (logTbAction != null) {
+ final LinearLayout tbView = (LinearLayout) findViewById(group);
+ if (tbView == null) {
+ return false;
+ }
+
+ final TextView tbText = (TextView) tbView.findViewById(R.id.action);
+ if (tbText == null) {
+ return false;
+ }
+
+ for (cgTrackableLog tb : trackables) {
+ if (tb.id == group) {
+ tbChanged = true;
+
+ tb.action = id;
+ tbText.setText(logTbAction);
+
+ Log.i(cgSettings.tag, "Trackable " + tb.trackCode + " (" + tb.name + ") has new action: #" + id);
+ }
+ }
+
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.onContextItemSelected: " + e.toString());
+ }
+ }
+
+ return false;
+ }
+
+ public void init() {
+ if (geocode != null) {
+ app.setAction(geocode);
+ }
+
+ types.clear();
+
+ if (cache.type.equals("event") || cache.type.equals("mega") || cache.type.equals("cito") || cache.type.equals("lostfound")) {
+ types.add(cgBase.LOG_WILL_ATTEND);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_ATTENDED);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ } else if (cache.type.equals("earth")) {
+ types.add(cgBase.LOG_FOUND_IT);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ } else if (cache.type.equals("webcam")) {
+ types.add(cgBase.LOG_WEBCAM_PHOTO_TAKEN);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ } else {
+ types.add(cgBase.LOG_FOUND_IT);
+ types.add(cgBase.LOG_DIDNT_FIND_IT);
+ types.add(cgBase.LOG_NOTE);
+ types.add(cgBase.LOG_NEEDS_ARCHIVE);
+ types.add(cgBase.LOG_NEEDS_MAINTENANCE);
+ }
+ if (cache.owner.equalsIgnoreCase(settings.getUsername()) == true) {
+ types.add(cgBase.LOG_OWNER_MAINTENANCE);
+ types.add(cgBase.LOG_TEMP_DISABLE_LISTING);
+ types.add(cgBase.LOG_ENABLE_LISTING);
+ types.add(cgBase.LOG_ARCHIVE);
+ types.remove(new Integer(cgBase.LOG_UPDATE_COORDINATES));
+ if (cache.type.equals("event") || cache.type.equals("mega") || cache.type.equals("cito") || cache.type.equals("lostfound")) {
+ types.add(cgBase.LOG_ANNOUNCEMENT);
+ }
+ }
+
+ final cgLog log = app.loadLogOffline(geocode);
+ if (log != null) {
+ typeSelected = log.type;
+ date.setTime(new Date(log.date));
+ text = log.log;
+ if (typeSelected == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ post.setText(res.getString(R.string.log_post_no_rate));
+ }
+ } else if (settings.getSignature() != null && settings.getSignature().length() > 0) {
+ addSignature(LOG_SIGNATURE);
+ }
+
+ if (types.contains(typeSelected) == false) {
+ if (alreadyFound == true) {
+ typeSelected = cgBase.LOG_NOTE;
+ } else {
+ typeSelected = types.get(0);
+ }
+ setType(typeSelected);
+ }
+
+ Button typeButton = (Button) findViewById(R.id.type);
+ registerForContextMenu(typeButton);
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+ typeButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View view) {
+ openContextMenu(view);
+ }
+ });
+
+ Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeovisitDateListener());
+
+ EditText logView = (EditText) findViewById(R.id.log);
+ if (logView.getText().length() == 0 && text != null && text.length() > 0) {
+ logView.setText(text);
+ }
+
+
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+ if (tweetCheck == null) {
+ tweetCheck = (CheckBox) findViewById(R.id.tweet);
+ }
+ tweetCheck.setChecked(true);
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+ if (viewstate == null || viewstate.length() == 0) {
+ post.setEnabled(false);
+ post.setOnTouchListener(null);
+ post.setOnClickListener(null);
+
+ loadData thread;
+ thread = new loadData(cacheid);
+ thread.start();
+ } else {
+ post.setEnabled(true);
+ post.setOnClickListener(new postListener());
+ }
+
+ if (save == null) {
+ save = (Button) findViewById(R.id.save);
+ }
+ save.setOnClickListener(new saveListener());
+
+ if (clear == null) {
+ clear = (Button) findViewById(R.id.clear);
+ }
+ clear.setOnClickListener(new clearListener());
+ }
+
+ public void setDate(Calendar dateIn) {
+ date = dateIn;
+
+ final Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ }
+
+ public void setType(int type) {
+ final Button typeButton = (Button) findViewById(R.id.type);
+
+ if (cgBase.logTypes2.get(type) != null) {
+ typeSelected = type;
+ }
+ if (cgBase.logTypes2.get(typeSelected) == null) {
+ typeSelected = 1;
+ }
+ typeButton.setText(cgBase.logTypes2.get(typeSelected));
+
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+
+ if (type == 2 && tbChanged == false) {
+ // TODO: change action
+ } else if (type != 2 && tbChanged == false) {
+ // TODO: change action
+ }
+
+ if (type == cgBase.LOG_FOUND_IT && settings.twitter == 1) {
+ tweetBox.setVisibility(View.VISIBLE);
+ } else {
+ tweetBox.setVisibility(View.GONE);
+ }
+
+ if (post == null) {
+ post = (Button) findViewById(R.id.post);
+ }
+
+ if (type == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ if (rating == 0) {
+ post.setText(res.getString(R.string.log_post_no_rate));
+ } else {
+ post.setText(res.getString(R.string.log_post_rate) + " " + rating + "*");
+ }
+ } else {
+ post.setText(res.getString(R.string.log_post));
+ }
+ }
+
+ private class cgeovisitDateListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ Dialog dateDialog = new cgeodate(activity, (cgeovisit) activity, date);
+ dateDialog.setCancelable(true);
+ dateDialog.show();
+ }
+ }
+
+ private class postListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (gettingViewstate == false) {
+ waitDialog = ProgressDialog.show(activity, null, res.getString(R.string.log_saving), true);
+ waitDialog.setCancelable(true);
+
+ String log = ((EditText) findViewById(R.id.log)).getText().toString();
+ Thread thread = new postLog(postLogHandler, log);
+ thread.start();
+ } else {
+ warning.showToast(res.getString(R.string.err_log_load_data_still));
+ }
+ }
+ }
+
+ private class saveListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ String log = ((EditText) findViewById(R.id.log)).getText().toString();
+ final boolean status = app.saveLogOffline(geocode, date.getTime(), typeSelected, log);
+ if (save == null) {
+ save = (Button) findViewById(R.id.save);
+ }
+ save.setOnClickListener(new saveListener());
+
+ if (status == true) {
+ warning.showToast(res.getString(R.string.info_log_saved));
+ app.saveVisitDate(geocode);
+ } else {
+ warning.showToast(res.getString(R.string.err_log_post_failed));
+ }
+ }
+ }
+
+ private class clearListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ app.clearLogOffline(geocode);
+
+ if (alreadyFound == true) {
+ typeSelected = cgBase.LOG_NOTE;
+ } else {
+ typeSelected = types.get(0);
+ }
+ date.setTime(new Date());
+ text = null;
+
+ setType(typeSelected);
+
+ Button dateButton = (Button) findViewById(R.id.date);
+ dateButton.setText(cgBase.dateOutShort.format(date.getTime()));
+ dateButton.setOnClickListener(new cgeovisitDateListener());
+
+ EditText logView = (EditText) findViewById(R.id.log);
+ if (text != null && text.length() > 0) {
+ logView.setText(text);
+ } else {
+ logView.setText("");
+ }
+
+ if (clear == null) {
+ clear = (Button) findViewById(R.id.clear);
+ }
+ clear.setOnClickListener(new clearListener());
+
+ warning.showToast(res.getString(R.string.info_log_cleared));
+ }
+ }
+
+ private class loadData extends Thread {
+
+ private String cacheid = null;
+
+ public loadData(String cacheidIn) {
+ cacheid = cacheidIn;
+
+ if (cacheid == null) {
+ warning.showToast(res.getString(R.string.err_detail_cache_forgot_visit));
+
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public void run() {
+ final HashMap<String, String> params = new HashMap<String, String>();
+
+ showProgressHandler.sendEmptyMessage(0);
+ gettingViewstate = true;
+ attempts++;
+
+ try {
+ if (cacheid != null && cacheid.length() > 0) {
+ params.put("ID", cacheid);
+ } else {
+ loadDataHandler.sendEmptyMessage(0);
+ return;
+ }
+
+ final String page = base.request(false, "www.geocaching.com", "/seek/log.aspx", "GET", params, false, false, false).getData();
+
+ viewstate = base.findViewstate(page, 0);
+ viewstate1 = base.findViewstate(page, 1);
+ trackables = base.parseTrackableLog(page);
+
+ final ArrayList<Integer> typesPre = base.parseTypes(page);
+ if (typesPre.size() > 0) {
+ types.clear();
+ types.addAll(typesPre);
+ types.remove(new Integer(cgBase.LOG_UPDATE_COORDINATES));
+ }
+ typesPre.clear();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.loadData.run: " + e.toString());
+ }
+
+ loadDataHandler.sendEmptyMessage(0);
+ }
+ }
+
+ private class postLog extends Thread {
+
+ Handler handler = null;
+ String log = null;
+
+ public postLog(Handler handlerIn, String logIn) {
+ handler = handlerIn;
+ log = logIn;
+ }
+
+ @Override
+ public void run() {
+ int ret = -1;
+
+ ret = postLogFn(log);
+
+ handler.sendEmptyMessage(ret);
+ }
+ }
+
+ public int postLogFn(String log) {
+ int status = -1;
+
+ try {
+ if (tweetBox == null) {
+ tweetBox = (LinearLayout) findViewById(R.id.tweet_box);
+ }
+ if (tweetCheck == null) {
+ tweetCheck = (CheckBox) findViewById(R.id.tweet);
+ }
+
+ status = base.postLog(app, geocode, cacheid, viewstate, viewstate1, typeSelected, date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log, trackables);
+
+ if (status == 1) {
+ cgLog logNow = new cgLog();
+ logNow.author = settings.getUsername();
+ logNow.date = date.getTimeInMillis();
+ logNow.type = typeSelected;
+ logNow.log = log;
+
+ cache.logs.add(0, logNow);
+ app.addLog(geocode, logNow);
+
+ if (typeSelected == cgBase.LOG_FOUND_IT) {
+ app.markFound(geocode);
+ if (cache != null) {
+ cache.found = true;
+ }
+ }
+
+ if (cache != null) {
+ app.putCacheInCache(cache);
+ } else {
+ app.removeCacheFromCache(geocode);
+ }
+ }
+
+ if (status == 1) {
+ app.clearLogOffline(geocode);
+ }
+
+ if (
+ status == 1 && typeSelected == cgBase.LOG_FOUND_IT && settings.twitter == 1
+ && settings.tokenPublic != null && settings.tokenPublic.length() > 0 && settings.tokenSecret != null
+ && settings.tokenSecret.length() > 0 && tweetCheck.isChecked() == true && tweetBox.getVisibility() == View.VISIBLE
+ ) {
+ base.postTweetCache(app, settings, geocode);
+ }
+
+ if (status == 1 && typeSelected == cgBase.LOG_FOUND_IT && settings.isGCvoteLogin() == true) {
+ base.setRating(cache.guid, rating);
+ }
+
+ return status;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeovisit.postLogFn: " + e.toString());
+ }
+
+ return 1000;
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-log",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeowaypoint.java b/src/cgeo/geocaching/cgeowaypoint.java
new file mode 100644
index 0000000..5121a38
--- /dev/null
+++ b/src/cgeo/geocaching/cgeowaypoint.java
@@ -0,0 +1,465 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.util.Log;
+import android.text.Html;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.widget.Button;
+
+import com.google.android.apps.analytics.GoogleAnalyticsTracker;
+import java.util.ArrayList;
+
+public class cgeowaypoint extends Activity {
+
+ private static final int MENU_ID_EXTERN = 23;
+ private static final int MENU_ID_RMAPS = 21;
+ private static final int MENU_ID_LOCUS = 20;
+ private static final int MENU_ID_NAVIGATION = 0;
+ private static final int MENU_ID_CACHES_AROUND = 5;
+ private static final int MENU_ID_TURNBYTURN = 4;
+ private static final int MENU_ID_MAP = 1;
+ private static final int MENU_ID_RADAR = 3;
+ private static final int MENU_ID_COMPASS = 2;
+ private GoogleAnalyticsTracker tracker = null;
+ private cgWaypoint waypoint = null;
+ private String geocode = null;
+ private int id = -1;
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private Activity activity = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private ProgressDialog waitDialog = null;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private Handler loadWaypointHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (waypoint == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+
+ warning.showToast(res.getString(R.string.err_waypoint_load_failed));
+
+ finish();
+ return;
+ } else {
+ final TextView identification = (TextView) findViewById(R.id.identification);
+ final TextView coords = (TextView) findViewById(R.id.coordinates);
+ final TextView note = (TextView) findViewById(R.id.note);
+ final ImageView compass = (ImageView) findViewById(R.id.compass);
+ final View separator = (View) findViewById(R.id.separator);
+
+ if (waypoint.name != null && waypoint.name.length() > 0) {
+ base.setTitle(activity, Html.fromHtml(waypoint.name.trim()).toString());
+ } else {
+ base.setTitle(activity, res.getString(R.string.waypoint_title));
+ }
+
+ if (waypoint.prefix.equalsIgnoreCase("OWN") == false) {
+ identification.setText(waypoint.prefix.trim() + "/" + waypoint.lookup.trim());
+ } else {
+ identification.setText(res.getString(R.string.waypoint_custom));
+ }
+
+ if (waypoint.latitude != null && waypoint.longitude != null) {
+ coords.setText(Html.fromHtml(base.formatCoordinate(waypoint.latitude, "lat", true) + " | " + base.formatCoordinate(waypoint.longitude, "lon", true)), TextView.BufferType.SPANNABLE);
+ compass.setVisibility(View.VISIBLE);
+ separator.setVisibility(View.VISIBLE);
+ } else {
+ coords.setText(res.getString(R.string.waypoint_unknown_coordinates));
+ compass.setVisibility(View.GONE);
+ separator.setVisibility(View.GONE);
+ }
+
+ if (waypoint.note != null && waypoint.note.length() > 0) {
+ note.setText(Html.fromHtml(waypoint.note.trim()), TextView.BufferType.SPANNABLE);
+ }
+
+ Button buttonEdit = (Button) findViewById(R.id.edit);
+ buttonEdit.setOnClickListener(new editWaypointListener(waypoint.id));
+
+ Button buttonDelete = (Button) findViewById(R.id.delete);
+ if (waypoint.type != null && waypoint.type.equalsIgnoreCase("own") == true) {
+ buttonDelete.setOnClickListener(new deleteWaypointListener(waypoint.id));
+ buttonDelete.setVisibility(View.VISIBLE);
+ }
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypointHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(this, getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(this);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.waypoint);
+ base.setTitle(activity, "waypoint");
+
+ // google analytics
+ tracker = GoogleAnalyticsTracker.getInstance();
+ tracker.start(cgSettings.analytics, this);
+ tracker.dispatch();
+ base.sendAnal(activity, tracker, "/waypoint/detail");
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+
+ // try to get data from extras
+ if (extras != null) {
+ id = extras.getInt("waypoint");
+ geocode = extras.getString("geocode");
+ }
+
+ if (id <= 0) {
+ warning.showToast(res.getString(R.string.err_waypoint_unknown));
+ finish();
+ return;
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (waitDialog == null) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+ if (tracker != null) {
+ tracker.stop();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, MENU_ID_COMPASS, 0, res.getString(R.string.cache_menu_compass)).setIcon(android.R.drawable.ic_menu_compass); // compass
+
+ SubMenu subMenu = menu.addSubMenu(1, MENU_ID_NAVIGATION, 0, res.getString(R.string.cache_menu_navigate)).setIcon(android.R.drawable.ic_menu_more);
+ subMenu.add(0, MENU_ID_RADAR, 0, res.getString(R.string.cache_menu_radar)); // radar
+ subMenu.add(0, MENU_ID_MAP, 0, res.getString(R.string.cache_menu_map)); // c:geo map
+ if (base.isLocus(activity)) {
+ subMenu.add(0, MENU_ID_LOCUS, 0, res.getString(R.string.cache_menu_locus)); // ext.: locus
+ }
+ if (base.isRmaps(activity)) {
+ subMenu.add(0, MENU_ID_RMAPS, 0, res.getString(R.string.cache_menu_rmaps)); // ext.: rmaps
+ }
+ subMenu.add(0, MENU_ID_EXTERN, 0, res.getString(R.string.cache_menu_map_ext)); // ext.: other
+ subMenu.add(0, MENU_ID_TURNBYTURN, 0, res.getString(R.string.cache_menu_tbt)); // turn-by-turn
+
+ menu.add(0, MENU_ID_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ try {
+ boolean visible = waypoint != null && waypoint.latitude != null && waypoint.longitude != null;
+ menu.findItem(MENU_ID_NAVIGATION).setVisible(visible);
+ menu.findItem(MENU_ID_COMPASS).setVisible(visible);
+ menu.findItem(MENU_ID_CACHES_AROUND).setVisible(visible);
+ } catch (Exception e) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int menuItem = item.getItemId();
+
+ if (menuItem == MENU_ID_MAP) {
+ showOnMap();
+ return true;
+ } else if (menuItem == MENU_ID_COMPASS) {
+ goCompass(null);
+ return true;
+ } else if (menuItem == MENU_ID_RADAR) {
+ radarTo();
+ return true;
+ } else if (menuItem == MENU_ID_TURNBYTURN) {
+ if (geo != null) {
+ base.runNavigation(activity, res, settings, warning, tracker, waypoint.latitude, waypoint.longitude, geo.latitudeNow, geo.longitudeNow);
+ } else {
+ base.runNavigation(activity, res, settings, warning, tracker, waypoint.latitude, waypoint.longitude);
+ }
+
+ return true;
+ } else if (menuItem == MENU_ID_CACHES_AROUND) {
+ cachesAround();
+ return true;
+ } else if (menuItem == MENU_ID_LOCUS) {
+ base.runExternalMap(cgBase.mapAppLocus, activity, res, warning, tracker, waypoint); // locus
+ return true;
+ } else if (menuItem == MENU_ID_RMAPS) {
+ base.runExternalMap(cgBase.mapAppRmaps, activity, res, warning, tracker, waypoint); // rmaps
+ return true;
+ } else if (menuItem == MENU_ID_EXTERN) {
+ base.runExternalMap(cgBase.mapAppAny, activity, res, warning, tracker, waypoint); // extern
+ return true;
+ }
+
+ return false;
+ }
+
+ private void showOnMap() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent mapIntent = new Intent(activity, settings.getMapFactory().getMapClass());
+ mapIntent.putExtra("latitude", waypoint.latitude);
+ mapIntent.putExtra("longitude", waypoint.longitude);
+ mapIntent.putExtra("wpttype", waypoint.type);
+
+ activity.startActivity(mapIntent);
+ }
+
+ private void radarTo() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ try {
+ if (cgBase.isIntentAvailable(activity, "com.google.android.radar.SHOW_RADAR") == true) {
+ Intent radarIntent = new Intent("com.google.android.radar.SHOW_RADAR");
+ radarIntent.putExtra("latitude", new Float(waypoint.latitude));
+ radarIntent.putExtra("longitude", new Float(waypoint.longitude));
+ activity.startActivity(radarIntent);
+ } else {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
+ dialog.setTitle(res.getString(R.string.err_radar_title));
+ dialog.setMessage(res.getString(R.string.err_radar_message));
+ dialog.setCancelable(true);
+ dialog.setPositiveButton("yes", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ try {
+ activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:com.eclipsim.gpsstatus2")));
+ dialog.cancel();
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_market));
+ Log.e(cgSettings.tag, "cgeowaypoint.radarTo.onClick: " + e.toString());
+ }
+ }
+ });
+ dialog.setNegativeButton("no", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ }
+ } catch (Exception e) {
+ warning.showToast(res.getString(R.string.err_radar_generic));
+ Log.e(cgSettings.tag, "cgeowaypoint.radarTo: " + e.toString());
+ }
+ }
+
+ private void cachesAround() {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ cgeocaches cachesActivity = new cgeocaches();
+
+ Intent cachesIntent = new Intent(activity, cachesActivity.getClass());
+ cachesIntent.putExtra("type", "coordinate");
+ cachesIntent.putExtra("latitude", waypoint.latitude);
+ cachesIntent.putExtra("longitude", waypoint.longitude);
+ cachesIntent.putExtra("cachetype", settings.cacheType);
+
+ activity.startActivity(cachesIntent);
+
+ finish();
+ }
+
+ private class loadWaypoint extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ waypoint = app.loadWaypoint(id);
+
+ loadWaypointHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString());
+ }
+ }
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ // nothing
+ }
+ }
+
+ private class editWaypointListener implements View.OnClickListener {
+
+ private int id = -1;
+
+ public editWaypointListener(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ Intent editIntent = new Intent(activity, cgeowaypointadd.class);
+ editIntent.putExtra("waypoint", id);
+ activity.startActivity(editIntent);
+ }
+ }
+
+ private class deleteWaypointListener implements View.OnClickListener {
+
+ private Integer id = null;
+
+ public deleteWaypointListener(int idIn) {
+ id = idIn;
+ }
+
+ public void onClick(View arg0) {
+ if (app.deleteWaypoint(id) == false) {
+ warning.showToast(res.getString(R.string.err_waypoint_delete_failed));
+ } else {
+ app.removeCacheFromCache(geocode);
+
+ finish();
+ return;
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-details",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ public void goCompass(View view) {
+ if (waypoint == null || waypoint.latitude == null || waypoint.longitude == null) {
+ warning.showToast(res.getString(R.string.err_location_unknown));
+ }
+
+ Intent navigateIntent = new Intent(activity, cgeonavigate.class);
+ navigateIntent.putExtra("latitude", waypoint.latitude);
+ navigateIntent.putExtra("longitude", waypoint.longitude);
+ navigateIntent.putExtra("geocode", waypoint.prefix.trim() + "/" + waypoint.lookup.trim());
+ navigateIntent.putExtra("name", waypoint.name);
+
+ if (cgeonavigate.coordinates != null) {
+ cgeonavigate.coordinates.clear();
+ }
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(new cgCoord(waypoint));
+ activity.startActivity(navigateIntent);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/cgeowaypointadd.java b/src/cgeo/geocaching/cgeowaypointadd.java
new file mode 100644
index 0000000..ec58257
--- /dev/null
+++ b/src/cgeo/geocaching/cgeowaypointadd.java
@@ -0,0 +1,434 @@
+package cgeo.geocaching;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Html;
+import android.util.Log;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.EditText;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class cgeowaypointadd extends Activity {
+
+ private cgeoapplication app = null;
+ private Resources res = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private Activity activity = null;
+ private String geocode = null;
+ private int id = -1;
+ private cgGeo geo = null;
+ private cgUpdateLoc geoUpdate = new update();
+ private EditText latEdit = null;
+ private EditText lonEdit = null;
+ private ProgressDialog waitDialog = null;
+ private cgWaypoint waypoint = null;
+ private String type = "own";
+ private String prefix = "OWN";
+ private String lookup = "---";
+ /**
+ * number of waypoints that the corresponding cache has until now
+ */
+ private int wpCount = 0;
+ private Handler loadWaypointHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (waypoint == null) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+
+ id = -1;
+ } else {
+ geocode = waypoint.geocode;
+ type = waypoint.type;
+ prefix = waypoint.prefix;
+ lookup = waypoint.lookup;
+
+ app.setAction(geocode);
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(waypoint.latitude, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(waypoint.longitude, "lon", true));
+ ((EditText) findViewById(R.id.name)).setText(Html.fromHtml(waypoint.name.trim()).toString());
+ ((EditText) findViewById(R.id.note)).setText(Html.fromHtml(waypoint.note.trim()).toString());
+
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ }
+ } catch (Exception e) {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog = null;
+ }
+ Log.e(cgSettings.tag, "cgeowaypointadd.loadWaypointHandler: " + e.toString());
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // init
+ activity = this;
+ res = this.getResources();
+ app = (cgeoapplication) this.getApplication();
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+
+ // set layout
+ if (settings.skin == 1) {
+ setTheme(R.style.light);
+ } else {
+ setTheme(R.style.dark);
+ }
+ setContentView(R.layout.waypoint_new);
+ base.setTitle(activity, "waypoint");
+
+ // google analytics
+ base.sendAnal(activity, "/waypoint/new");
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ // get parameters
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ geocode = extras.getString("geocode");
+ wpCount = extras.getInt("count", 0);
+ id = extras.getInt("waypoint");
+ }
+
+ if ((geocode == null || geocode.length() == 0) && id <= 0) {
+ warning.showToast(res.getString(R.string.err_waypoint_cache_unknown));
+
+ finish();
+ return;
+ }
+
+ if (id <= 0) {
+ base.setTitle(activity, res.getString(R.string.waypoint_add_title));
+ } else {
+ base.setTitle(activity, res.getString(R.string.waypoint_edit_title));
+ }
+
+ if (geocode != null) {
+ app.setAction(geocode);
+ }
+
+ Button buttonCurrent = (Button) findViewById(R.id.current);
+ buttonCurrent.setOnClickListener(new currentListener());
+
+ Button addWaypoint = (Button) findViewById(R.id.add_waypoint);
+ addWaypoint.setOnClickListener(new coordsListener());
+
+ ArrayList<String> wayPointNames = new ArrayList<String>(cgBase.waypointTypes.values());
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.name);
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, wayPointNames);
+ textView.setAdapter(adapter);
+
+
+ if (id > 0) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+
+ if (id > 0) {
+ if (waitDialog == null) {
+ waitDialog = ProgressDialog.show(this, null, res.getString(R.string.waypoint_loading), true);
+ waitDialog.setCancelable(true);
+
+ (new loadWaypoint()).start();
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public void onStop() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ super.onPause();
+ }
+
+ private class update extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (latEdit == null) {
+ latEdit = (EditText) findViewById(R.id.latitude);
+ }
+ if (lonEdit == null) {
+ lonEdit = (EditText) findViewById(R.id.longitude);
+ }
+
+ latEdit.setHint(base.formatCoordinate(geo.latitudeNow, "lat", false));
+ lonEdit.setHint(base.formatCoordinate(geo.longitudeNow, "lon", false));
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ private class loadWaypoint extends Thread {
+
+ @Override
+ public void run() {
+ try {
+ waypoint = app.loadWaypoint(id);
+
+ loadWaypointHandler.sendMessage(new Message());
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeowaypoint.loadWaypoint.run: " + e.toString());
+ }
+ }
+ }
+
+ private class currentListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_unknown_position));
+ return;
+ }
+
+ ((EditText) findViewById(R.id.latitude)).setText(base.formatCoordinate(geo.latitudeNow, "lat", true));
+ ((EditText) findViewById(R.id.longitude)).setText(base.formatCoordinate(geo.longitudeNow, "lon", true));
+ }
+ }
+
+ private class coordsListener implements View.OnClickListener {
+
+ public void onClick(View arg0) {
+ ArrayList<Double> coords = new ArrayList<Double>();
+ Double latitude = null;
+ Double longitude = null;
+
+ final String bearingText = ((EditText) findViewById(R.id.bearing)).getText().toString();
+ final String distanceText = ((EditText) findViewById(R.id.distance)).getText().toString();
+ final String latText = ((EditText) findViewById(R.id.latitude)).getText().toString();
+ final String lonText = ((EditText) findViewById(R.id.longitude)).getText().toString();
+
+ if ((bearingText == null || bearingText.length() == 0) && (distanceText == null || distanceText.length() == 0)
+ && (latText == null || latText.length() == 0) && (lonText == null || lonText.length() == 0)) {
+ warning.helpDialog(res.getString(R.string.err_point_no_position_given_title), res.getString(R.string.err_point_no_position_given));
+ return;
+ }
+
+ if (latText != null && latText.length() > 0 && lonText != null && lonText.length() > 0) {
+ // latitude & longitude
+ HashMap<String, Object> latParsed = base.parseCoordinate(latText, "lat");
+ HashMap<String, Object> lonParsed = base.parseCoordinate(lonText, "lat");
+
+ if (latParsed == null || latParsed.get("coordinate") == null || latParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lat));
+ return;
+ }
+
+ if (lonParsed == null || lonParsed.get("coordinate") == null || lonParsed.get("string") == null) {
+ warning.showToast(res.getString(R.string.err_parse_lon));
+ return;
+ }
+
+ latitude = (Double) latParsed.get("coordinate");
+ longitude = (Double) lonParsed.get("coordinate");
+ } else {
+ if (geo == null || geo.latitudeNow == null || geo.longitudeNow == null) {
+ warning.showToast(res.getString(R.string.err_point_curr_position_unavailable));
+ return;
+ }
+
+ latitude = geo.latitudeNow;
+ longitude = geo.longitudeNow;
+ }
+
+ if (bearingText != null && bearingText.length() > 0 && distanceText != null && distanceText.length() > 0) {
+ // bearing & distance
+ Double bearing = null;
+ try {
+ bearing = new Double(bearingText);
+ } catch (Exception e) {
+ // probably not a number
+ }
+ if (bearing == null) {
+ warning.helpDialog(res.getString(R.string.err_point_bear_and_dist_title), res.getString(R.string.err_point_bear_and_dist));
+ return;
+ }
+
+ Double distance = null; // km
+
+ final Pattern patternA = Pattern.compile("^([0-9\\.\\,]+)[ ]*m$", Pattern.CASE_INSENSITIVE); // m
+ final Pattern patternB = Pattern.compile("^([0-9\\.\\,]+)[ ]*km$", Pattern.CASE_INSENSITIVE); // km
+ final Pattern patternC = Pattern.compile("^([0-9\\.\\,]+)[ ]*ft$", Pattern.CASE_INSENSITIVE); // ft - 0.3048m
+ final Pattern patternD = Pattern.compile("^([0-9\\.\\,]+)[ ]*yd$", Pattern.CASE_INSENSITIVE); // yd - 0.9144m
+ final Pattern patternE = Pattern.compile("^([0-9\\.\\,]+)[ ]*mi$", Pattern.CASE_INSENSITIVE); // mi - 1609.344m
+
+ Matcher matcherA = patternA.matcher(distanceText);
+ Matcher matcherB = patternB.matcher(distanceText);
+ Matcher matcherC = patternC.matcher(distanceText);
+ Matcher matcherD = patternD.matcher(distanceText);
+ Matcher matcherE = patternE.matcher(distanceText);
+
+ if (matcherA.find() == true && matcherA.groupCount() > 0) {
+ distance = (new Double(matcherA.group(1))) * 0.001;
+ } else if (matcherB.find() == true && matcherB.groupCount() > 0) {
+ distance = new Double(matcherB.group(1));
+ } else if (matcherC.find() == true && matcherC.groupCount() > 0) {
+ distance = (new Double(matcherC.group(1))) * 0.0003048;
+ } else if (matcherD.find() == true && matcherD.groupCount() > 0) {
+ distance = (new Double(matcherD.group(1))) * 0.0009144;
+ } else if (matcherE.find() == true && matcherE.groupCount() > 0) {
+ distance = (new Double(matcherE.group(1))) * 1.609344;
+ } else {
+ try {
+ if (settings.units == cgSettings.unitsImperial) {
+ distance = (new Double(distanceText)) * 1.609344; // considering it miles
+ } else {
+ distance = (new Double(distanceText)) * 0.001; // considering it meters
+ }
+ } catch (Exception e) {
+ // probably not a number
+ }
+ }
+
+ if (distance == null) {
+ warning.showToast(res.getString(R.string.err_parse_dist));
+ return;
+ }
+
+ Double latParsed = null;
+ Double lonParsed = null;
+
+ HashMap<String, Double> coordsDst = base.getRadialDistance(latitude, longitude, bearing, distance);
+
+ latParsed = coordsDst.get("latitude");
+ lonParsed = coordsDst.get("longitude");
+
+ if (latParsed == null || lonParsed == null) {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return;
+ }
+
+ coords.add(0, (Double) latParsed);
+ coords.add(1, (Double) lonParsed);
+ } else if (latitude != null && longitude != null) {
+ coords.add(0, latitude);
+ coords.add(1, longitude);
+ } else {
+ warning.showToast(res.getString(R.string.err_point_location_error));
+ return;
+ }
+
+ String name = ((EditText) findViewById(R.id.name)).getText().toString().trim();
+ // if no name is given, just give the waypoint its number as name
+ if (name.length() == 0) {
+ name = res.getString(R.string.waypoint) + " " + String.valueOf(wpCount + 1);
+ }
+ final String note = ((EditText) findViewById(R.id.note)).getText().toString().trim();
+
+ final cgWaypoint waypoint = new cgWaypoint();
+ waypoint.type = type;
+ waypoint.geocode = geocode;
+ waypoint.prefix = prefix;
+ waypoint.lookup = lookup;
+ waypoint.name = name;
+ waypoint.latitude = coords.get(0);
+ waypoint.longitude = coords.get(1);
+ waypoint.latitudeString = base.formatCoordinate(coords.get(0), "lat", true);
+ waypoint.longitudeString = base.formatCoordinate(coords.get(1), "lon", true);
+ waypoint.note = note;
+
+ if (app.saveOwnWaypoint(id, geocode, waypoint) == true) {
+ app.removeCacheFromCache(geocode);
+
+ finish();
+ return;
+ } else {
+ warning.showToast(res.getString(R.string.err_waypoint_add_failed));
+ }
+ }
+ }
+
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ public void goManual(View view) {
+ try {
+ if (id >= 0) {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-edit",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ } else {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-waypoint-new",
+ activity,
+ "http://cgeo.carnero.cc/manual/"
+ );
+ }
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/filter/cgFilter.java b/src/cgeo/geocaching/filter/cgFilter.java
new file mode 100644
index 0000000..20f04c9
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilter.java
@@ -0,0 +1,20 @@
+package cgeo.geocaching.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import cgeo.geocaching.cgCache;
+
+public abstract class cgFilter {
+ abstract boolean applyFilter(cgCache cache);
+
+ public void filter(List<cgCache> list){
+ List<cgCache> itemsToRemove = new ArrayList<cgCache>();
+ for(cgCache item : list){
+ if(!applyFilter(item)){
+ itemsToRemove.add(item);
+ }
+ }
+ list.removeAll(itemsToRemove);
+ }
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterBySize.java b/src/cgeo/geocaching/filter/cgFilterBySize.java
new file mode 100644
index 0000000..b32afc0
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterBySize.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterBySize extends cgFilter {
+ private String size;
+
+ public cgFilterBySize(String size){
+ this.size = size;
+ }
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.size.equals(size);
+ }
+
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterByTrackables.java b/src/cgeo/geocaching/filter/cgFilterByTrackables.java
new file mode 100644
index 0000000..44c85c1
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterByTrackables.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterByTrackables extends cgFilter {
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.hasTrackables();
+ }
+
+}
diff --git a/src/cgeo/geocaching/filter/cgFilterByType.java b/src/cgeo/geocaching/filter/cgFilterByType.java
new file mode 100644
index 0000000..8ba177b
--- /dev/null
+++ b/src/cgeo/geocaching/filter/cgFilterByType.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.filter;
+
+import cgeo.geocaching.cgCache;
+
+public class cgFilterByType extends cgFilter {
+ private String type;
+
+ public cgFilterByType(String type){
+ this.type = type;
+ }
+
+ @Override
+ boolean applyFilter(cgCache cache) {
+ return cache.type.equals(type);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java b/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java
new file mode 100644
index 0000000..68929cf
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleCacheOverlay.java
@@ -0,0 +1,101 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+/**
+ * Google specific implementation of the itemized cache overlay
+ * @author rsudev
+ *
+ */
+public class googleCacheOverlay extends ItemizedOverlay<googleCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgMapOverlay base;
+
+ public googleCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new cgMapOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public cgMapOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleCacheOverlayItem) 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
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here...
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java b/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java
new file mode 100644
index 0000000..5546077
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleCacheOverlayItem.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+public class googleCacheOverlayItem extends OverlayItem implements CacheOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public googleCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint((int)(coordinate.latitude * 1e6), (int)(coordinate.longitude * 1e6)), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleGeoPoint.java b/src/cgeo/geocaching/googlemaps/googleGeoPoint.java
new file mode 100644
index 0000000..a22e7d4
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleGeoPoint.java
@@ -0,0 +1,13 @@
+package cgeo.geocaching.googlemaps;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+
+import com.google.android.maps.GeoPoint;
+
+public class googleGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public googleGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapActivity.java b/src/cgeo/geocaching/googlemaps/googleMapActivity.java
new file mode 100644
index 0000000..a95b741
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapActivity.java
@@ -0,0 +1,101 @@
+package cgeo.geocaching.googlemaps;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import cgeo.geocaching.mapcommon.MapBase;
+import cgeo.geocaching.mapcommon.cgeomap;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+
+import com.google.android.maps.MapActivity;
+
+public class googleMapActivity extends MapActivity implements ActivityImpl {
+
+ private MapBase mapBase;
+
+ public googleMapActivity() {
+ mapBase = new cgeomap(this);
+ }
+
+ @Override
+ protected boolean isRouteDisplayed() {
+ return false;
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @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 superOnCreateOptionsMenu(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 boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapController.java b/src/cgeo/geocaching/googlemaps/googleMapController.java
new file mode 100644
index 0000000..c779b32
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapController.java
@@ -0,0 +1,37 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapController;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+
+public class googleMapController implements MapControllerImpl {
+
+ private MapController mapController;
+
+ public googleMapController(MapController mapControllerIn) {
+ mapController = mapControllerIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.animateTo((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ mapController.setZoom(mapzoom);
+ }
+
+ @Override
+ public void zoomToSpan(int latSpanE6, int lonSpanE6) {
+ mapController.zoomToSpan(latSpanE6, lonSpanE6);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapFactory.java b/src/cgeo/geocaching/googlemaps/googleMapFactory.java
new file mode 100644
index 0000000..86e75a0
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapFactory.java
@@ -0,0 +1,54 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class googleMapFactory implements MapFactory{
+
+ @Override
+ public Class getMapClass() {
+ return googleMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.map;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.googlemap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6) {
+ return new googleGeoPoint(latE6, lonE6);
+ }
+
+ @Override
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn) {
+ googleOverlay baseOvl = new googleOverlay(ovlIn);
+ return baseOvl;
+ }
+
+ @Override
+ public CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type) {
+ googleCacheOverlayItem baseItem = new googleCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context, cgUser userOne) {
+ googleUsersOverlayItem baseItem = new googleUsersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleMapProjection.java b/src/cgeo/geocaching/googlemaps/googleMapProjection.java
new file mode 100644
index 0000000..476d78d
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapProjection.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.googlemaps;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.Projection;
+
+import android.graphics.Point;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+
+public class googleMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public googleMapProjection(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/src/cgeo/geocaching/googlemaps/googleMapView.java b/src/cgeo/geocaching/googlemaps/googleMapView.java
new file mode 100644
index 0000000..b63ca2e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleMapView.java
@@ -0,0 +1,118 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+public class googleMapView extends MapView implements MapViewImpl{
+
+ public googleMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public googleMapView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public googleMapView(Context context, String apiKey) {
+ super(context, apiKey);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ try {
+ super.displayZoomControls(takeFocus);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.displayZoomControls: " + e.toString());
+ }
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new googleMapController(getController());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new googleGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay)ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new googleMapProjection(getProjection());
+ }
+
+ @Override
+ public cgMapOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ googleCacheOverlay ovl = new googleCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ googleUsersOverlay ovl = new googleUsersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel();
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+ // nothing to do for google maps...
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return true;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ //Nothing to do for google maps...
+ }
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleOverlay.java b/src/cgeo/geocaching/googlemaps/googleOverlay.java
new file mode 100644
index 0000000..3847d9f
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleOverlay.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching.googlemaps;
+
+import android.graphics.Canvas;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+import com.google.android.maps.MapView;
+import com.google.android.maps.Overlay;
+
+public class googleOverlay extends Overlay implements OverlayImpl {
+
+ private OverlayBase overlayBase;
+
+ public googleOverlay(OverlayBase overlayBaseIn) {
+ overlayBase = overlayBaseIn;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ super.draw(canvas, mapView, shadow);
+
+ overlayBase.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+}
diff --git a/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java b/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java
new file mode 100644
index 0000000..5019e6e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleUsersOverlay.java
@@ -0,0 +1,94 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapView;
+
+public class googleUsersOverlay extends ItemizedOverlay<googleUsersOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgUsersOverlay base;
+
+ public googleUsersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new cgUsersOverlay(this, contextIn);
+ }
+
+ @Override
+ public cgUsersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected googleUsersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (googleUsersOverlayItem) 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
+ public void draw(Canvas canvas, MapView mapView, boolean shadow) {
+ base.draw(canvas, (MapViewImpl) mapView, shadow);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ super.setLastFocusedIndex(i);
+ }
+
+ @Override
+ public boolean superOnTap(int index) {
+ return super.onTap(index);
+ }
+
+ @Override
+ public void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, (MapView) mapView, shadow);
+ }
+
+ @Override
+ public void superDrawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // Nothing to do here
+ }
+
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java b/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java
new file mode 100644
index 0000000..c3d404e
--- /dev/null
+++ b/src/cgeo/geocaching/googlemaps/googleUsersOverlayItem.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.googlemaps;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.OverlayItem;
+
+public class googleUsersOverlayItem extends OverlayItem implements UserOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public googleUsersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint((int)(userIn.latitude * 1e6), (int)(userIn.longitude * 1e6)), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
new file mode 100644
index 0000000..41739e2
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/ItemizedOverlayBase.java
@@ -0,0 +1,57 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayItemImpl;
+
+/**
+ * Base class for itemized overlays. Delegates calls from deriving classes to the contained
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public abstract class ItemizedOverlayBase {
+
+ private ItemizedOverlayImpl ovlImpl;
+
+ public ItemizedOverlayBase(ItemizedOverlayImpl ovlImplIn) {
+ ovlImpl = ovlImplIn;
+ }
+
+ void populate() {
+ ovlImpl.superPopulate();
+ }
+
+ public boolean onTap(int index) {
+ return ovlImpl.superOnTap(index);
+ }
+
+ Drawable boundCenter(Drawable markerIn) {
+ return ovlImpl.superBoundCenter(markerIn);
+ }
+
+ Drawable boundCenterBottom(Drawable markerIn) {
+ return ovlImpl.superBoundCenterBottom(markerIn);
+ }
+
+ void setLastFocusedItemIndex(int index){
+ ovlImpl.superSetLastFocusedItemIndex(index);
+ }
+
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ ovlImpl.superDraw(canvas, mapView, shadow);
+ }
+
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ ovlImpl.superDrawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ public abstract OverlayItemImpl createItem(int index);
+
+ public abstract int size();
+}
diff --git a/src/cgeo/geocaching/mapcommon/MapBase.java b/src/cgeo/geocaching/mapcommon/MapBase.java
new file mode 100644
index 0000000..2340998
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/MapBase.java
@@ -0,0 +1,64 @@
+package cgeo.geocaching.mapcommon;
+
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Base class for the map activity. Delegates base class calls to the
+ * provider-specific implementation.
+ * @author rsudev
+ *
+ */
+public class MapBase {
+
+ ActivityImpl mapActivity;
+
+ public MapBase(ActivityImpl activity) {
+ mapActivity = activity;
+ }
+
+ public Resources getResources() {
+ return mapActivity.getResources();
+ }
+
+ public Activity getActivity() {
+ return mapActivity.getActivity();
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ mapActivity.superOnCreate(savedInstanceState);
+ }
+
+ public void onResume() {
+ mapActivity.superOnResume();
+ }
+
+ public void onStop() {
+ mapActivity.superOnResume();
+ }
+
+ public void onPause() {
+ mapActivity.superOnResume();
+ }
+
+ public void onDestroy() {
+ mapActivity.superOnDestroy();
+ }
+
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return mapActivity.superOnCreateOptionsMenu(menu);
+ }
+
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return mapActivity.superOnPrepareOptionsMenu(menu);
+ }
+
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return mapActivity.superOnOptionsItemSelected(item);
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
new file mode 100644
index 0000000..3951c14
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapMyOverlay.java
@@ -0,0 +1,198 @@
+package cgeo.geocaching.mapcommon;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.location.Location;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+import java.util.ArrayList;
+
+public class cgMapMyOverlay implements OverlayBase {
+ private cgSettings settings = null;
+ private Location coordinates = null;
+ private GeoPointImpl location = null;
+ private Double heading = new Double(0);
+ private Paint accuracyCircle = null;
+ private Paint historyLine = null;
+ private Paint historyLineShadow = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Bitmap arrow = null;
+ private int widthArrow = 0;
+ private int heightArrow = 0;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private Location historyRecent = null;
+ private ArrayList<Location> history = new ArrayList<Location>();
+ private Point historyPointN = new Point();
+ private Point historyPointP = new Point();
+
+ public cgMapMyOverlay(cgSettings settingsIn) {
+ settings = settingsIn;
+ }
+
+ public void setCoordinates(Location coordinatesIn) {
+ coordinates = coordinatesIn;
+ location = settings.getMapFactory().getGeoPointBase((int)(coordinatesIn.getLatitude() * 1e6), (int)(coordinatesIn.getLongitude() * 1e6));
+ }
+
+ public void setHeading(Double headingIn) {
+ heading = headingIn;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ if (coordinates == null || location == null) return;
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (accuracyCircle == null) {
+ accuracyCircle = new Paint();
+ accuracyCircle.setAntiAlias(true);
+ accuracyCircle.setStrokeWidth(1.0f);
+ }
+
+ if (historyLine == null) {
+ historyLine = new Paint();
+ historyLine.setAntiAlias(true);
+ historyLine.setStrokeWidth(3.0f);
+ historyLine.setColor(0xFFFFFFFF);
+ }
+
+ if (historyLineShadow == null) {
+ historyLineShadow = new Paint();
+ historyLineShadow.setAntiAlias(true);
+ historyLineShadow.setStrokeWidth(7.0f);
+ historyLineShadow.setColor(0x66000000);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ double latitude = coordinates.getLatitude();
+ double longitude = coordinates.getLongitude();
+ float accuracy = coordinates.getAccuracy();
+
+ float[] result = new float[1];
+
+ Location.distanceBetween(latitude, longitude, latitude, longitude + 1, result);
+ float longitudeLineDistance = result[0];
+
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(latitude * 1e6), (int)((longitude - accuracy / longitudeLineDistance) * 1e6));
+ projection.toPixels(leftGeo, left);
+ projection.toPixels(location, center);
+ int radius = center.x - left.x;
+
+ accuracyCircle.setColor(0x66000000);
+ accuracyCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ accuracyCircle.setColor(0x08000000);
+ accuracyCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, accuracyCircle);
+
+ if (coordinates.getAccuracy() < 50f && ((historyRecent != null && cgBase.getDistance(historyRecent.getLatitude(), historyRecent.getLongitude(), coordinates.getLatitude(), coordinates.getLongitude()) > 0.005) || historyRecent == null)) {
+ if (historyRecent != null) history.add(historyRecent);
+ historyRecent = coordinates;
+
+ int toRemove = history.size() - 700;
+
+ if (toRemove > 0) {
+ for (int cnt = 0; cnt < toRemove; cnt ++) {
+ history.remove(cnt);
+ }
+ }
+ }
+
+ if (settings.maptrail == 1) {
+ int size = history.size();
+ if (size > 1) {
+ int alpha = 0;
+ int alphaCnt = size - 201;
+ if (alphaCnt < 1) alphaCnt = 1;
+
+ for (int cnt = 1; cnt < size; cnt ++) {
+ Location prev = history.get(cnt - 1);
+ Location now = history.get(cnt);
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ if ((alphaCnt - cnt) > 0) alpha = Math.round(255 / (alphaCnt - cnt));
+ else alpha = 255;
+
+ historyLineShadow.setAlpha(alpha);
+ historyLine.setAlpha(alpha);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (size > 0) {
+ Location prev = history.get(size - 1);
+ Location now = coordinates;
+
+ if (prev != null && now != null) {
+ projection.toPixels(mapFactory.getGeoPointBase((int)(prev.getLatitude() * 1e6), (int)(prev.getLongitude() * 1e6)), historyPointP);
+ projection.toPixels(mapFactory.getGeoPointBase((int)(now.getLatitude() * 1e6), (int)(now.getLongitude() * 1e6)), historyPointN);
+
+ historyLineShadow.setAlpha(255);
+ historyLine.setAlpha(255);
+
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLineShadow);
+ canvas.drawLine(historyPointP.x, historyPointP.y, historyPointN.x, historyPointN.y, historyLine);
+ }
+ }
+ }
+
+ if (arrow == null) {
+ arrow = BitmapFactory.decodeResource(settings.getContext().getResources(), R.drawable.my_location_chevron);
+ widthArrow = arrow.getWidth();
+ heightArrow = arrow.getHeight();
+ }
+
+ int marginLeft;
+ int marginTop;
+
+ marginLeft = center.x - (widthArrow / 2);
+ marginTop = center.y - (heightArrow / 2);
+
+ canvas.rotate(new Float(heading), center.x, center.y);
+ canvas.drawBitmap(arrow, marginLeft, marginTop, null);
+ canvas.rotate(-(new Float(heading)), center.x, center.y);
+
+ canvas.setDrawFilter(remfil);
+
+ //super.draw(canvas, mapView, shadow);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgMapOverlay.java b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
new file mode 100644
index 0000000..7433ccb
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgMapOverlay.java
@@ -0,0 +1,322 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Point;
+import android.location.Location;
+import android.text.Html;
+import android.util.Log;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.cgeonavigate;
+import cgeo.geocaching.cgeopopup;
+import cgeo.geocaching.cgeowaypoint;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+import java.util.ArrayList;
+
+import org.mapsforge.android.maps.Projection;
+
+public class cgMapOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+ private Context context = null;
+ private Boolean fromDetail = false;
+ private boolean displayCircles = false;
+ private ProgressDialog waitDialog = null;
+ private Point center = new Point();
+ private Point left = new Point();
+ private Paint blockedCircle = null;
+ private PaintFlagsDrawFilter setfil = null;
+ private PaintFlagsDrawFilter remfil = null;
+ private cgSettings settings;
+
+ public cgMapOverlay(cgSettings settingsIn, ItemizedOverlayImpl ovlImpl, Context contextIn, Boolean fromDetailIn) {
+ super(ovlImpl);
+
+ populate();
+ settings = settingsIn;
+
+ context = contextIn;
+ fromDetail = fromDetailIn;
+ }
+
+ public void updateItems(CacheOverlayItemImpl item) {
+ ArrayList<CacheOverlayItemImpl> itemsPre = new ArrayList<CacheOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<CacheOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (CacheOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenterBottom(item.getMarker(0)));
+ }
+
+// items.clear();
+
+// if (itemsPre.size() > 0) {
+ items = (ArrayList<CacheOverlayItemImpl>) itemsPre.clone();
+// }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ public boolean getCircles() {
+ return displayCircles;
+ }
+
+ public void switchCircles() {
+ displayCircles = !displayCircles;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+
+ drawInternal(canvas, mapView.getMapProjection());
+
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+
+ drawInternal(canvas, projection);
+
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ private void drawInternal(Canvas canvas, MapProjectionImpl projection) {
+
+ MapFactory mapFactory = settings.getMapFactory();
+
+ if (displayCircles) {
+ if (blockedCircle == null) {
+ blockedCircle = new Paint();
+ blockedCircle.setAntiAlias(true);
+ blockedCircle.setStrokeWidth(1.0f);
+ }
+
+ if (setfil == null) setfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
+ if (remfil == null) remfil = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
+
+ canvas.setDrawFilter(setfil);
+
+ for (CacheOverlayItemImpl item : items) {
+ final cgCoord itemCoord = item.getCoord();
+ float[] result = new float[1];
+
+ Location.distanceBetween(itemCoord.latitude, itemCoord.longitude, itemCoord.latitude, itemCoord.longitude + 1, result);
+ final float longitudeLineDistance = result[0];
+
+ GeoPointImpl itemGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)(itemCoord.longitude * 1e6));
+ GeoPointImpl leftGeo = mapFactory.getGeoPointBase((int)(itemCoord.latitude * 1e6), (int)((itemCoord.longitude - 161 / longitudeLineDistance) * 1e6));
+
+ projection.toPixels(itemGeo, center);
+ projection.toPixels(leftGeo, left);
+ int radius = center.x - left.x;
+
+ final String type = item.getType();
+ if (type == null || "multi".equals(type) || "mystery".equals(type) || "virtual".equals(type)) {
+ blockedCircle.setColor(0x66000000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ } else {
+ blockedCircle.setColor(0x66BB0000);
+ blockedCircle.setStyle(Style.STROKE);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+
+ blockedCircle.setColor(0x44BB0000);
+ blockedCircle.setStyle(Style.FILL);
+ canvas.drawCircle(center.x, center.y, radius, blockedCircle);
+ }
+ }
+
+ canvas.setDrawFilter(remfil);
+ }
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ if (waitDialog == null) {
+ waitDialog = new ProgressDialog(context);
+ waitDialog.setMessage("loading details...");
+ waitDialog.setCancelable(false);
+ }
+ waitDialog.show();
+
+ CacheOverlayItemImpl item = items.get(index);
+ cgCoord coordinate = item.getCoord();
+
+ if (coordinate.type != null && coordinate.type.equalsIgnoreCase("cache") == true && coordinate.geocode != null && coordinate.geocode.length() > 0) {
+ Intent popupIntent = new Intent(context, cgeopopup.class);
+
+ popupIntent.putExtra("fromdetail", fromDetail);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else if (coordinate.type != null && coordinate.type.equalsIgnoreCase("waypoint") == true && coordinate.id != null && coordinate.id > 0) {
+ Intent popupIntent = new Intent(context, cgeowaypoint.class);
+
+ popupIntent.putExtra("waypoint", coordinate.id);
+ popupIntent.putExtra("geocode", coordinate.geocode);
+
+ context.startActivity(popupIntent);
+ } else {
+ waitDialog.dismiss();
+ return false;
+ }
+
+ waitDialog.dismiss();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public CacheOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ public void infoDialog(int index) {
+ final CacheOverlayItemImpl item = items.get(index);
+ final cgCoord coordinate = item.getCoord();
+
+ if (coordinate == null) {
+ Log.e(cgSettings.tag, "cgMapOverlay:infoDialog: No coordinates given");
+ return;
+ }
+
+ try {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ dialog.setCancelable(true);
+
+ if (coordinate.type.equalsIgnoreCase("cache")) {
+ dialog.setTitle("cache");
+
+ String cacheType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ cacheType = cgBase.cacheTypesInv.get(coordinate.typeSpec);
+ } else {
+ cacheType = cgBase.cacheTypesInv.get("mystery");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ngeocode: " + coordinate.geocode.toUpperCase() + "\ntype: " + cacheType);
+ if (fromDetail == false) {
+ dialog.setPositiveButton("detail", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ Intent cachesIntent = new Intent(context, cgeodetail.class);
+ cachesIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(cachesIntent);
+
+ dialog.cancel();
+ }
+ });
+ } else {
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.geocode.toUpperCase());
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+ } else {
+ dialog.setTitle("waypoint");
+
+ String waypointType;
+ if (cgBase.cacheTypesInv.containsKey(coordinate.typeSpec) == true) {
+ waypointType = cgBase.waypointTypes.get(coordinate.typeSpec);
+ } else {
+ waypointType = cgBase.waypointTypes.get("waypoint");
+ }
+
+ dialog.setMessage(Html.fromHtml(item.getTitle()) + "\n\ntype: " + waypointType);
+ dialog.setPositiveButton("navigate", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ cgeonavigate navigateActivity = new cgeonavigate();
+
+ cgeonavigate.coordinates = new ArrayList<cgCoord>();
+ cgeonavigate.coordinates.add(coordinate);
+
+ Intent navigateIntent = new Intent(context, navigateActivity.getClass());
+ navigateIntent.putExtra("latitude", coordinate.latitude);
+ navigateIntent.putExtra("longitude", coordinate.longitude);
+ navigateIntent.putExtra("geocode", coordinate.name);
+
+ context.startActivity(navigateIntent);
+ dialog.cancel();
+ }
+ });
+ }
+
+ dialog.setNegativeButton("dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapOverlay.infoDialog: " + e.toString());
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgOverlayScale.java b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
new file mode 100644
index 0000000..1e4a6e6
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgOverlayScale.java
@@ -0,0 +1,140 @@
+package cgeo.geocaching.mapcommon;
+
+import android.app.Activity;
+import android.graphics.BlurMaskFilter;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Typeface;
+import android.util.DisplayMetrics;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+public class cgOverlayScale implements OverlayBase {
+ private cgSettings settings = null;
+ private Paint scale = null;
+ private Paint scaleShadow = null;
+ private BlurMaskFilter blur = null;
+ private float pixelDensity = 0l;
+ private double pixels = 0d;
+ private int bottom = 0;
+ private double distance = 0d;
+ private double distanceRound = 0d;
+ private String units = null;
+
+ public cgOverlayScale(Activity activity, cgSettings settingsIn) {
+ settings = settingsIn;
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ pixelDensity = metrics.density;
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ //super.draw(canvas, mapView, shadow);
+
+ final double span = mapView.getLongitudeSpan() / 1e6;
+ final GeoPointImpl center = mapView.getMapViewCenter();
+
+ pixels = mapView.getWidth() / 2; // pixels related to following latitude span
+ bottom = mapView.getHeight() - 14; // pixels from bottom side of screen
+ distance = cgBase.getDistance((center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) - (span /2)), (center.getLatitudeE6() / 1e6), ((center.getLongitudeE6() / 1e6) + (span /2)));
+ distance = distance / 2;
+ distanceRound = 0d;
+
+ if(settings.units == cgSettings.unitsImperial) {
+ distance *= cgBase.kmInMiles;
+
+ if (distance > 100) { // 100+ mi > 1xx mi
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "mi";
+ } else if (distance > 10) { // 10 - 100 mi > 1x mi
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "mi";
+ } else if (distance > 1) { // 1 - 10 mi > 1.x mi
+ distanceRound = Math.floor(distance);
+ units = "mi";
+ } else if (distance > 0.1) { // 0.1 mi - 1.0 mi > 1xx ft
+ distance *= 5280;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "ft";
+ } else { // 1 - 100 ft > 1x ft
+ distance *= 5280;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "ft";
+ }
+ } else {
+ if (distance > 100) { // 100+ km > 1xx km
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "km";
+ } else if (distance > 10) { // 10 - 100 km > 1x km
+ distanceRound = Math.floor(distance / 10) * 10;
+ units = "km";
+ } else if (distance > 1) { // 1 - 10 km > 1.x km
+ distanceRound = Math.floor(distance);
+ units = "km";
+ } else if (distance > 0.1) { // 100 m - 1 km > 1xx m
+ distance *= 1000;
+ distanceRound = Math.floor(distance / 100) * 100;
+ units = "m";
+ } else { // 1 - 100 m > 1x m
+ distance *= 1000;
+ distanceRound = Math.round(distance / 10) * 10;
+ units = "m";
+ }
+ }
+
+ pixels = Math.round((pixels / distance) * distanceRound);
+
+ if (blur == null) {
+ blur = new BlurMaskFilter(3, BlurMaskFilter.Blur.NORMAL);
+ }
+
+ if (scaleShadow == null) {
+ scaleShadow = new Paint();
+ scaleShadow.setAntiAlias(true);
+ scaleShadow.setStrokeWidth(4 * pixelDensity);
+ scaleShadow.setMaskFilter(blur);
+ scaleShadow.setTextSize(14 * pixelDensity);
+ scaleShadow.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (scale == null) {
+ scale = new Paint();
+ scale.setAntiAlias(true);
+ scale.setStrokeWidth(2 * pixelDensity);
+ scale.setTextSize(14 * pixelDensity);
+ scale.setTypeface(Typeface.DEFAULT_BOLD);
+ }
+
+ if (mapView.isSatellite()) {
+ scaleShadow.setColor(0xFF000000);
+ scale.setColor(0xFFFFFFFF);
+ } else {
+ scaleShadow.setColor(0xFFFFFFFF);
+ scale.setColor(0xFF000000);
+ }
+
+ canvas.drawLine(10, bottom, 10, (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine((int)(pixels + 10), bottom, (int)(pixels + 10), (bottom - (8 * pixelDensity)), scaleShadow);
+ canvas.drawLine(8, bottom, (int)(pixels + 12), bottom, scaleShadow);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scaleShadow);
+
+ canvas.drawLine(11, bottom, 11, (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine((int)(pixels + 9), bottom, (int)(pixels + 9), (bottom - (6 * pixelDensity)), scale);
+ canvas.drawLine(10, bottom, (int)(pixels + 10), bottom, scale);
+ canvas.drawText(String.format("%.0f", distanceRound) + " " + units, (float)(pixels - (10 * pixelDensity)), (bottom - (10 * pixelDensity)), scale);
+ }
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
new file mode 100644
index 0000000..8eb76cd
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgUsersOverlay.java
@@ -0,0 +1,185 @@
+package cgeo.geocaching.mapcommon;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.util.Log;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgeodetail;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class cgUsersOverlay extends ItemizedOverlayBase implements OverlayBase {
+
+ private ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+ private Context context = null;
+ private final Pattern patternGeocode = Pattern.compile("^(GC[A-Z0-9]+)(\\: ?(.+))?$", Pattern.CASE_INSENSITIVE);
+
+ public cgUsersOverlay(ItemizedOverlayImpl ovlImplIn, Context contextIn) {
+ super(ovlImplIn);
+ populate();
+
+ context = contextIn;
+ }
+
+ protected void updateItems(UserOverlayItemImpl item) {
+ ArrayList<UserOverlayItemImpl> itemsPre = new ArrayList<UserOverlayItemImpl>();
+ itemsPre.add(item);
+
+ updateItems(itemsPre);
+ }
+
+ public void updateItems(ArrayList<UserOverlayItemImpl> itemsPre) {
+ if (itemsPre == null) {
+ return;
+ }
+
+ for (UserOverlayItemImpl item : itemsPre) {
+ item.setMarker(boundCenter(item.getMarker(0)));
+ }
+
+ items.clear();
+
+ if (itemsPre.size() > 0) {
+ items = (ArrayList<UserOverlayItemImpl>) itemsPre.clone();
+ }
+
+ setLastFocusedItemIndex(-1); // to reset tap during data change
+ populate();
+ }
+
+ @Override
+ public boolean onTap(int index) {
+ try {
+ if (items.size() <= index) {
+ return false;
+ }
+
+ final UserOverlayItemImpl item = items.get(index);
+ final cgUser user = item.getUser();
+
+ // set action
+ String action = null;
+ String geocode = null;
+ final Matcher matcherGeocode = patternGeocode.matcher(user.action.trim());
+
+ if (user.action.length() == 0 || user.action.equalsIgnoreCase("pending")) {
+ action = "Looking around";
+ } else if (user.action.equalsIgnoreCase("tweeting")) {
+ action = "Tweeting";
+ } else if (matcherGeocode.find() == true) {
+ if (matcherGeocode.group(1) != null) {
+ geocode = matcherGeocode.group(1).trim().toUpperCase();
+ }
+ if (matcherGeocode.group(3) != null) {
+ action = "Heading to " + geocode + " (" + matcherGeocode.group(3).trim() + ")";
+ } else {
+ action = "Heading to " + geocode;
+ }
+ } else {
+ action = user.action;
+ }
+
+ // set icon
+ int icon = -1;
+ if (user.client.equalsIgnoreCase("c:geo") == true) {
+ icon = R.drawable.client_cgeo;
+ } else if (user.client.equalsIgnoreCase("preCaching") == true) {
+ icon = R.drawable.client_precaching;
+ } else if (user.client.equalsIgnoreCase("Handy Geocaching") == true) {
+ icon = R.drawable.client_handygeocaching;
+ }
+
+ final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
+ if (icon > -1) {
+ dialog.setIcon(icon);
+ }
+ dialog.setTitle(user.username);
+ dialog.setMessage(action);
+ dialog.setCancelable(true);
+ if (geocode != null && geocode.length() > 0) {
+ dialog.setPositiveButton(geocode + "?", new cacheDetails(geocode));
+ }
+ dialog.setNeutralButton("Dismiss", new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+
+ AlertDialog alert = dialog.create();
+ alert.show();
+
+ return true;
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.onTap: " + e.toString());
+ }
+
+ return false;
+ }
+
+ @Override
+ public void draw(Canvas canvas, MapViewImpl mapView, boolean shadow) {
+ super.draw(canvas, mapView, false);
+ }
+
+ @Override
+ public void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel) {
+ super.drawOverlayBitmap(canvas, drawPosition, projection, drawZoomLevel);
+ }
+
+ @Override
+ public UserOverlayItemImpl createItem(int index) {
+ try {
+ return items.get(index);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.createItem: " + e.toString());
+ }
+
+ return null;
+ }
+
+ @Override
+ public int size() {
+ try {
+ return items.size();
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgUsersOverlay.size: " + e.toString());
+ }
+
+ return 0;
+ }
+
+ private class cacheDetails implements DialogInterface.OnClickListener {
+
+ private String geocode = null;
+
+ public cacheDetails(String geocodeIn) {
+ geocode = geocodeIn;
+ }
+
+ public void onClick(DialogInterface dialog, int id) {
+ if (geocode != null) {
+ Intent detailIntent = new Intent(context, cgeodetail.class);
+ detailIntent.putExtra("geocode", geocode);
+ context.startActivity(detailIntent);
+ }
+
+ dialog.cancel();
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapcommon/cgeomap.java b/src/cgeo/geocaching/mapcommon/cgeomap.java
new file mode 100644
index 0000000..7ba7532
--- /dev/null
+++ b/src/cgeo/geocaching/mapcommon/cgeomap.java
@@ -0,0 +1,1686 @@
+package cgeo.geocaching.mapcommon;
+
+import gnu.android.app.appmanualclient.*;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import java.util.ArrayList;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgDirection;
+import cgeo.geocaching.cgGeo;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.cgUpdateDir;
+import cgeo.geocaching.cgUpdateLoc;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.cgWarning;
+import cgeo.geocaching.cgWaypoint;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import cgeo.geocaching.cgSearch;
+
+import java.util.HashMap;
+import java.util.Locale;
+
+public class cgeomap extends MapBase {
+
+ private Resources res = null;
+ private Activity activity = null;
+ private MapViewImpl mapView = null;
+ private MapControllerImpl mapController = null;
+ private cgSettings settings = null;
+ private cgBase base = null;
+ private cgWarning warning = null;
+ private cgeoapplication app = null;
+ private SharedPreferences.Editor prefsEdit = null;
+ private cgGeo geo = null;
+ private cgDirection dir = null;
+ private cgUpdateLoc geoUpdate = new UpdateLoc();
+ private cgUpdateDir dirUpdate = new UpdateDir();
+ // from intent
+ private boolean fromDetailIntent = false;
+ private Long searchIdIntent = null;
+ private String geocodeIntent = null;
+ private Double latitudeIntent = null;
+ private Double longitudeIntent = null;
+ private String waypointTypeIntent = null;
+ // status data
+ private Long searchId = null;
+ private String token = null;
+ private boolean noMapTokenShowed = false;
+ // map status data
+ private boolean followMyLocation = false;
+ private Integer centerLatitude = null;
+ private Integer centerLongitude = null;
+ private Integer spanLatitude = null;
+ private Integer spanLongitude = null;
+ private Integer centerLatitudeUsers = null;
+ private Integer centerLongitudeUsers = null;
+ private Integer spanLatitudeUsers = null;
+ private Integer spanLongitudeUsers = null;
+ // thread
+ private LoadTimer loadTimer = null;
+ private UsersTimer usersTimer = null;
+ private LoadThread loadThread = null;
+ private DownloadThread downloadThread = null;
+ private DisplayThread displayThread = null;
+ private UsersThread usersThread = null;
+ private DisplayUsersThread displayUsersThread = null;
+ private LoadDetails loadDetailsThread = null;
+ private volatile long loadThreadRun = 0l;
+ private volatile long downloadThreadRun = 0l;
+ private volatile long usersThreadRun = 0l;
+ private volatile boolean downloaded = false;
+ // overlays
+ private cgMapOverlay overlayCaches = null;
+ private cgUsersOverlay overlayUsers = null;
+ private cgOverlayScale overlayScale = null;
+ private cgMapMyOverlay overlayMyLoc = null;
+ // data for overlays
+ private int cachesCnt = 0;
+ private HashMap<Integer, Drawable> iconsCache = new HashMap<Integer, Drawable>();
+ private ArrayList<cgCache> caches = new ArrayList<cgCache>();
+ private ArrayList<cgUser> users = new ArrayList<cgUser>();
+ private ArrayList<cgCoord> coordinates = new ArrayList<cgCoord>();
+ // storing for offline
+ private ProgressDialog waitDialog = null;
+ private int detailTotal = 0;
+ private int detailProgress = 0;
+ private Long detailProgressTime = 0l;
+ // views
+ private ImageView myLocSwitch = null;
+ // other things
+ private boolean live = true; // live map (live, dead) or rest (displaying caches on map)
+ private boolean liveChanged = false; // previous state for loadTimer
+ private boolean centered = false; // if map is already centered
+ private boolean alreadyCentered = false; // -""- for setting my location
+ // handlers
+ final private Handler displayHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ // set title
+ final StringBuilder title = new StringBuilder();
+
+ if (live == true) {
+ title.append(res.getString(R.string.map_live));
+ } else {
+ title.append(res.getString(R.string.map_map));
+ }
+
+ if (caches != null && cachesCnt > 0) {
+ title.append(" ");
+ title.append("[");
+ title.append(caches.size());
+ title.append("]");
+ }
+
+ base.setTitle(activity, title.toString());
+ } else if (what == 1 && mapView != null) {
+ mapView.invalidate();
+ }
+ }
+ };
+ final private Handler showProgressHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ final int what = msg.what;
+
+ if (what == 0) {
+ base.showProgress(activity, false);
+ } else if (what == 1) {
+ base.showProgress(activity, true);
+ }
+ }
+ };
+ final private Handler loadDetailsHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ if (waitDialog != null) {
+ Float diffTime = new Float((System.currentTimeMillis() - detailProgressTime) / 1000); // seconds left
+ Float oneCache = diffTime / detailProgress; // left time per cache
+ Float etaTime = (detailTotal - detailProgress) * oneCache; // seconds remaining
+
+ waitDialog.setProgress(detailProgress);
+ if (etaTime < 40) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 90) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", (etaTime / 60)) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ }
+ } else {
+ if (waitDialog != null) {
+ waitDialog.dismiss();
+ waitDialog.setOnCancelListener(null);
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ }
+ }
+ };
+ final private Handler noMapTokenHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (!noMapTokenShowed) {
+ warning.showToast(res.getString(R.string.map_token_err));
+
+ noMapTokenShowed = true;
+ }
+ }
+ };
+
+ public cgeomap(ActivityImpl activity) {
+ super(activity);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // class init
+ res = this.getResources();
+ activity = this.getActivity();
+ app = (cgeoapplication) activity.getApplication();
+ app.setAction(null);
+ settings = new cgSettings(activity, activity.getSharedPreferences(cgSettings.preferences, 0));
+ base = new cgBase(app, settings, activity.getSharedPreferences(cgSettings.preferences, 0));
+ warning = new cgWarning(activity);
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ MapFactory mapFactory = settings.getMapFactory();
+
+ // reset status
+ noMapTokenShowed = false;
+
+ // set layout
+ activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // set layout
+ if (settings.skin == 1) {
+ activity.setTheme(R.style.light);
+ } else {
+ activity.setTheme(R.style.dark);
+ }
+ activity.setContentView(settings.getMapFactory().getMapLayoutId());
+ base.setTitle(activity, res.getString(R.string.map_map));
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ mapView = (MapViewImpl) activity.findViewById(mapFactory.getMapViewId());
+ mapView.setMapSource(settings);
+ if (!mapView.needsScaleOverlay()) {
+ mapView.setBuiltinScale(true);
+ }
+
+ // initialize map
+ if (settings.maptype == cgSettings.mapSatellite) {
+ mapView.setSatellite(true);
+ } else {
+ mapView.setSatellite(false);
+ }
+ mapView.setBuiltInZoomControls(true);
+ mapView.displayZoomControls(true);
+ mapView.preLoad();
+
+ // initialize overlays
+ mapView.clearOverlays();
+
+ if (overlayMyLoc == null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (settings.publicLoc > 0 && overlayUsers == null) {
+ overlayUsers = mapView.createAddUsersOverlay(activity, getResources().getDrawable(R.drawable.user_location));
+ }
+
+ if (overlayCaches == null) {
+ overlayCaches = mapView.createAddMapOverlay(settings, mapView.getContext(), getResources().getDrawable(R.drawable.marker), fromDetailIntent);
+ }
+
+ if (overlayScale == null && mapView.needsScaleOverlay()) {
+ overlayScale = new cgOverlayScale(activity, settings);
+ mapView.addOverlay(mapFactory.getOverlayBaseWrapper(overlayScale));
+ }
+
+ mapView.invalidate();
+
+ mapController = mapView.getMapController();
+ mapController.setZoom(settings.mapzoom);
+
+ // start location and directory services
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ // get parameters
+ Bundle extras = activity.getIntent().getExtras();
+ if (extras != null) {
+ fromDetailIntent = extras.getBoolean("detail");
+ searchIdIntent = extras.getLong("searchid");
+ geocodeIntent = extras.getString("geocode");
+ latitudeIntent = extras.getDouble("latitude");
+ longitudeIntent = extras.getDouble("longitude");
+ waypointTypeIntent = extras.getString("wpttype");
+
+ if (searchIdIntent == 0l) {
+ searchIdIntent = null;
+ }
+ if (latitudeIntent == 0.0) {
+ latitudeIntent = null;
+ }
+ if (longitudeIntent == 0.0) {
+ longitudeIntent = null;
+ }
+ }
+
+ // live or death
+ if (searchIdIntent == null && geocodeIntent == null && (latitudeIntent == null || longitudeIntent == null)) {
+ live = true;
+ } else {
+ live = false;
+ }
+
+ // google analytics
+ if (live) {
+ base.sendAnal(activity, "/map/live");
+
+ followMyLocation = true;
+ } else {
+ base.sendAnal(activity, "/map/normal");
+
+ followMyLocation = false;
+
+ if (geocodeIntent != null || searchIdIntent != null || (latitudeIntent != null && longitudeIntent != null)) {
+ centerMap(geocodeIntent, searchIdIntent, latitudeIntent, longitudeIntent);
+ }
+ }
+ setMyLoc(null);
+ startTimer();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ settings.load();
+
+ app.setAction(null);
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+
+ if (geo != null) {
+ geoUpdate.updateLoc(geo);
+ }
+ if (dir != null) {
+ dirUpdate.updateDir(dir);
+ }
+
+ startTimer();
+ }
+
+ @Override
+ public void onStop() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ savePrefs();
+
+ if (mapView != null) {
+ mapView.destroyDrawingCache();
+ }
+
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(0, 1, 0, res.getString(R.string.caches_on_map)).setIcon(android.R.drawable.ic_menu_mapmode);
+ menu.add(0, 3, 0, res.getString(R.string.map_live_disable)).setIcon(android.R.drawable.ic_menu_close_clear_cancel);
+ menu.add(0, 4, 0, res.getString(R.string.caches_store_offline)).setIcon(android.R.drawable.ic_menu_set_as).setEnabled(false);
+ menu.add(0, 2, 0, res.getString(R.string.map_trail_hide)).setIcon(android.R.drawable.ic_menu_recent_history);
+ menu.add(0, 5, 0, res.getString(R.string.map_circles_hide)).setIcon(android.R.drawable.ic_menu_view);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ MenuItem item;
+ try {
+ item = menu.findItem(1); // view
+ if (mapView != null && mapView.isSatellite() == false) {
+ item.setTitle(res.getString(R.string.map_view_satellite));
+ } else {
+ item.setTitle(res.getString(R.string.map_view_map));
+ }
+
+ item = menu.findItem(2); // show trail
+ if (settings.maptrail == 1) {
+ item.setTitle(res.getString(R.string.map_trail_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_trail_show));
+ }
+
+ item = menu.findItem(3); // live map
+ if (live == false) {
+ item.setEnabled(false);
+ item.setTitle(res.getString(R.string.map_live_enable));
+ } else {
+ if (settings.maplive == 1) {
+ item.setTitle(res.getString(R.string.map_live_disable));
+ } else {
+ item.setTitle(res.getString(R.string.map_live_enable));
+ }
+ }
+
+ item = menu.findItem(4); // store loaded
+ if (live && !isLoading() && app.getNotOfflineCount(searchId) > 0 && caches != null && caches.size() > 0) {
+ item.setEnabled(true);
+ } else {
+ item.setEnabled(false);
+ }
+
+ item = menu.findItem(5); // show circles
+ if (overlayCaches != null && overlayCaches.getCircles()) {
+ item.setTitle(res.getString(R.string.map_circles_hide));
+ } else {
+ item.setTitle(res.getString(R.string.map_circles_show));
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onPrepareOptionsMenu: " + e.toString());
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int id = item.getItemId();
+
+ if (id == 1) {
+ if (mapView != null && mapView.isSatellite() == false) {
+ mapView.setSatellite(true);
+
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ prefsEdit.commit();
+ } else {
+ mapView.setSatellite(false);
+
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ prefsEdit.commit();
+ }
+
+ return true;
+ } else if (id == 2) {
+ if (settings.maptrail == 1) {
+ prefsEdit.putInt("maptrail", 0);
+ prefsEdit.commit();
+
+ settings.maptrail = 0;
+ } else {
+ prefsEdit.putInt("maptrail", 1);
+ prefsEdit.commit();
+
+ settings.maptrail = 1;
+ }
+ } else if (id == 3) {
+ if (settings.maplive == 1) {
+ settings.liveMapDisable();
+ } else {
+ settings.liveMapEnable();
+ }
+ liveChanged = true;
+ searchId = null;
+ searchIdIntent = null;
+ } else if (id == 4) {
+ if (live && !isLoading() && caches != null && !caches.isEmpty()) {
+ final ArrayList<String> geocodes = new ArrayList<String>();
+
+ ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ try {
+ if (cachesProtected != null && cachesProtected.size() > 0) {
+ final GeoPointImpl mapCenter = mapView.getMapViewCenter();
+ final int mapCenterLat = mapCenter.getLatitudeE6();
+ final int mapCenterLon = mapCenter.getLongitudeE6();
+ final int mapSpanLat = mapView.getLatitudeSpan();
+ final int mapSpanLon = mapView.getLongitudeSpan();
+
+ for (cgCache oneCache : cachesProtected) {
+ if (oneCache != null && oneCache.latitude != null && oneCache.longitude != null) {
+ if (base.isCacheInViewPort(mapCenterLat, mapCenterLon, mapSpanLat, mapSpanLon, oneCache.latitude, oneCache.longitude) && app.isOffline(oneCache.geocode, null) == false) {
+ geocodes.add(oneCache.geocode);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeomap.onOptionsItemSelected.#4: " + e.toString());
+ }
+
+ detailTotal = geocodes.size();
+
+ if (detailTotal == 0) {
+ warning.showToast(res.getString(R.string.warn_save_nothing));
+
+ return true;
+ }
+
+ waitDialog = new ProgressDialog(activity);
+ waitDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ waitDialog.setCancelable(true);
+ waitDialog.setMax(detailTotal);
+ waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+
+ public void onCancel(DialogInterface arg0) {
+ try {
+ if (loadDetailsThread != null) {
+ loadDetailsThread.stopIt();
+ }
+
+ if (geo == null) {
+ geo = app.startGeo(activity, geoUpdate, base, settings, warning, 0, 0);
+ }
+ if (settings.useCompass == 1 && dir == null) {
+ dir = app.startDir(activity, dirUpdate, warning);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.onPrepareOptionsMenu.onCancel: " + e.toString());
+ }
+ }
+ });
+
+ Float etaTime = new Float((detailTotal * (float) 7) / 60);
+ if (etaTime < 0.4) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + res.getString(R.string.caches_eta_ltm));
+ } else if (etaTime < 1.5) {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_min));
+ } else {
+ waitDialog.setMessage(res.getString(R.string.caches_downloading) + " " + String.format(Locale.getDefault(), "%.0f", etaTime) + " " + res.getString(R.string.caches_eta_mins));
+ }
+ waitDialog.show();
+
+ detailProgressTime = System.currentTimeMillis();
+
+ loadDetailsThread = new LoadDetails(loadDetailsHandler, geocodes);
+ loadDetailsThread.start();
+
+ return true;
+ }
+ } else if (id == 5) {
+ if (overlayCaches == null) {
+ return false;
+ }
+
+ overlayCaches.switchCircles();
+ }
+
+ return false;
+ }
+
+ private void savePrefs() {
+ if (mapView == null) {
+ return;
+ }
+
+ if (mapView.isSatellite()) {
+ prefsEdit.putInt("maptype", cgSettings.mapSatellite);
+ settings.maptype = cgSettings.mapSatellite;
+ } else {
+ prefsEdit.putInt("maptype", cgSettings.mapClassic);
+ settings.maptype = cgSettings.mapClassic;
+ }
+
+ if (prefsEdit == null) {
+ prefsEdit = activity.getSharedPreferences(cgSettings.preferences, 0).edit();
+ }
+ prefsEdit.putInt("mapzoom", mapView.getMapZoomLevel());
+ prefsEdit.commit();
+ }
+
+ // set center of map to my location
+ private void myLocationInMiddle() {
+ if (geo == null) {
+ return;
+ }
+ if (!followMyLocation) {
+ return;
+ }
+
+ centerMap(geo.latitudeNow, geo.longitudeNow);
+ }
+
+ // class: update location
+ private class UpdateLoc extends cgUpdateLoc {
+
+ @Override
+ public void updateLoc(cgGeo geo) {
+ if (geo == null) {
+ return;
+ }
+
+ try {
+ if (overlayMyLoc == null && mapView != null) {
+ overlayMyLoc = new cgMapMyOverlay(settings);
+ mapView.addOverlay(settings.getMapFactory().getOverlayBaseWrapper(overlayMyLoc));
+ }
+
+ if (overlayMyLoc != null && geo.location != null) {
+ overlayMyLoc.setCoordinates(geo.location);
+ }
+
+ if (geo.latitudeNow != null && geo.longitudeNow != null) {
+ if (followMyLocation == true) {
+ myLocationInMiddle();
+ }
+ }
+
+ if (settings.useCompass == 0 || (geo.speedNow != null && geo.speedNow > 5)) { // use GPS when speed is higher than 18 km/h
+ if (geo.bearingNow != null) {
+ overlayMyLoc.setHeading(geo.bearingNow);
+ } else {
+ overlayMyLoc.setHeading(new Double(0));
+ }
+ }
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "Failed to update location.");
+ }
+ }
+ }
+
+ // class: update direction
+ private class UpdateDir extends cgUpdateDir {
+
+ @Override
+ public void updateDir(cgDirection dir) {
+ if (dir == null || dir.directionNow == null) {
+ return;
+ }
+
+ if (overlayMyLoc != null && mapView != null && (geo == null || geo.speedNow == null || geo.speedNow <= 5)) { // use compass when speed is lower than 18 km/h
+ overlayMyLoc.setHeading(dir.directionNow);
+ mapView.invalidate();
+ }
+ }
+ }
+
+ public void startTimer() {
+ if (latitudeIntent != null && longitudeIntent != null) {
+ // display just one point
+ (new DisplayPointThread()).start();
+ } else {
+ // start timer
+ if (loadTimer != null) {
+ loadTimer.stopIt();
+ loadTimer = null;
+ }
+ loadTimer = new LoadTimer();
+ loadTimer.start();
+ }
+
+ if (settings.publicLoc > 0) {
+ if (usersTimer != null) {
+ usersTimer.stopIt();
+ usersTimer = null;
+ }
+ usersTimer = new UsersTimer();
+ usersTimer.start();
+ }
+ }
+
+ // loading timer
+ private class LoadTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (loadThread != null) {
+ loadThread.stopIt();
+ loadThread = null;
+ }
+
+ if (downloadThread != null) {
+ downloadThread.stopIt();
+ downloadThread = null;
+ }
+
+ if (displayThread != null) {
+ displayThread.stopIt();
+ displayThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ boolean force = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+ force = false;
+
+ if (liveChanged) {
+ moved = true;
+ force = true;
+ } else if (live && settings.maplive == 1 && downloaded == false) {
+ moved = true;
+ } else if (centerLatitude == null || centerLongitude == null) {
+ moved = true;
+ } else if (spanLatitude == null || spanLongitude == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitude) > 50) || (Math.abs(spanLongitudeNow - spanLongitude) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow / 4)) // map moved
+ ) && (cachesCnt <= 0 || caches == null || caches.isEmpty()
+ || !base.isInViewPort(centerLatitude, centerLongitude, centerLatitudeNow, centerLongitudeNow, spanLatitude, spanLongitude, spanLatitudeNow, spanLongitudeNow))) {
+ moved = true;
+ }
+
+ if (moved && caches != null && centerLatitude != null && centerLongitude != null && ((Math.abs(centerLatitudeNow - centerLatitude) > (spanLatitudeNow * 1.2)) || (Math.abs(centerLongitudeNow - centerLongitude) > (spanLongitudeNow * 1.2)))) {
+ force = true;
+ }
+
+ //LeeB
+ // save new values
+ if (moved) {
+ liveChanged = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (1000 < (currentTime - loadThreadRun)) {
+ // from web
+ if (20000 < (currentTime - loadThreadRun)) {
+ force = true; // probably stucked thread
+ }
+
+ if (force && loadThread != null && loadThread.isWorking()) {
+ loadThread.stopIt();
+
+ try {
+ sleep(100);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (loadThread != null && loadThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitude = centerLatitudeNow;
+ centerLongitude = centerLongitudeNow;
+ spanLatitude = spanLatitudeNow;
+ spanLongitude = spanLongitudeNow;
+
+ showProgressHandler.sendEmptyMessage(1); // show progress
+
+ loadThread = new LoadThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ loadThread.setName("loadThread");
+ loadThread.start(); //loadThread will kick off downloadThread once it's done
+ }
+ }
+ }
+
+ if (!isLoading()) {
+ showProgressHandler.sendEmptyMessage(0); // hide progress
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // loading timer
+ private class UsersTimer extends Thread {
+
+ private volatile boolean stop = false;
+
+ public void stopIt() {
+ stop = true;
+
+ if (usersThread != null) {
+ usersThread.stopIt();
+ usersThread = null;
+ }
+
+ if (displayUsersThread != null) {
+ displayUsersThread.stopIt();
+ displayUsersThread = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ GeoPointImpl mapCenterNow;
+ int centerLatitudeNow;
+ int centerLongitudeNow;
+ int spanLatitudeNow;
+ int spanLongitudeNow;
+ boolean moved = false;
+ long currentTime = 0;
+
+ while (!stop) {
+ try {
+ sleep(250);
+
+ if (mapView != null) {
+ // get current viewport
+ mapCenterNow = mapView.getMapViewCenter();
+ centerLatitudeNow = mapCenterNow.getLatitudeE6();
+ centerLongitudeNow = mapCenterNow.getLongitudeE6();
+ spanLatitudeNow = mapView.getLatitudeSpan();
+ spanLongitudeNow = mapView.getLongitudeSpan();
+
+ // check if map moved or zoomed
+ moved = false;
+
+ currentTime = System.currentTimeMillis();
+
+ if (60000 < (currentTime - usersThreadRun)) {
+ moved = true;
+ } else if (centerLatitudeUsers == null || centerLongitudeUsers == null) {
+ moved = true;
+ } else if (spanLatitudeUsers == null || spanLongitudeUsers == null) {
+ moved = true;
+ } else if (((Math.abs(spanLatitudeNow - spanLatitudeUsers) > 50) || (Math.abs(spanLongitudeNow - spanLongitudeUsers) > 50) || // changed zoom
+ (Math.abs(centerLatitudeNow - centerLatitudeUsers) > (spanLatitudeNow / 4)) || (Math.abs(centerLongitudeNow - centerLongitudeUsers) > (spanLongitudeNow / 4)) // map moved
+ ) && !base.isInViewPort(centerLatitudeUsers, centerLongitudeUsers, centerLatitudeNow, centerLongitudeNow, spanLatitudeUsers, spanLongitudeUsers, spanLatitudeNow, spanLongitudeNow)) {
+ moved = true;
+ }
+
+ // save new values
+ if (moved && (1000 < (currentTime - usersThreadRun))) {
+ if (usersThread != null && usersThread.isWorking()) {
+ continue;
+ }
+
+ centerLatitudeUsers = centerLatitudeNow;
+ centerLongitudeUsers = centerLongitudeNow;
+ spanLatitudeUsers = spanLatitudeNow;
+ spanLongitudeUsers = spanLongitudeNow;
+
+ usersThread = new UsersThread(centerLatitude, centerLongitude, spanLatitude, spanLongitude);
+ usersThread.start();
+ }
+ }
+
+ yield();
+ } catch (Exception e) {
+ Log.w(cgSettings.tag, "cgeomap.LoadUsersTimer.run: " + e.toString());
+ }
+ };
+ }
+ }
+
+ // load caches from database
+ private class LoadThread extends DoThread {
+
+ public LoadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ loadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //LeeB - I think this can be done better:
+ //1. fetch and draw(in another thread) caches from the db (fast? db read will be the slow bit)
+ //2. fetch and draw(in another thread) and then insert into the db caches from geocaching.com - dont draw/insert if exist in memory?
+
+ // stage 1 - pull and render from the DB only
+ if (settings.maplive == 0) {
+ searchId = app.getStoredInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ } else {
+ searchId = app.getCachedInViewport(centerLat, centerLon, spanLat, spanLon, settings.cacheType);
+ }
+
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ if (stop) {
+ displayThread.stopIt();
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (settings.maplive >= 1) {
+ if (downloadThread != null && downloadThread.isWorking()) {
+ downloadThread.stopIt();
+ }
+ downloadThread = new DownloadThread(centerLat, centerLon, spanLat, spanLon);
+ downloadThread.setName("downloadThread");
+ downloadThread.start();
+ }
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load caches from internet
+ private class DownloadThread extends DoThread {
+
+ public DownloadThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() { //first time we enter we have crappy long/lat....
+ try {
+ stop = false;
+ working = true;
+ downloadThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ //*** this needs to be in it's own thread
+ // stage 2 - pull and render from geocaching.com
+ //this should just fetch and insert into the db _and_ be cancel-able if the viewport changes
+
+ if (token == null) {
+ token = base.getMapUserToken(noMapTokenHandler);
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ HashMap<String, String> params = new HashMap<String, String>();
+ params.put("usertoken", token);
+ params.put("latitude-min", String.format((Locale) null, "%.6f", latMin));
+ params.put("latitude-max", String.format((Locale) null, "%.6f", latMax));
+ params.put("longitude-min", String.format((Locale) null, "%.6f", lonMin));
+ params.put("longitude-max", String.format((Locale) null, "%.6f", lonMax));
+
+ searchId = base.searchByViewport(params, 0);
+ if (searchId != null) {
+ downloaded = true;
+ }
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ caches = app.getCaches(searchId, centerLat, centerLon, spanLat, spanLon);
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ //render
+ if (displayThread != null && displayThread.isWorking()) {
+ displayThread.stopIt();
+ }
+ displayThread = new DisplayThread(centerLat, centerLon, spanLat, spanLon);
+ displayThread.start();
+
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display (down)loaded caches
+ private class DisplayThread extends DoThread {
+
+ public DisplayThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || caches == null) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display caches
+ final ArrayList<cgCache> cachesProtected = (ArrayList<cgCache>) caches.clone();
+ final ArrayList<CacheOverlayItemImpl> items = new ArrayList<CacheOverlayItemImpl>();
+
+ if (cachesProtected != null && !cachesProtected.isEmpty()) {
+ int counter = 0;
+ int icon = 0;
+ Drawable pin = null;
+ CacheOverlayItemImpl item = null;
+
+ for (cgCache cacheOne : cachesProtected) {
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ if (cacheOne.latitude == null && cacheOne.longitude == null) {
+ continue;
+ }
+
+ final cgCoord coord = new cgCoord(cacheOne);
+ coordinates.add(coord);
+
+ item = settings.getMapFactory().getCacheOverlayItem(coord, cacheOne.type);
+ icon = base.getIcon(true, cacheOne.type, cacheOne.own, cacheOne.found, cacheOne.disabled || cacheOne.archived);
+ pin = null;
+
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+
+ /*
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ */
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = cachesProtected.size();
+
+ if (stop) {
+ displayHandler.sendEmptyMessage(0);
+ working = false;
+
+ return;
+ }
+
+ // display cache waypoints
+ if (cachesCnt == 1 && (geocodeIntent != null || searchIdIntent != null) && !live) {
+ if (cachesCnt == 1 && live == false) {
+ cgCache oneCache = cachesProtected.get(0);
+
+ if (oneCache != null && oneCache.waypoints != null && !oneCache.waypoints.isEmpty()) {
+ for (cgWaypoint oneWaypoint : oneCache.waypoints) {
+ if (oneWaypoint.latitude == null && oneWaypoint.longitude == null) {
+ continue;
+ }
+
+ cgCoord coord = new cgCoord(oneWaypoint);
+
+ coordinates.add(coord);
+ item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ icon = base.getIcon(false, oneWaypoint.type, false, false, false);
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ items.add(item);
+ }
+
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+ }
+ } else {
+ overlayCaches.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+
+ cachesProtected.clear();
+
+ displayHandler.sendEmptyMessage(0);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // load users from Go 4 Cache
+ private class UsersThread extends DoThread {
+
+ public UsersThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+ usersThreadRun = System.currentTimeMillis();
+
+ if (stop) {
+ return;
+ }
+
+ double latMin = (centerLat / 1e6) - ((spanLat / 1e6) / 2) - ((spanLat / 1e6) / 4);
+ double latMax = (centerLat / 1e6) + ((spanLat / 1e6) / 2) + ((spanLat / 1e6) / 4);
+ double lonMin = (centerLon / 1e6) - ((spanLon / 1e6) / 2) - ((spanLon / 1e6) / 4);
+ double lonMax = (centerLon / 1e6) + ((spanLon / 1e6) / 2) + ((spanLon / 1e6) / 4);
+ double llCache;
+
+ if (latMin > latMax) {
+ llCache = latMax;
+ latMax = latMin;
+ latMin = llCache;
+ }
+ if (lonMin > lonMax) {
+ llCache = lonMax;
+ lonMax = lonMin;
+ lonMin = llCache;
+ }
+
+ users = base.getGeocachersInViewport(settings.getUsername(), latMin, latMax, lonMin, lonMax);
+
+ if (stop) {
+ return;
+ }
+
+ if (displayUsersThread != null && displayUsersThread.isWorking()) {
+ displayUsersThread.stopIt();
+ }
+ displayUsersThread = new DisplayUsersThread(users, centerLat, centerLon, spanLat, spanLon);
+ displayUsersThread.start();
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display users of Go 4 Cache
+ private class DisplayUsersThread extends DoThread {
+
+ private ArrayList<cgUser> users = null;
+
+ public DisplayUsersThread(ArrayList<cgUser> usersIn, long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ super(centerLatIn, centerLonIn, spanLatIn, spanLonIn);
+
+ users = usersIn;
+ }
+
+ @Override
+ public void run() {
+ try {
+ stop = false;
+ working = true;
+
+ if (mapView == null || users == null || users.isEmpty()) {
+ return;
+ }
+
+ // display users
+ ArrayList<UserOverlayItemImpl> items = new ArrayList<UserOverlayItemImpl>();
+
+ int counter = 0;
+ UserOverlayItemImpl item = null;
+
+ for (cgUser userOne : users) {
+ if (stop) {
+ return;
+ }
+
+ if (userOne.latitude == null && userOne.longitude == null) {
+ continue;
+ }
+
+ item = settings.getMapFactory().getUserOverlayItemBase(activity, userOne);
+ items.add(item);
+
+ counter++;
+ if ((counter % 10) == 0) {
+ overlayUsers.updateItems(items);
+ displayHandler.sendEmptyMessage(1);
+ }
+ }
+
+ overlayUsers.updateItems(items);
+ } finally {
+ working = false;
+ }
+ }
+ }
+
+ // display one point
+ private class DisplayPointThread extends Thread {
+
+ @Override
+ public void run() {
+ if (mapView == null || caches == null) {
+ return;
+ }
+
+ if (latitudeIntent != null && longitudeIntent != null) {
+ cgCoord coord = new cgCoord();
+ coord.type = "waypoint";
+ coord.latitude = latitudeIntent;
+ coord.longitude = longitudeIntent;
+ coord.name = "some place";
+
+ coordinates.add(coord);
+ CacheOverlayItemImpl item = settings.getMapFactory().getCacheOverlayItem(coord, null);
+
+ final int icon = base.getIcon(false, waypointTypeIntent, false, false, false);
+ Drawable pin = null;
+ if (iconsCache.containsKey(icon)) {
+ pin = iconsCache.get(icon);
+ } else {
+ pin = getResources().getDrawable(icon);
+ pin.setBounds(0, 0, pin.getIntrinsicWidth(), pin.getIntrinsicHeight());
+ iconsCache.put(icon, pin);
+ }
+ item.setMarker(pin);
+
+ overlayCaches.updateItems(item);
+ displayHandler.sendEmptyMessage(1);
+
+ cachesCnt = 1;
+ } else {
+ cachesCnt = 0;
+ }
+
+ displayHandler.sendEmptyMessage(0);
+ }
+ }
+
+ // parent for those above :)
+ private class DoThread extends Thread {
+
+ protected boolean working = true;
+ protected boolean stop = false;
+ protected long centerLat = 0l;
+ protected long centerLon = 0l;
+ protected long spanLat = 0l;
+ protected long spanLon = 0l;
+
+ public DoThread(long centerLatIn, long centerLonIn, long spanLatIn, long spanLonIn) {
+ centerLat = centerLatIn;
+ centerLon = centerLonIn;
+ spanLat = spanLatIn;
+ spanLon = spanLonIn;
+ }
+
+ public synchronized boolean isWorking() {
+ return working;
+ }
+
+ public synchronized void stopIt() {
+ stop = true;
+ }
+ }
+
+ // get if map is loading something
+ private synchronized boolean isLoading() {
+ boolean loading = false;
+
+ if (loadThread != null && loadThread.isWorking()) {
+ loading = true;
+ } else if (downloadThread != null && downloadThread.isWorking()) {
+ loading = true;
+ } else if (displayThread != null && displayThread.isWorking()) {
+ loading = true;
+ }
+
+ return loading;
+ }
+
+ // store caches
+ private class LoadDetails extends Thread {
+
+ private Handler handler = null;
+ private ArrayList<String> geocodes = null;
+ private volatile boolean stop = false;
+ private long last = 0l;
+
+ public LoadDetails(Handler handlerIn, ArrayList<String> geocodesIn) {
+ handler = handlerIn;
+ geocodes = geocodesIn;
+ }
+
+ public void stopIt() {
+ stop = true;
+ }
+
+ @Override
+ public void run() {
+ if (geocodes == null || geocodes.isEmpty()) {
+ return;
+ }
+
+ if (dir != null) {
+ dir = app.removeDir();
+ }
+ if (geo != null) {
+ geo = app.removeGeo();
+ }
+
+ for (String geocode : geocodes) {
+ try {
+ if (stop == true) {
+ break;
+ }
+
+ if (!app.isOffline(geocode, null)) {
+ if ((System.currentTimeMillis() - last) < 1500) {
+ try {
+ int delay = 1000 + ((Double) (Math.random() * 1000)).intValue() - (int) (System.currentTimeMillis() - last);
+ if (delay < 0) {
+ delay = 500;
+ }
+
+ sleep(delay);
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+
+ if (stop == true) {
+ Log.i(cgSettings.tag, "Stopped storing process.");
+
+ break;
+ }
+
+ base.storeCache(app, activity, null, geocode, 1, handler);
+ }
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgeocaches.LoadDetails.run: " + e.toString());
+ } finally {
+ // one more cache over
+ detailProgress++;
+ handler.sendEmptyMessage(0);
+ }
+
+ yield();
+
+ last = System.currentTimeMillis();
+ }
+
+ // we're done
+ handler.sendEmptyMessage(1);
+ }
+ }
+
+ // center map to desired location
+ private void centerMap(Double latitude, Double longitude) {
+ if (latitude == null || longitude == null) {
+ return;
+ }
+ if (mapView == null) {
+ return;
+ }
+
+ if (!alreadyCentered) {
+ alreadyCentered = true;
+
+ mapController.setCenter(makeGeoPoint(latitude, longitude));
+ } else {
+ mapController.animateTo(makeGeoPoint(latitude, longitude));
+ }
+ }
+
+ // move map to view results of searchIdIntent
+ private void centerMap(String geocodeCenter, Long searchIdCenter, Double latitudeCenter, Double longitudeCenter) {
+ if (!centered && (geocodeCenter != null || searchIdIntent != null)) {
+ try {
+ ArrayList<Object> viewport;
+
+ if (geocodeCenter != null) {
+ viewport = app.getBounds(geocodeCenter);
+ } else {
+ viewport = app.getBounds(searchIdCenter);
+ }
+
+ Integer cnt = (Integer) viewport.get(0);
+ Integer minLat = null;
+ Integer maxLat = null;
+ Integer minLon = null;
+ Integer maxLon = null;
+
+ if (viewport.get(1) != null) {
+ minLat = new Double((Double) viewport.get(1) * 1e6).intValue();
+ }
+ if (viewport.get(2) != null) {
+ maxLat = new Double((Double) viewport.get(2) * 1e6).intValue();
+ }
+ if (viewport.get(3) != null) {
+ maxLon = new Double((Double) viewport.get(3) * 1e6).intValue();
+ }
+ if (viewport.get(4) != null) {
+ minLon = new Double((Double) viewport.get(4) * 1e6).intValue();
+ }
+
+ if (cnt == null || cnt <= 0 || minLat == null || maxLat == null || minLon == null || maxLon == null) {
+ return;
+ }
+
+ int centerLat = 0;
+ int centerLon = 0;
+
+ if ((Math.abs(maxLat) - Math.abs(minLat)) != 0) {
+ centerLat = minLat + ((maxLat - minLat) / 2);
+ } else {
+ centerLat = maxLat;
+ }
+ if ((Math.abs(maxLon) - Math.abs(minLon)) != 0) {
+ centerLon = minLon + ((maxLon - minLon) / 2);
+ } else {
+ centerLon = maxLon;
+ }
+
+ if (cnt != null && cnt > 0) {
+ mapController.setCenter(settings.getMapFactory().getGeoPointBase(centerLat, centerLon));
+ if (Math.abs(maxLat - minLat) != 0 && Math.abs(maxLon - minLon) != 0) {
+ mapController.zoomToSpan(Math.abs(maxLat - minLat), Math.abs(maxLon - minLon));
+ }
+ }
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ } else if (!centered && latitudeCenter != null && longitudeCenter != null) {
+ try {
+ mapController.setCenter(makeGeoPoint(latitudeCenter, longitudeCenter));
+ } catch (Exception e) {
+ // nothing at all
+ }
+
+ centered = true;
+ alreadyCentered = true;
+ }
+ }
+
+ // switch My Location button image
+ private void setMyLoc(Boolean status) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (status == null) {
+ if (followMyLocation == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ } else {
+ if (status == true) {
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ } else {
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ }
+ }
+
+ myLocSwitch.setOnClickListener(new MyLocationListener());
+ }
+
+ // set my location listener
+ private class MyLocationListener implements View.OnClickListener {
+
+ public void onClick(View view) {
+ if (myLocSwitch == null) {
+ myLocSwitch = (ImageView) activity.findViewById(R.id.my_position);
+ }
+
+ if (followMyLocation == true) {
+ followMyLocation = false;
+
+ myLocSwitch.setImageResource(R.drawable.my_location_off);
+ } else {
+ followMyLocation = true;
+ myLocationInMiddle();
+
+ myLocSwitch.setImageResource(R.drawable.my_location_on);
+ }
+ }
+ }
+
+ // make geopoint
+ private GeoPointImpl makeGeoPoint(Double latitude, Double longitude) {
+ return settings.getMapFactory().getGeoPointBase((int) (latitude * 1e6), (int) (longitude * 1e6));
+ }
+
+ // close activity and open homescreen
+ public void goHome(View view) {
+ base.goHome(activity);
+ }
+
+ // open manual entry
+ public void goManual(View view) {
+ try {
+ AppManualReaderClient.openManual(
+ "c-geo",
+ "c:geo-live-map",
+ activity,
+ "http://cgeo.carnero.cc/manual/");
+ } catch (Exception e) {
+ // nothing
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java b/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java
new file mode 100644
index 0000000..1895744
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/ActivityImpl.java
@@ -0,0 +1,33 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapActivity implementations.
+ * @author rsudev
+ *
+ */
+public interface ActivityImpl {
+
+ Resources getResources();
+
+ Activity getActivity();
+
+ void superOnCreate(Bundle savedInstanceState);
+
+ void superOnResume();
+
+ void superOnDestroy();
+
+ boolean superOnCreateOptionsMenu(Menu menu);
+
+ boolean superOnPrepareOptionsMenu(Menu menu);
+
+ boolean superOnOptionsItemSelected(MenuItem item);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java
new file mode 100644
index 0000000..bdb8511
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/CacheOverlayItemImpl.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgCoord;
+
+/**
+ * Covers the common functions of the provider-specific
+ * CacheOverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface CacheOverlayItemImpl extends OverlayItemImpl {
+
+ public cgCoord getCoord();
+
+ public String getType();
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java b/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java
new file mode 100644
index 0000000..c6e80d4
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/GeoPointImpl.java
@@ -0,0 +1,15 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * GeoPoint implementations
+ * @author rsudev
+ *
+ */
+public interface GeoPointImpl {
+
+ int getLatitudeE6();
+
+ int getLongitudeE6();
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java b/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java
new file mode 100644
index 0000000..73eed1f
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/ItemizedOverlayImpl.java
@@ -0,0 +1,33 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.mapcommon.ItemizedOverlayBase;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines the common functions to access the provider-specific
+ * ItemizedOverlay implementation
+ * @author rsudev
+ *
+ */
+public interface ItemizedOverlayImpl {
+
+ ItemizedOverlayBase getBase();
+
+ void superPopulate();
+
+ void superSetLastFocusedItemIndex(int i);
+
+ Drawable superBoundCenter(Drawable markerIn);
+
+ Drawable superBoundCenterBottom(Drawable marker);
+
+ boolean superOnTap(int index);
+
+ void superDraw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void superDrawOverlayBitmap(Canvas canvas, Point drawPosition, MapProjectionImpl projection,
+ byte drawZoomLevel);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java b/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java
new file mode 100644
index 0000000..dbdb955
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapControllerImpl.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Defines the common functions of the provider-specific
+ * MapController implementations
+ * @author rsudev
+ *
+ */
+public interface MapControllerImpl {
+
+ void setZoom(int mapzoom);
+
+ void setCenter(GeoPointImpl geoPoint);
+
+ void animateTo(GeoPointImpl geoPoint);
+
+ void zoomToSpan(int latSpanE6, int lonSpanE6);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapFactory.java b/src/cgeo/geocaching/mapinterfaces/MapFactory.java
new file mode 100644
index 0000000..fe09626
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapFactory.java
@@ -0,0 +1,30 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.content.Context;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+
+/**
+ * Defines functions of a factory class to get implementation specific objects
+ * (GeoPoints, OverlayItems, ...)
+ * @author rsudev
+ *
+ */
+public interface MapFactory {
+
+ public Class getMapClass();
+
+ public int getMapViewId();
+
+ public int getMapLayoutId();
+
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6);
+
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn);
+
+ CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type);
+
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context,
+ cgUser userOne);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java b/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java
new file mode 100644
index 0000000..10d36ee
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapProjectionImpl.java
@@ -0,0 +1,17 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.Point;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapProjection implementations
+ * @author rsudev
+ *
+ */
+public interface MapProjectionImpl {
+
+ Object getImpl();
+
+ void toPixels(GeoPointImpl leftGeo, Point left);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java b/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java
new file mode 100644
index 0000000..651b39f
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/MapViewImpl.java
@@ -0,0 +1,64 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * Defines common functions of the provider-specific
+ * MapView implementations
+ * @author rsudev
+ *
+ */
+public interface MapViewImpl {
+
+ void invalidate();
+
+ void setSatellite(boolean b);
+
+ void setBuiltInZoomControls(boolean b);
+
+ void displayZoomControls(boolean b);
+
+ void preLoad();
+
+ void clearOverlays();
+
+ void addOverlay(OverlayImpl ovl);
+
+ MapControllerImpl getMapController();
+
+ void destroyDrawingCache();
+
+ boolean isSatellite();
+
+ GeoPointImpl getMapViewCenter();
+
+ int getLatitudeSpan();
+
+ int getLongitudeSpan();
+
+ int getMapZoomLevel();
+
+ int getWidth();
+
+ int getHeight();
+
+ MapProjectionImpl getMapProjection();
+
+ Context getContext();
+
+ cgMapOverlay createAddMapOverlay(cgSettings settings, Context context,
+ Drawable drawable, boolean fromDetailIntent);
+
+ cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn);
+
+ boolean needsScaleOverlay();
+
+ void setBuiltinScale(boolean b);
+
+ void setMapSource(cgSettings settings);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayBase.java b/src/cgeo/geocaching/mapinterfaces/OverlayBase.java
new file mode 100644
index 0000000..59afb49
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayBase.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+
+/**
+ * Defines the base functions of the provider-independent
+ * Overlay implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayBase {
+
+ void draw(Canvas canvas, MapViewImpl mapView, boolean shadow);
+
+ void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ MapProjectionImpl projection, byte drawZoomLevel);
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java b/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java
new file mode 100644
index 0000000..6680b6a
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayImpl.java
@@ -0,0 +1,11 @@
+package cgeo.geocaching.mapinterfaces;
+
+/**
+ * Marker interface of the provider-specific
+ * Overlay implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayImpl {
+
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java
new file mode 100644
index 0000000..0f0297e
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/OverlayItemImpl.java
@@ -0,0 +1,18 @@
+package cgeo.geocaching.mapinterfaces;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Common functions of the provider-specific
+ * OverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface OverlayItemImpl {
+
+ public String getTitle();
+
+ public Drawable getMarker(int index);
+
+ public void setMarker(Drawable markerIn);
+}
diff --git a/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java b/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java
new file mode 100644
index 0000000..6b1532d
--- /dev/null
+++ b/src/cgeo/geocaching/mapinterfaces/UserOverlayItemImpl.java
@@ -0,0 +1,14 @@
+package cgeo.geocaching.mapinterfaces;
+
+import cgeo.geocaching.cgUser;
+
+/**
+ * Common functions of the provider-specific
+ * UserOverlayItem implementations
+ * @author rsudev
+ *
+ */
+public interface UserOverlayItemImpl extends OverlayItemImpl {
+
+ public cgUser getUser();
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java b/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java
new file mode 100644
index 0000000..a7665cb
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfCacheOverlay.java
@@ -0,0 +1,99 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+
+public class mfCacheOverlay extends ItemizedOverlay<mfCacheOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgMapOverlay base;
+
+ public mfCacheOverlay(cgSettings settingsIn, Context contextIn, Drawable markerIn, Boolean fromDetailIn) {
+ super(boundCenterBottom(markerIn));
+ base = new cgMapOverlay(settingsIn, this, contextIn, fromDetailIn);
+ }
+
+ @Override
+ public cgMapOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfCacheOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfCacheOverlayItem) 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 mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.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);
+ }
+
+}
+
diff --git a/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java b/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java
new file mode 100644
index 0000000..b6b7d62
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfCacheOverlayItem.java
@@ -0,0 +1,35 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.graphics.drawable.Drawable;
+
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+
+public class mfCacheOverlayItem extends OverlayItem implements CacheOverlayItemImpl {
+ private String cacheType = null;
+ private cgCoord coord;
+
+ public mfCacheOverlayItem(cgCoord coordinate, String type) {
+ super(new GeoPoint((int)(coordinate.latitude * 1e6), (int)(coordinate.longitude * 1e6)), coordinate.name, "");
+
+ this.cacheType = type;
+ this.coord = coordinate;
+ }
+
+ public cgCoord getCoord() {
+ return coord;
+ }
+
+ public String getType() {
+ return cacheType;
+ }
+
+ @Override
+ public Drawable getMarker(int index) {
+ return getMarker();
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfGeoPoint.java b/src/cgeo/geocaching/mapsforge/mfGeoPoint.java
new file mode 100644
index 0000000..1261887
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfGeoPoint.java
@@ -0,0 +1,12 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+
+public class mfGeoPoint extends GeoPoint implements GeoPointImpl {
+
+ public mfGeoPoint(int latitudeE6, int longitudeE6) {
+ super(latitudeE6, longitudeE6);
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapActivity.java b/src/cgeo/geocaching/mapsforge/mfMapActivity.java
new file mode 100644
index 0000000..b878def
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapActivity.java
@@ -0,0 +1,96 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.MapActivity;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import cgeo.geocaching.mapcommon.MapBase;
+import cgeo.geocaching.mapcommon.cgeomap;
+import cgeo.geocaching.mapinterfaces.ActivityImpl;
+
+
+public class mfMapActivity extends MapActivity implements ActivityImpl {
+
+ private MapBase mapBase;
+
+ public mfMapActivity() {
+ mapBase = new cgeomap(this);
+ }
+
+ @Override
+ public Activity getActivity() {
+ return this;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ mapBase.onCreate(icicle);
+ }
+
+ @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 superOnCreateOptionsMenu(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 boolean superOnPrepareOptionsMenu(Menu menu) {
+ return super.onPrepareOptionsMenu(menu);
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapController.java b/src/cgeo/geocaching/mapsforge/mfMapController.java
new file mode 100644
index 0000000..30f1c29
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapController.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapController;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+
+public class mfMapController implements MapControllerImpl {
+
+ private MapController mapController;
+
+ public mfMapController(MapController mapControllerIn) {
+ mapController = mapControllerIn;
+ }
+
+ @Override
+ public void animateTo(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setCenter(GeoPointImpl geoPoint) {
+ mapController.setCenter((GeoPoint)geoPoint);
+ }
+
+ @Override
+ public void setZoom(int mapzoom) {
+ mapController.setZoom(mapzoom);
+ }
+
+ @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);
+ }
+ }
+}
+
diff --git a/src/cgeo/geocaching/mapsforge/mfMapFactory.java b/src/cgeo/geocaching/mapsforge/mfMapFactory.java
new file mode 100644
index 0000000..2031187
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapFactory.java
@@ -0,0 +1,54 @@
+package cgeo.geocaching.mapsforge;
+
+import android.content.Context;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgCoord;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.CacheOverlayItemImpl;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapFactory;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class mfMapFactory implements MapFactory{
+
+ @Override
+ public Class getMapClass() {
+ return mfMapActivity.class;
+ }
+
+ @Override
+ public int getMapViewId() {
+ return R.id.mfmap;
+ }
+
+ @Override
+ public int getMapLayoutId() {
+ return R.layout.mfmap;
+ }
+
+ @Override
+ public GeoPointImpl getGeoPointBase(int latE6, int lonE6) {
+ return new mfGeoPoint(latE6, lonE6);
+ }
+
+ @Override
+ public OverlayImpl getOverlayBaseWrapper(OverlayBase ovlIn) {
+ mfOverlay baseOvl = new mfOverlay(ovlIn);
+ return baseOvl;
+ }
+
+ @Override
+ public CacheOverlayItemImpl getCacheOverlayItem(cgCoord coordinate, String type) {
+ mfCacheOverlayItem baseItem = new mfCacheOverlayItem(coordinate, type);
+ return baseItem;
+ }
+
+ @Override
+ public UserOverlayItemImpl getUserOverlayItemBase(Context context, cgUser userOne) {
+ mfUsersOverlayItem baseItem = new mfUsersOverlayItem(context, userOne);
+ return baseItem;
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfMapProjection.java b/src/cgeo/geocaching/mapsforge/mfMapProjection.java
new file mode 100644
index 0000000..7252b17
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapProjection.java
@@ -0,0 +1,28 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.Projection;
+
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import android.graphics.Point;
+
+public class mfMapProjection implements MapProjectionImpl {
+
+ private Projection projection;
+
+ public mfMapProjection(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/src/cgeo/geocaching/mapsforge/mfMapView.java b/src/cgeo/geocaching/mapsforge/mfMapView.java
new file mode 100644
index 0000000..a68e7c0
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfMapView.java
@@ -0,0 +1,159 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.MapViewMode;
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import cgeo.geocaching.cgSettings;
+import cgeo.geocaching.mapcommon.cgMapOverlay;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.GeoPointImpl;
+import cgeo.geocaching.mapinterfaces.MapControllerImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+public class mfMapView extends MapView implements MapViewImpl {
+
+ public mfMapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ try {
+ if (getMapZoomLevel() >= 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
+ getController().setZoom(22);
+ }
+
+ super.draw(canvas);
+ } catch (Exception e) {
+ Log.e(cgSettings.tag, "cgMapView.draw: " + e.toString());
+ }
+ }
+
+ @Override
+ public void displayZoomControls(boolean takeFocus) {
+ // nothing to do here
+ }
+
+ @Override
+ public MapControllerImpl getMapController() {
+ return new mfMapController(getController());
+ }
+
+ @Override
+ public GeoPointImpl getMapViewCenter() {
+ GeoPoint point = getMapCenter();
+ return new mfGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
+ }
+
+ @Override
+ public void addOverlay(OverlayImpl ovl) {
+ getOverlays().add((Overlay)ovl);
+ }
+
+ @Override
+ public void clearOverlays() {
+ getOverlays().clear();
+ }
+
+ @Override
+ public MapProjectionImpl getMapProjection() {
+ return new mfMapProjection(getProjection());
+ }
+
+ @Override
+ public cgMapOverlay createAddMapOverlay(cgSettings settings,
+ Context context, Drawable drawable, boolean fromDetailIntent) {
+
+ mfCacheOverlay ovl = new mfCacheOverlay(settings, context, drawable, fromDetailIntent);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public cgUsersOverlay createAddUsersOverlay(Context context, Drawable markerIn) {
+ mfUsersOverlay ovl = new mfUsersOverlay(context, markerIn);
+ getOverlays().add(ovl);
+ return ovl.getBase();
+ }
+
+ @Override
+ public int getLatitudeSpan() {
+
+ Projection projection = getProjection();
+
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(0, getHeight());
+
+ return Math.abs(high.getLatitudeE6() - low.getLatitudeE6());
+ }
+
+ @Override
+ public int getLongitudeSpan() {
+ Projection projection = getProjection();
+
+ GeoPoint low = projection.fromPixels(0, 0);
+ GeoPoint high = projection.fromPixels(getWidth(), 0);
+
+ return Math.abs(high.getLongitudeE6() - low.getLongitudeE6());
+ }
+
+ @Override
+ public boolean isSatellite() {
+ return false;
+ }
+
+ @Override
+ public void preLoad() {
+ // Nothing to do here
+ }
+
+ @Override
+ public void setSatellite(boolean b) {
+ // Nothing to do here
+ }
+
+ @Override
+ public int getMapZoomLevel() {
+ return getZoomLevel();
+ }
+
+ @Override
+ public boolean needsScaleOverlay() {
+ return false;
+ }
+
+ @Override
+ public void setBuiltinScale(boolean b) {
+ setScaleBar(b);
+ }
+
+ @Override
+ public void setMapSource(cgSettings settings) {
+
+ setMapViewMode(MapViewMode.MAPNIK_TILE_DOWNLOAD);
+
+ switch(settings.mapProvider) {
+ case mapsforgeMapnik:
+ // is default
+ break;
+ case mapsforgeOsmarender:
+ setMapViewMode(MapViewMode.OSMARENDER_TILE_DOWNLOAD);
+ break;
+ case mapsforgeOffline:
+ if (isValidMapFile(settings.getMapFile())) {
+ setMapViewMode(MapViewMode.CANVAS_RENDERER);
+ super.setMapFile(settings.getMapFile());
+ }
+ }
+ }
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfOverlay.java b/src/cgeo/geocaching/mapsforge/mfOverlay.java
new file mode 100644
index 0000000..e015307
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfOverlay.java
@@ -0,0 +1,26 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.Overlay;
+import org.mapsforge.android.maps.Projection;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import cgeo.geocaching.mapinterfaces.OverlayBase;
+import cgeo.geocaching.mapinterfaces.OverlayImpl;
+
+public class mfOverlay extends Overlay implements OverlayImpl {
+
+ private OverlayBase overlayBase;
+
+ public mfOverlay(OverlayBase overlayBaseIn) {
+ overlayBase = overlayBaseIn;
+ }
+
+ @Override
+ protected void drawOverlayBitmap(Canvas canvas, Point drawPosition,
+ Projection projection, byte drawZoomLevel) {
+
+ overlayBase.drawOverlayBitmap(canvas, drawPosition, new mfMapProjection(projection), drawZoomLevel);
+ }
+
+}
diff --git a/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java b/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java
new file mode 100644
index 0000000..64ccc37
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfUsersOverlay.java
@@ -0,0 +1,98 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.ItemizedOverlay;
+import org.mapsforge.android.maps.MapView;
+import org.mapsforge.android.maps.Projection;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.mapcommon.cgUsersOverlay;
+import cgeo.geocaching.mapinterfaces.ItemizedOverlayImpl;
+import cgeo.geocaching.mapinterfaces.MapProjectionImpl;
+import cgeo.geocaching.mapinterfaces.MapViewImpl;
+
+public class mfUsersOverlay extends ItemizedOverlay<mfUsersOverlayItem> implements ItemizedOverlayImpl {
+
+ private cgUsersOverlay base;
+
+ public mfUsersOverlay(Context contextIn, Drawable markerIn) {
+ super(boundCenter(markerIn));
+ base = new cgUsersOverlay(this, contextIn);
+ }
+
+ @Override
+ public cgUsersOverlay getBase() {
+ return base;
+ }
+
+ @Override
+ protected mfUsersOverlayItem createItem(int i) {
+ if (base == null)
+ return null;
+
+ return (mfUsersOverlayItem) 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 mfMapProjection(projection), drawZoomLevel);
+ }
+
+ @Override
+ public void superPopulate() {
+ populate();
+ }
+
+ @Override
+ public Drawable superBoundCenter(Drawable markerIn) {
+ return super.boundCenter(markerIn);
+ }
+
+ @Override
+ public Drawable superBoundCenterBottom(Drawable marker) {
+ return super.boundCenterBottom(marker);
+ }
+
+ @Override
+ public void superSetLastFocusedItemIndex(int i) {
+ // Nothing to do here
+ }
+
+ @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);
+ }
+
+} \ No newline at end of file
diff --git a/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java b/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java
new file mode 100644
index 0000000..a38a0a6
--- /dev/null
+++ b/src/cgeo/geocaching/mapsforge/mfUsersOverlayItem.java
@@ -0,0 +1,43 @@
+package cgeo.geocaching.mapsforge;
+
+import org.mapsforge.android.maps.GeoPoint;
+import org.mapsforge.android.maps.OverlayItem;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import cgeo.geocaching.R;
+import cgeo.geocaching.cgUser;
+import cgeo.geocaching.mapinterfaces.UserOverlayItemImpl;
+
+public class mfUsersOverlayItem extends OverlayItem implements UserOverlayItemImpl {
+ private Context context = null;
+ private cgUser user = null;
+
+ public mfUsersOverlayItem(Context contextIn, cgUser userIn) {
+ super(new GeoPoint((int)(userIn.latitude * 1e6), (int)(userIn.longitude * 1e6)), userIn.username, "");
+
+ context = contextIn;
+ user = userIn;
+ }
+
+ @Override
+ public Drawable getMarker(int state) {
+ Drawable marker = null;
+
+ if (user != null && user.located != null && user.located.getTime() >= (System.currentTimeMillis() - (20 * 60 * 1000))) {
+ marker = context.getResources().getDrawable(R.drawable.user_location_active);
+ } else {
+ marker = context.getResources().getDrawable(R.drawable.user_location);
+ }
+
+ marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+ marker.setAlpha(190);
+ setMarker(marker);
+
+ return marker;
+ }
+
+ public cgUser getUser() {
+ return user;
+ }
+}
diff --git a/src/gnu/android/app/appmanualclient/AppManualReaderClient.java b/src/gnu/android/app/appmanualclient/AppManualReaderClient.java
new file mode 100644
index 0000000..02d9b32
--- /dev/null
+++ b/src/gnu/android/app/appmanualclient/AppManualReaderClient.java
@@ -0,0 +1,377 @@
+package gnu.android.app.appmanualclient;
+
+import java.util.List;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * The "App Manual Reader" client is a class to be used in applications which
+ * want to offer their users manuals through the gnu.android.appmanualreader
+ * application. Such applications do not need to include the whole
+ * "App Manual Reader" app but instead just have to include only this little
+ * package. This package then provides the mechanism to open suitable installed
+ * manuals. It does not include any manuals itself.
+ * <p>
+ *
+ * (c) 2011 Geocrasher (geocrasher@gmx.eu)
+ * <p>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ * <p>
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ * <p>
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ *
+ * @author Geocrasher
+ */
+public class AppManualReaderClient {
+
+ /**
+ * The URI scheme used to identify application manual URIs when flinging
+ * Intents around within an Android device, in the hope that there are
+ * activities registered which will handle such application manual URIs.
+ * Usually, there won't be just a single activity registered but instead
+ * many, depending on how many manuals are installed on an Android device.
+ */
+ public static final String URI_SCHEME_APPMANUAL = "appmanual";
+
+ /**
+ * Standardized topic for opening a manual at its beginning.
+ *
+ * @see #openManual(String, String, Context)
+ * @see #openManual(String, String, Context, String)
+ */
+ public static final String TOPIC_HOME = "andtw-home";
+ /**
+ * Standardized topic for opening the index of a manual.
+ *
+ * @see #openManual(String, String, Context)
+ * @see #openManual(String, String, Context, String)
+ */
+ public static final String TOPIC_INDEX = "andtw-index";
+ /**
+ * Standardized topic for opening a manual's "about" topic.
+ *
+ * @see #openManual(String, String, Context)
+ * @see #openManual(String, String, Context, String)
+ */
+ public static final String TOPIC_ABOUT_MANUAL = "andtw-about";
+
+ /**
+ * Convenience function to open a manual at a specific topic. See
+ * {@link #openManual(String, String, Context, String)} for a detailed
+ * description.
+ *
+ * @param manualIdentifier
+ * the identifier of the manual to open. This identifier must
+ * uniquely identify the manual as such, independent of the
+ * particular locale the manual is intended for.
+ * @param topic
+ * the topic to open. Please do not use spaces for topic names.
+ * With respect to the TiddlyWiki infrastructure used for manuals
+ * the topic needs to the tag of a (single) tiddler. This way
+ * manuals can be localized (especially their topic titles)
+ * without breaking an app's knowledge about topics. Some
+ * standardized topics are predefined, such as
+ * {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
+ * {@link #TOPIC_ABOUT_MANUAL}.
+ * @param context
+ * the context (usually an Activity) from which the manual is to
+ * be opened. In particular, this context is required to derive
+ * the proper current locale configuration in order to open
+ * appropriate localized manuals, if installed.
+ *
+ * @exception ActivityNotFoundException
+ * there is no suitable manual installed and all combinations
+ * of locale scope failed to activate any manual.
+ *
+ * @see #openManual(String, String, Context, String, Boolean)
+ */
+ public static void openManual(String manualIdentifier, String topic,
+ Context context) throws ActivityNotFoundException {
+ openManual(manualIdentifier, topic, context, null, false);
+ }
+
+ /**
+ * Convenience function to open a manual at a specific topic. See
+ * {@link #openManual(String, String, Context, String)} for a detailed
+ * description.
+ *
+ * @param manualIdentifier
+ * the identifier of the manual to open. This identifier must
+ * uniquely identify the manual as such, independent of the
+ * particular locale the manual is intended for.
+ * @param topic
+ * the topic to open. Please do not use spaces for topic names.
+ * With respect to the TiddlyWiki infrastructure used for manuals
+ * the topic needs to the tag of a (single) tiddler. This way
+ * manuals can be localized (especially their topic titles)
+ * without breaking an app's knowledge about topics. Some
+ * standardized topics are predefined, such as
+ * {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
+ * {@link #TOPIC_ABOUT_MANUAL}.
+ * @param context
+ * the context (usually an Activity) from which the manual is to
+ * be opened. In particular, this context is required to derive
+ * the proper current locale configuration in order to open
+ * appropriate localized manuals, if installed.
+ *
+ * @exception ActivityNotFoundException
+ * there is no suitable manual installed and all combinations
+ * of locale scope failed to activate any manual.
+ * @param fallbackUri
+ * either <code>null</code> or a fallback URI to be used in case
+ * the user has not installed any suitable manual.
+ *
+ * @see #openManual(String, String, Context, String, Boolean)
+ */
+ public static void openManual(String manualIdentifier, String topic,
+ Context context, String fallbackUri)
+ throws ActivityNotFoundException {
+ openManual(manualIdentifier, topic, context, fallbackUri, false);
+ }
+
+ /**
+ * Opens a manual at a specific topic. At least it tries to open a manual.
+ * As manuals are (usually) installed separately and we use late binding in
+ * form of implicit intents, a lot of things can go wrong.
+ *
+ * We use late binding and the intent architecture in particular as follows:
+ * first, we use our own URI scheme called "appmanual". Second, we use the
+ * host field as a unique manual identifier (such as "c-geo" for the app
+ * manuals for a map which must not be named by the powers that wanna be).
+ * Third, a localized manual is differentiated as a path with a single
+ * element in form of (in this precedence) "/lang_country_variant",
+ * "/lang__variant", "/lang_country", "/lang", or "/". Fourth, the topic to
+ * open is encoded as the a fragment "#topic=mytopic".
+ *
+ * In order to support localization, manuals can register themselves with
+ * different URIs.
+ *
+ * @param manualIdentifier
+ * the identifier of the manual to open. This identifier must
+ * uniquely identify the manual as such, independent of the
+ * particular locale the manual is intended for.
+ * @param topic
+ * the topic to open. Please do not use spaces for topic names.
+ * With respect to the TiddlyWiki infrastructure used for manuals
+ * the topic needs to the tag of a (single) tiddler. This way
+ * manuals can be localized (especially their topic titles)
+ * without breaking an app's knowledge about topics. Some
+ * standardized topics are predefined, such as
+ * {@link #TOPIC_HOME}, {@link #TOPIC_INDEX}, and
+ * {@link #TOPIC_ABOUT_MANUAL}.
+ * @param context
+ * the context (usually an Activity) from which the manual is to
+ * be opened. In particular, this context is required to derive
+ * the proper current locale configuration in order to open
+ * appropriate localized manuals, if installed.
+ * @param fallbackUri
+ * either <code>null</code> or a fallback URI to be used in case
+ * the user has not installed any suitable manual.
+ * @param contextAffinity
+ * if <code>true</code>, then we try to open the manual within
+ * the context, if possible. That is, if the package of the
+ * calling context also offers suitable activity registrations,
+ * then we will prefer them over any other registrations. If you
+ * don't know what this means, then you probably don't need this
+ * very special capability and should specify <code>false</code>
+ * for this parameter.
+ *
+ * @exception ActivityNotFoundException
+ * there is no suitable manual installed and all combinations
+ * of locale scope failed to activate any manual and no
+ * {@literal fallbackUri} was given.
+ */
+ public static void openManual(String manualIdentifier, String topic,
+ Context context, String fallbackUri, Boolean contextAffinity)
+ throws ActivityNotFoundException {
+ //
+ // The path of an "appmanual:" URI consists simply of the locale
+ // information. This allows manual packages to register themselves
+ // for both very specific locales as well as very broad ones.
+ //
+ String localePath = "/"
+ + context.getResources().getConfiguration().locale.toString();
+ //
+ // We later need this intent in order to try to launch an appropriate
+ // manual (respectively its manual viewer). And yes, we need to set
+ // the intent's category explicitly, even as we will later use
+ // startActivity(): if we don't do this, the proper activity won't be
+ // started albeit the filter almost matches. That dirty behavior (it is
+ // documented wrong) had cost me half a day until I noticed some
+ // informational log entry generated from the ActivityManager. Grrrr!
+ //
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ int defaultIntentFlags = intent.getFlags();
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ //
+ // Try to open the manual in the following order (subject to
+ // availability):
+ // 1. manualIdentifier_lang_country_variant (can also be
+ // manualIdentifier_lang__variant in some cases)
+ // 2. manualIdentifier_lang_country
+ // 3. manualIdentifier_lang
+ // 4. manualIdentifier
+ // Of course, manuals are free to register more than one Intent,
+ // in particular, the should register also the plain manualIdentifier
+ // as a suitable fallback strategy. Even when installing multiple
+ // manuals this doesn't matter, as the user then can choose which
+ // one to use on a single or permanent basis.
+ //
+ String logTag = "appmanualclient";
+ for ( ;; ) {
+ Uri uri = Uri.parse(URI_SCHEME_APPMANUAL + "://" + manualIdentifier
+ + localePath + "#topic='" + topic + "'");
+ // Note: we do not use a MIME type for this.
+ intent.setData(uri);
+ intent.setFlags(defaultIntentFlags);
+ if ( contextAffinity ) {
+ //
+ // What is happening here? Well, here we try something that we
+ // would like to call "package affinity activity resolving".
+ // Given an implicit(!) intent we try to figure out whether the
+ // package of the context which is trying to open the manual is
+ // able to resolve the intent. If this is the case, then we
+ // simply turn the implicit intent into an explicit(!) intent.
+ // We do this by setting the concrete module, that is: package
+ // name (eventually the one of the calling context) and class
+ // name within the package.
+ //
+ List<ResolveInfo> capableActivities = context
+ .getPackageManager()
+ .queryIntentActivityOptions(null, null, intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ int capables = capableActivities.size();
+ if ( capables > 1 ) {
+ for ( int idx = 0; idx < capables; ++idx ) {
+ ActivityInfo activityInfo = capableActivities.get(idx).activityInfo;
+ if ( activityInfo.packageName.contentEquals(context
+ .getPackageName()) ) {
+ intent.setClassName(activityInfo.packageName,
+ activityInfo.name);
+ //
+ // First match is okay, so we quit searching and
+ // continue with the usual attempt to start the
+ // activity. This should not fail, as we already
+ // found a match; yet the code is very forgiving in
+ // this respect and would just try another round
+ // with "downsized" locale requirements.
+ //
+ break;
+ }
+ }
+ }
+ // FIXME
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+ } else {
+ //
+ // No context affinity required, thus we need to set some flags:
+ //
+ // ...NEW_TASK: we want to start the manual reader activity as a
+ // separate
+ // task so that it can be kept open, yet in the background when
+ // returning to the application from which the manual was
+ // opened.
+ //
+ // ...SINGLE_TOP:
+ //
+ // ...RESET_TASK_IF_NEEDED: clear the manual reader activities
+ // down to the root activity. We've set the required
+ // ...CLEAR_WHEN_TASK_RESET above when opening the meta-manual
+ // with the context affinity.
+ //
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+ try {
+ if ( Log.isLoggable(logTag, Log.INFO) ) {
+ Log.i(logTag,
+ "Trying to activate manual: uri=" + uri.toString());
+ }
+ context.startActivity(intent);
+ //
+ // We could successfully activate the manual activity, so no
+ // further trials are required.
+ //
+ return;
+ } catch ( ActivityNotFoundException noActivity ) {
+ //
+ // Ensure that we switch back to implicit intent resolving for
+ // the next round.
+ //
+ intent.setComponent(null);
+ //
+ // As long as we still have some locale information, reduce it
+ // and try again a broader locale.
+ //
+ if ( localePath.length() > 1 ) {
+ int underscore = localePath.lastIndexOf('_');
+ if ( underscore > 0 ) {
+ localePath = localePath.substring(0, underscore);
+ //
+ // Handle the case where we have a locale variant, yet
+ // no locale country, thus two underscores in immediate
+ // series. Get rid of both.
+ //
+ if ( localePath.endsWith("_") ) {
+ localePath = localePath
+ .substring(0, underscore - 1);
+ }
+ } else {
+ //
+ // Ready for the last round: try without any locale
+ // modifiers.
+ //
+ localePath = "/";
+ }
+ } else {
+ //
+ // We've tried all combinations, so we've run out of them
+ // and bail out.
+ //
+ break;
+ }
+ }
+ //
+ // Okay, go for the next round, we've updated (or rather trimmed)
+ // the localeIdent, so let us try this.
+ //
+ }
+ //
+ // If we reach this code point then no suitable activity could be found
+ // and activated. In case the caller specified a fallback URI we will
+ // try to open that. As this will activate a suitable browser and this
+ // is an asynchronous activity we won't get back any negative results,
+ // such as 404's. Here we will only see such problems that prevented the
+ // start of a suitable browsing activity.
+ //
+ if ( fallbackUri != null ) {
+ intent = new Intent(Intent.ACTION_VIEW, Uri.parse(fallbackUri));
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ context.startActivity(intent);
+ }
+ //
+ // We could not activate any manual and there was no fallback URI to
+ // open, so we finally bail out unsuccessful with an exception.
+ //
+ throw new ActivityNotFoundException();
+ }
+}