diff options
Diffstat (limited to 'main')
71 files changed, 1137 insertions, 763 deletions
diff --git a/main/AndroidManifest.xml b/main/AndroidManifest.xml index 38f82a8..7836d07 100644 --- a/main/AndroidManifest.xml +++ b/main/AndroidManifest.xml @@ -445,7 +445,7 @@ </service> <activity - android:name=".connector.oc.OCDEAuthorizationActivity" + android:name=".connector.oc.OCAuthorizationActivity" android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:launchMode="singleTask" @@ -458,25 +458,7 @@ <data android:host="www.cgeo.org" - android:pathPrefix="/opencaching.de/" - android:scheme="callback" /> - </intent-filter> - </activity> - <activity - android:name=".connector.oc.OCPLAuthorizationActivity" - android:configChanges="keyboardHidden|orientation" - android:label="@string/app_name" - android:launchMode="singleTask" - android:windowSoftInputMode="stateHidden" > - <intent-filter> - <action android:name="android.intent.action.VIEW" /> - - <category android:name="android.intent.category.DEFAULT" /> - <category android:name="android.intent.category.BROWSABLE" /> - - <data - android:host="www.cgeo.org" - android:pathPrefix="/opencaching.pl/" + android:pathPrefix="/opencaching" android:scheme="callback" /> </intent-filter> </activity> diff --git a/main/build.xml b/main/build.xml index 257aaf3..a888e9b 100644 --- a/main/build.xml +++ b/main/build.xml @@ -112,6 +112,12 @@ <filter token="ocde.okapi.consumer.secret" value="${ocde.okapi.consumer.secret}"/> <filter token="ocpl.okapi.consumer.key" value="${ocpl.okapi.consumer.key}"/> <filter token="ocpl.okapi.consumer.secret" value="${ocpl.okapi.consumer.secret}"/> + <filter token="ocus.okapi.consumer.key" value="${ocus.okapi.consumer.key}"/> + <filter token="ocus.okapi.consumer.secret" value="${ocus.okapi.consumer.secret}"/> + <filter token="ocnl.okapi.consumer.key" value="${ocnl.okapi.consumer.key}"/> + <filter token="ocnl.okapi.consumer.secret" value="${ocnl.okapi.consumer.secret}"/> + <filter token="ocro.okapi.consumer.key" value="${ocro.okapi.consumer.key}"/> + <filter token="ocro.okapi.consumer.secret" value="${ocro.okapi.consumer.secret}"/> </filterset> </copy> </target> diff --git a/main/libs/rxjava-android-0.17.1-cgeo.jar b/main/libs/rxjava-android-0.17.5.jar Binary files differindex 1120cb5..42b7f16 100644 --- a/main/libs/rxjava-android-0.17.1-cgeo.jar +++ b/main/libs/rxjava-android-0.17.5.jar diff --git a/main/libs/rxjava-async-util-0.17.1-cgeo.jar b/main/libs/rxjava-async-util-0.17.5.jar Binary files differindex 644daab..bc71622 100644 --- a/main/libs/rxjava-async-util-0.17.1-cgeo.jar +++ b/main/libs/rxjava-async-util-0.17.5.jar diff --git a/main/libs/rxjava-core-0.17.1-cgeo.jar b/main/libs/rxjava-core-0.17.1-cgeo.jar Binary files differdeleted file mode 100644 index 75692f2..0000000 --- a/main/libs/rxjava-core-0.17.1-cgeo.jar +++ /dev/null diff --git a/main/libs/rxjava-core-0.17.5.jar b/main/libs/rxjava-core-0.17.5.jar Binary files differnew file mode 100644 index 0000000..5a54704 --- /dev/null +++ b/main/libs/rxjava-core-0.17.5.jar diff --git a/main/proguard-project.txt b/main/proguard-project.txt index bb064b9..5b606f5 100644 --- a/main/proguard-project.txt +++ b/main/proguard-project.txt @@ -48,10 +48,6 @@ # The backup agent class is not called from our code. -keep public class cgeo.geocaching.backup.CentralBackupAgent --keepclassmembers class cgeo.geocaching.compatibility.AndroidLevel8 { - public static <methods>; -} - # Butter knife view injection, see http://jakewharton.github.io/butterknife/ -dontwarn butterknife.internal.** -keep class **$$ViewInjector { *; } diff --git a/main/project/rawimages/c-geo_contacts_play_icon.png b/main/project/rawimages/c-geo_contacts_play_icon.png Binary files differnew file mode 100644 index 0000000..f2d66c0 --- /dev/null +++ b/main/project/rawimages/c-geo_contacts_play_icon.png diff --git a/main/res/values-cs/strings.xml b/main/res/values-cs/strings.xml index 0dd9155..dcf6e6b 100644 --- a/main/res/values-cs/strings.xml +++ b/main/res/values-cs/strings.xml @@ -364,6 +364,15 @@ <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Aktivace</string> <string name="init_oc_pl_description">Autorizovat c:geo pro hledání keší a přístup/filtrování tvých nalezených keší služby opencaching.pl.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Aktivace</string> + <string name="init_oc_nl_description">Autorizovat c:geo pro hledání keší a přístup/filtrování tvých nalezených keší služby opencaching.nl.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Aktivace</string> + <string name="init_oc_us_description">Autorizovat c:geo pro hledání keší a přístup/filtrování tvých nalezených keší služby opencaching.us.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Aktivace</string> + <string name="init_oc_ro_description">Autorizovat c:geo pro hledání keší a přístup/filtrování tvých nalezených keší služby opencaching.ro.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Aktivace</string> @@ -528,6 +537,9 @@ <string name="auth_dialog_completed_twitter">c:geo nyní může posílat zprávy na Tvůj Twitter.</string> <string name="auth_ocde">opencaching.de</string> <string name="auth_ocpl">opencaching.pl</string> + <string name="auth_ocnl">opencaching.nl</string> + <string name="auth_ocus">opencaching.us</string> + <string name="auth_ocro">opencaching.ro</string> <string name="auth_dialog_completed_oc">c:geo je nyní autorizováno pro interakce s %s.</string> <string name="cache_offline">Offline</string> <string name="cache_offline_refresh">Obnovit</string> diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml index 5e8b279..5be1fb6 100644 --- a/main/res/values-de/strings.xml +++ b/main/res/values-de/strings.xml @@ -364,6 +364,15 @@ <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Aktiviere</string> <string name="init_oc_pl_description">Autorisiere c:geo auf opencaching.pl zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Aktivieren</string> + <string name="init_oc_nl_description">Autorisiere c:geo auf opencaching.nl zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Aktivieren</string> + <string name="init_oc_us_description">Autorisiere c:geo auf opencaching.us zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Aktivieren</string> + <string name="init_oc_ro_description">Autorisiere c:geo auf opencaching.ro zuzugreifen um Caches zu suchen und nach deinen Funden zu filtern.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Aktivieren</string> diff --git a/main/res/values-fr/strings.xml b/main/res/values-fr/strings.xml index 3ac8a94..8c89df6 100644 --- a/main/res/values-fr/strings.xml +++ b/main/res/values-fr/strings.xml @@ -66,6 +66,7 @@ <string name="log_unarchived">Désarchivée</string> <string name="log_needs_archived">Nécessite d\'être archivée</string> <string name="log_discovered">Découverte</string> + <string name="log_reviewer">Note du relecteur</string> <string name="log_submit_for_review">Soumettre pour examen</string> <string name="log_retractlisting">Retirer l\'entrée</string> <string name="log_marked_missing">Marquer comme absente</string> @@ -363,6 +364,15 @@ <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Activer</string> <string name="init_oc_pl_description">Autoriser c:geo à utiliser opencaching.pl pour chercher des caches et accéder/filtrer vos caches trouvées.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Activer</string> + <string name="init_oc_nl_description">Autoriser c:geo à utiliser opencaching.nl pour chercher des caches et accéder/filtrer vos caches trouvées.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Activer</string> + <string name="init_oc_us_description">Autoriser c:geo à utiliser opencaching.us pour chercher des caches et accéder/filtrer vos caches trouvées.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Activer</string> + <string name="init_oc_ro_description">Autoriser c:geo à utiliser opencaching.ro pour chercher des caches et accéder/filtrer vos caches trouvées.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Activer</string> diff --git a/main/res/values-lt/strings.xml b/main/res/values-lt/strings.xml index 4c380d8..3375fc0 100644 --- a/main/res/values-lt/strings.xml +++ b/main/res/values-lt/strings.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!--Generated by crowdin.net--> <resources xmlns:tools="http://schemas.android.com/tools"> - <string name="app_name">c:geo</string> <string name="cache">Slėptuvė</string> <string name="detail">Informacija</string> <string name="search">Ieškoti</string> @@ -163,10 +162,10 @@ <string name="err_missing_device_name">Prieš registruodamiesi įveskite prietaiso pavadinimą.</string> <string name="err_favorite_failed">Nepavyko pakeisti mėgiamos slėptuvės statuso.</string> <string name="err_select_logimage_failed">Nepavyko pasirinkti nuotraukos slėptuvės įrašui.</string> - <string name="err_acquire_image_failed">Nepavyko priskirti nuotraukos.</string> + <string name="err_acquire_image_failed">Nepavyko pasiekti nuotraukos.</string> <string name="err_tb_display">c:geo negali parodyti norimo keliauninko. Ar tai tikrai keliauninkas?</string> <string name="err_tb_details_open">c:geo negali atidaryti keliauninko informacijos.</string> - <string name="err_tb_forgot_saw">c:geo pamiršo kokį keliauninką peržiūrėjote.</string> + <string name="err_tb_forgot_saw">c:geo pamiršo kokį keliauninką žiūrėjote.</string> <string name="err_tb_find">c:geo neranda keliauninko</string> <string name="err_tb_find_that">c:geo neranda šito keliauninko.</string> <string name="err_waypoint_cache_unknown">c:geo nežino, kokiai slėptuvei norite pridėti papildomą tašką.</string> @@ -186,7 +185,7 @@ <string name="err_search_address_forgot">c:geo pamiršo adresą kurio bandėte ieškoti.</string> <string name="err_parse_lat">c:geo nesupranta įvestos platumos.</string> <string name="err_parse_lon">c:geo nesupranta įvestos ilgumos.</string> - <string name="err_parse_dist">c:geo negali išanalizuoti atstumo.</string> + <string name="err_parse_dist">c:geo negali apdoroti atstumo.</string> <string name="err_parse_lat_lon">c:geo negali išanalizuoti platumos arba ilgumos.</string> <string name="warn_save_nothing">Čia nėra ko išsaugoti.</string> <string name="warn_no_cache_coord">Čia nėra slėptuvių su koordinatėmis.</string> @@ -240,8 +239,8 @@ <string name="caches_more_caches_no">Daugiau slėptuvių nėra</string> <string name="caches_more_caches_loading">Įkeliamos slėptuvės…</string> <string name="caches_more_caches_currently">dabar</string> - <string name="caches_downloading">Atsisiunčiamos slėptuvės…\nužtruks: </string> - <string name="caches_eta_ltm">Mažiau nei minutę</string> + <string name="caches_downloading">Atsisiunčiamos slėptuvės…\nUžtruks</string> + <string name="caches_eta_ltm">mažiau nei minutę</string> <string name="caches_store_offline">Išsaugoti slėptuves</string> <string name="caches_store_selected">Išsaugoti pasirinktas</string> <string name="caches_history">Istorija</string> @@ -338,17 +337,14 @@ <string name="settings_title_map">Žemėlapis</string> <string name="settings_title_map_data">Žemėlapio duomenys</string> <string name="settings_title_map_content">Žemėlapio turinys</string> - <string name="settings_title_gpx">GPX</string> <string name="settings_title_basicmembers">Parinktys baziniams nariams</string> <string name="settings_title_navigation">Navigacija</string> <string name="settings_title_system">Sistema</string> <string name="settings_title_navigation_menu">Navigacijos meniu</string> <string name="settings_category_browser">Naršyklė</string> - <string name="settings_category_geocaching">Geocaching</string> <string name="settings_category_social">Socialiniai tinklai</string> <string name="settings_category_logging_other">Kitos registravimo parinktys</string> <string name="settings_goto_url_button">daugiau …</string> - <string name="settings_title_gc">Geocaching.com</string> <string name="settings_title_ec">Extremcaching.com</string> <string name="settings_title_ox">Opencaching.com (Garmin)</string> <string name="settings_activate_gc">Aktyvuoti</string> @@ -362,9 +358,17 @@ <string name="init_oc">Opencaching.de</string> <string name="settings_activate_oc">Aktyvuoti</string> <string name="init_oc_de_description">Leiskite c:geo prisijungti prie opencaching.de tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> - <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Aktyvuoti</string> - <string name="init_oc_pl_description">Leisti c:geo prisijungti prie opencaching.pl tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> + <string name="init_oc_pl_description">Leiskite c:geo prisijungti prie opencaching.pl tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Aktyvuoti</string> + <string name="init_oc_nl_description">Leiskite c:geo prisijungti prie opencaching.nl tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Aktyvuoti</string> + <string name="init_oc_us_description">Leiskite c:geo prisijungti prie opencaching.us tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Aktyvuoti</string> + <string name="init_oc_ro_description">Leiskite c:geo prisijungti prie opencaching.ro tam, kad galėtumėt ieškoti slėptuvių ir prieiti/filtruoti rastas slėptuves.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Aktyvuoti</string> @@ -422,7 +426,7 @@ <string name="init_units">Imperiniai vienetai</string> <string name="init_summary_units">Vietoje metrinių vienetų naudoti imperinius vienetus</string> <string name="init_log_offline">Registravimas neprisijungus</string> - <string name="init_summary_log_offline">Įjungti registravimą neprisijungus (nebus rodomas įrašo langas, nebus įkeltas įrašas)</string> + <string name="init_summary_log_offline">Įjungti registravimą neprisijungus (nebus rodomas registravimo langas, nebus įkeltas įrašas)</string> <string name="init_choose_list">Klausti sąrašo</string> <string name="init_summary_choose_list">Klausti kuriame sąraše išsaugoti slėptuvę</string> <string name="init_livelist">Rodyti kryptį</string> @@ -528,7 +532,6 @@ <string name="auth_explain_long">Registracija bus pradėta paspaudus mygtuką \"Pradėti registraciją\". Šis procesas naršyklėje atvers %s puslapį. Prisijunkite prie savo paskyros ir leiskite <b>c:geo</b> ja naudotis.</string> <string name="auth_dialog_completed_twitter">c:geo priregistruota ir jai leidžiama rašyti Twitter paskyroje.</string> <string name="auth_ocde">opencaching.de</string> - <string name="auth_ocpl">opencaching.pl</string> <string name="auth_dialog_completed_oc">c:geo dabar registruota ir leidžiama naudotis %s.</string> <string name="cache_offline">Išsaugota</string> <string name="cache_offline_refresh">Naujinti</string> @@ -627,7 +630,6 @@ <string name="cache_menu_whereyougo">WhereYouGo</string> <string name="cache_menu_oruxmaps">OruxMaps</string> <string name="cache_menu_cachebeacon">Cache Beacon</string> - <string name="cache_menu_navigon">Navigon</string> <string name="cache_menu_pebble">Pebble</string> <string name="cache_status">Būsena</string> <string name="cache_status_offline_log">Įrašas išsaugotas</string> @@ -1095,15 +1097,13 @@ <string name="attribute_offset_cache_yes">Offset cache</string> <string name="attribute_offset_cache_no">No offset cache</string> <string name="quote">To make geocaching easier, to make users lazier.</string> - <string name="powered_by">carnero</string> <string name="support">Palaikymas: <a href="">support@cgeo.org</a></string> <string name="website">Tinklapis: <a href="">cgeo.org</a></string> <string name="facebook">Facebook: <a href="">c:geo page</a></string> <string name="twitter">Twitter: <a href="">@android_GC</a></string> <string name="nutshellmanual">Vadovas: <a href="">c:geo in a Nutshell</a></string> <string name="market">Android: <a href="">c:geo on Google Play</a></string> - <string name="about_twitter">Kaskart registruojant slėptuvę <b>c:geo</b> paskelbs nauja statusą Twitter\'yje.</string> - <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string> + <string name="about_twitter">Kaskart registruojant slėptuvę <b>c:geo</b> paskelbs nauja statusą Twitter paskyroje.</string> <string name="status_new_release" tools:ignore="UnusedResources">Galima nauja versija. \nSpauskite kad įdiegti.</string> <string name="status_new_nightly" tools:ignore="UnusedResources">Galima nauja naktinė versija.\nSpauskite kad įdiegti.</string> <string name="status_new_rc" tools:ignore="UnusedResources">Galima nauja versija. \nSpauskite kad įdiegti.</string> @@ -1132,8 +1132,8 @@ <item>1024 px</item> </string-array> <plurals name="caches_eta_mins"> - <item quantity="one">minutė</item> - <item quantity="few">minutės</item> + <item quantity="one">minutę</item> + <item quantity="few">minutes</item> <item quantity="other">minučių</item> </plurals> <plurals name="cache_counts"> diff --git a/main/res/values-nl/strings.xml b/main/res/values-nl/strings.xml index 71d3a0a..faa376b 100644 --- a/main/res/values-nl/strings.xml +++ b/main/res/values-nl/strings.xml @@ -78,9 +78,9 @@ <string name="log_saving">Log opslaan…</string> <string name="log_saving_and_uploading">Verzenden van log en uploaden foto…</string> <string name="log_clear">Wissen</string> - <string name="log_post">Verzenden log</string> - <string name="log_post_rate">Verzenden log & beoordeel</string> - <string name="log_post_no_rate">Verzenden log zonder beoordeling</string> + <string name="log_post">Verzend log</string> + <string name="log_post_rate">Verzend log & beoordeel</string> + <string name="log_post_no_rate">Verzend log zonder beoordeling</string> <string name="log_post_not_possible">Laden Log Pagina…</string> <string name="log_add">Toevoegen</string> <string name="log_rating">Beoordeling</string> @@ -364,6 +364,15 @@ <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Activeren</string> <string name="init_oc_pl_description">c:geo authoriseren met opencaching.pl om naar caches te zoeken en het filteren van gevonden caches.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Activeren</string> + <string name="init_oc_nl_description">c:geo Autoriseren met opencaching.nl naar caches te zoeken en je gevonden caches te benaderen/filteren.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Activeren</string> + <string name="init_oc_us_description">c:geo Autoriseren met opencaching.us naar caches te zoeken en je gevonden caches te benaderen/filteren.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Activeren</string> + <string name="init_oc_ro_description">c:geo Autoriseren met opencaching.ro naar caches te zoeken en je gevonden caches te benaderen/filteren.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Activeren</string> diff --git a/main/res/values-ro/strings.xml b/main/res/values-ro/strings.xml index ed4680b..20eade4 100644 --- a/main/res/values-ro/strings.xml +++ b/main/res/values-ro/strings.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <!--Generated by crowdin.net--> <resources xmlns:tools="http://schemas.android.com/tools"> + <string name="app_name">c:geo</string> <string name="cache">Cutie</string> <string name="detail">Detalii</string> <string name="search">Caută</string> @@ -335,14 +336,17 @@ <string name="settings_title_map">Hartă</string> <string name="settings_title_map_data">Configurare hărţi</string> <string name="settings_title_map_content">Informaţii afişate pe hartă</string> + <string name="settings_title_gpx">GPX</string> <string name="settings_title_basicmembers">Opţiuni pentru Basic Members</string> <string name="settings_title_navigation">Navigare</string> <string name="settings_title_system">Sistem</string> <string name="settings_title_navigation_menu">Meniu navigaţie</string> <string name="settings_category_browser">Browser</string> + <string name="settings_category_geocaching">Geocaching</string> <string name="settings_category_social">Social media</string> <string name="settings_category_logging_other">Alte opţiuni pentru jurnal</string> <string name="settings_goto_url_button">mai multe…</string> + <string name="settings_title_gc">Geocaching.com</string> <string name="settings_title_ec">Extremcaching.com</string> <string name="settings_title_ox">Opencaching.com (Garmin)</string> <string name="settings_activate_gc">Activează</string> @@ -356,8 +360,18 @@ <string name="init_oc">Opencaching.de</string> <string name="settings_activate_oc">Activează</string> <string name="init_oc_de_description">Autorizează c:geo pe opencaching.de pentru a putea căuta cutii şi a vedea/filtra cutiile găsite de tine.</string> + <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Activează</string> <string name="init_oc_pl_description">Autorizează c:geo pe opencaching.pl pentru a putea căuta cutii şi a vedea/filtra cutiile găsite de tine.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Activează</string> + <string name="init_oc_nl_description">Autorizează c:geo cu opencaching.nl pentru a putea căuta geocutii şi a putea accesa/filtra pe cele găsite de tine.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Activează</string> + <string name="init_oc_us_description">Autorizează c:geo cu opencaching.us pentru a putea căuta geocutii şi a putea accesa/filtra pe cele găsite de tine.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Activează</string> + <string name="init_oc_ro_description">Autorizează c:geo cu opencaching.ro pentru a putea căuta geocutii şi a putea accesa/filtra pe cele găsite de tine.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Activează</string> @@ -521,6 +535,9 @@ <string name="auth_explain_long">Apăsând \"Autorizează c:geo\" va începe procedura. Această procedură va deschide în browser pagina %s. Autentifică-te pe această pagină şi confirmă permisiunea pentru ca <b>c:geo</b> să aibe acces la contul tău. Aceasta este totul.</string> <string name="auth_dialog_completed_twitter">c:geo este acum autorizat să posteze pe Twitter.</string> <string name="auth_ocde">opencaching.de</string> + <string name="auth_ocpl">opencaching.pl</string> + <string name="auth_ocnl">opencaching.nl</string> + <string name="auth_ocro">opencaching.ro</string> <string name="auth_dialog_completed_oc">c:geo este acum autorizat să comunice cu %s.</string> <string name="cache_offline">Salvată</string> <string name="cache_offline_refresh">Împrospătează</string> @@ -619,6 +636,7 @@ <string name="cache_menu_whereyougo">WhereYouGo</string> <string name="cache_menu_oruxmaps">OruxMaps</string> <string name="cache_menu_cachebeacon">Cutie Baliză</string> + <string name="cache_menu_navigon">Navigon</string> <string name="cache_menu_pebble">Ceas \"Pebble\"</string> <string name="cache_status">Stare</string> <string name="cache_status_offline_log">Jurnal salvat</string> @@ -1094,6 +1112,7 @@ <string name="nutshellmanual">Manual: <a href="">c:geo într-o coajă de nucă</a></string> <string name="market">Android: <a href="">c:geo pe Google Play</a></string> <string name="about_twitter">Ar trebui ca <b>c:geo</b> să publice un statut nou pe Twitter de fiecare dată când scrii o însemnare pentru o geocutie?</string> + <string name="faq">FAQ: <a href="">faq.cgeo.org</a></string> <string name="status_new_release" tools:ignore="UnusedResources">A apărut o versiune nouă.\nApasă aici pentru a instala.</string> <string name="status_new_nightly" tools:ignore="UnusedResources">A apărut o nouă versiune zilnică.\nApasă aici pentru a instala.</string> <string name="status_new_rc" tools:ignore="UnusedResources">A apărut o un candidat pentru o versiune nouă.\nApasă aici pentru a instala.</string> diff --git a/main/res/values/changelog_master.xml b/main/res/values/changelog_master.xml index 1e3c3d4..572bfbf 100644 --- a/main/res/values/changelog_master.xml +++ b/main/res/values/changelog_master.xml @@ -2,5 +2,10 @@ <resources> <!-- changelog for the master branch --> <string name="changelog_master" translatable="false"> + <b>Next feature release:</b>\n + <b>New features:</b>\n + · Changed initial coordinate format for waypoints to MinDec\n + <b>Bugfixing:</b>\n + · Improved long click detection in lists\n </string> </resources> diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml index d231795..91b2c67 100644 --- a/main/res/values/preference_keys.xml +++ b/main/res/values/preference_keys.xml @@ -12,17 +12,27 @@ <string name="preference_screen_basicmembers">fakekey_basicmembers_screen</string> <string name="preference_screen_ocde">preference_screen_ocde</string> <string name="preference_screen_ocpl">preference_screen_ocpl</string> + <string name="preference_screen_ocnl">preference_screen_ocnl</string> + <string name="preference_screen_ocus">preference_screen_ocus</string> + <string name="preference_screen_ocro">preference_screen_ocro</string> <string name="preference_screen_ec">preference_screen_ec</string> + <string name="preference_screen_ox">preference_screen_ox</string> <string name="preference_screen_twitter">preference_screen_twitter</string> <string name="preference_screen_navigation_menu">fakekey_navigation_menu_screen</string> <string name="pref_fakekey_ocde_authorization">fakekey_ocde_authorization</string> <string name="pref_fakekey_ocpl_authorization">fakekey_ocpl_authorization</string> + <string name="pref_fakekey_ocnl_authorization">fakekey_ocnl_authorization</string> + <string name="pref_fakekey_ocus_authorization">fakekey_ocus_authorization</string> + <string name="pref_fakekey_ocro_authorization">fakekey_ocro_authorization</string> <string name="pref_fakekey_twitter_authorization">fakekey_twitter_authorization</string> <string name="pref_connectorGCActive">connectorGCActive</string> <string name="pref_username">username</string> <string name="pref_password">password</string> <string name="pref_connectorOCActive">connectorOCActive</string> <string name="pref_connectorOCPLActive">connectorOCPLActive</string> + <string name="pref_connectorOCNLActive">connectorOCNLActive</string> + <string name="pref_connectorOCUSActive">connectorOCUSActive</string> + <string name="pref_connectorOCROActive">connectorOCROActive</string> <string name="pref_ecusername">ecusername</string> <string name="pref_ecpassword">ecpassword</string> <string name="pref_connectorECActive">connectorECActive</string> @@ -131,9 +141,24 @@ <string name="pref_ocpl_tokenpublic">ocpl_tokenpublic</string> <string name="pref_temp_ocpl_token_secret">ocpl-temp-token-secret</string> <string name="pref_temp_ocpl_token_public">ocpl-temp-token-public</string> + <string name="pref_ocnl_tokensecret">ocnl_tokensecret</string> + <string name="pref_ocnl_tokenpublic">ocnl_tokenpublic</string> + <string name="pref_temp_ocnl_token_secret">ocnl-temp-token-secret</string> + <string name="pref_temp_ocnl_token_public">ocnl-temp-token-public</string> + <string name="pref_ocus_tokensecret">ocus_tokensecret</string> + <string name="pref_ocus_tokenpublic">ocus_tokenpublic</string> + <string name="pref_temp_ocus_token_secret">ocus-temp-token-secret</string> + <string name="pref_temp_ocus_token_public">ocus-temp-token-public</string> + <string name="pref_ocro_tokensecret">ocro_tokensecret</string> + <string name="pref_ocro_tokenpublic">ocro_tokenpublic</string> + <string name="pref_temp_ocro_token_secret">ocro-temp-token-secret</string> + <string name="pref_temp_ocro_token_public">ocro-temp-token-public</string> <string name="pref_fakekey_gc_website">fakekey_gc_website</string> <string name="pref_fakekey_ocde_website">fakekey_ocde_website</string> <string name="pref_fakekey_ocpl_website">fakekey_ocpl_website</string> + <string name="pref_fakekey_ocnl_website">fakekey_ocnl_website</string> + <string name="pref_fakekey_ocus_website">fakekey_ocus_website</string> + <string name="pref_fakekey_ocro_website">fakekey_ocro_website</string> <string name="pref_fakekey_ec_website">fakekey_ec_website</string> <string name="pref_fakekey_ox_website">fakekey_ox_website</string> <string name="pref_fakekey_gcvote_website">fakekey_gcvote_website</string> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 48cc323..62c3bbf 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -411,6 +411,15 @@ <string name="init_oc_pl">Opencaching.pl</string> <string name="settings_activate_oc_pl">Activate</string> <string name="init_oc_pl_description">Authorize c:geo with opencaching.pl to search for caches and access/filter your found caches.</string> + <string name="init_oc_nl">Opencaching.nl</string> + <string name="settings_activate_oc_nl">Activate</string> + <string name="init_oc_nl_description">Authorize c:geo with opencaching.nl to search for caches and access/filter your found caches.</string> + <string name="init_oc_us">Opencaching.us</string> + <string name="settings_activate_oc_us">Activate</string> + <string name="init_oc_us_description">Authorize c:geo with opencaching.us to search for caches and access/filter your found caches.</string> + <string name="init_oc_ro">Opencaching.ro</string> + <string name="settings_activate_oc_ro">Activate</string> + <string name="init_oc_ro_description">Authorize c:geo with opencaching.ro to search for caches and access/filter your found caches.</string> <string name="init_gcvote">GCvote.com</string> <string name="init_twitter">Twitter</string> <string name="settings_activate_twitter">Activate</string> @@ -425,6 +434,7 @@ <string name="init_login_popup_not_authorized">Not authorized</string> <string name="init_login_popup_invalid_timestamp">Local time invalid, adjust device time</string> <string name="init_login_popup_invalid_token">Authorization invalid, re-authorize</string> + <string name="settings_service_active">Active</string> <string name="init_signature">Signature</string> <string name="init_template_help">Placeholder strings like [NAME] will be expanded later when this template is used.</string> <string name="init_signature_template_button">Insert Template</string> @@ -583,6 +593,9 @@ <!-- auth opencaching --> <string name="auth_ocde">opencaching.de</string> <string name="auth_ocpl">opencaching.pl</string> + <string name="auth_ocnl">opencaching.nl</string> + <string name="auth_ocus">opencaching.us</string> + <string name="auth_ocro">opencaching.ro</string> <string name="auth_dialog_completed_oc">c:geo is now authorized to interact with %s.</string> <!-- cache --> @@ -1221,6 +1234,7 @@ <string name="status_new_rc" tools:ignore="UnusedResources">New release candidate available.\nClick to install.</string> <string name="status_geocaching_change" tools:ignore="UnusedResources">Recent changes on geocaching.com broke c:geo.\nWe are working on it, check again soon.</string> <string name="status_geocaching_livemap" tools:ignore="UnusedResources">Recent changes on geocaching.com broke the live map feature.\nWe are working on it, check again soon.</string> + <string name="status_geocaching_maintenance" tools:ignore="UnusedResources">geocaching.com is under maintenance.\nYou might run into various issues.</string> <string name="status_closeout_warning" tools:ignore="UnusedResources">You appear to be using a version of Android older than 2.1. Future releases of c:geo might no longer be available for your device.</string> <!-- text-to-speech for compass view --> diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml index 454574e..fb17fb8 100644 --- a/main/res/xml/preferences.xml +++ b/main/res/xml/preferences.xml @@ -132,6 +132,90 @@ android:title="@string/settings_open_website" /> </PreferenceCategory> </PreferenceScreen> + <PreferenceScreen + android:key="@string/preference_screen_ocnl" + android:title="@string/init_oc_nl" > + <PreferenceCategory android:title="@string/settings_settings" > + <CheckBoxPreference + android:defaultValue="false" + android:key="@string/pref_connectorOCNLActive" + android:title="@string/settings_activate_oc_nl" /> + + <cgeo.geocaching.settings.TextPreference + android:dependency="@string/pref_connectorOCNLActive" + android:layout="@layout/text_preference" + android:text="@string/init_oc_nl_description" /> + + <cgeo.geocaching.settings.OAuthPreference + android:dependency="@string/pref_connectorOCNLActive" + android:key="@string/pref_fakekey_ocnl_authorization" /> + </PreferenceCategory> + <PreferenceCategory android:title="@string/settings_information" > + <cgeo.geocaching.settings.CapabilitiesPreference + android:title="@string/settings_features" + cgeo:connector="OB" /> + + <Preference + android:key="@string/pref_fakekey_ocnl_website" + android:title="@string/settings_open_website" /> + </PreferenceCategory> + </PreferenceScreen> + <PreferenceScreen + android:key="@string/preference_screen_ocus" + android:title="@string/init_oc_us" > + <PreferenceCategory android:title="@string/settings_settings" > + <CheckBoxPreference + android:defaultValue="false" + android:key="@string/pref_connectorOCUSActive" + android:title="@string/settings_activate_oc_us" /> + + <cgeo.geocaching.settings.TextPreference + android:dependency="@string/pref_connectorOCUSActive" + android:layout="@layout/text_preference" + android:text="@string/init_oc_us_description" /> + + <cgeo.geocaching.settings.OAuthPreference + android:dependency="@string/pref_connectorOCUSActive" + android:key="@string/pref_fakekey_ocus_authorization" /> + </PreferenceCategory> + <PreferenceCategory android:title="@string/settings_information" > + <cgeo.geocaching.settings.CapabilitiesPreference + android:title="@string/settings_features" + cgeo:connector="OU" /> + + <Preference + android:key="@string/pref_fakekey_ocus_website" + android:title="@string/settings_open_website" /> + </PreferenceCategory> + </PreferenceScreen> + <PreferenceScreen + android:key="@string/preference_screen_ocro" + android:title="@string/init_oc_ro" > + <PreferenceCategory android:title="@string/settings_settings" > + <CheckBoxPreference + android:defaultValue="false" + android:key="@string/pref_connectorOCROActive" + android:title="@string/settings_activate_oc_ro" /> + + <cgeo.geocaching.settings.TextPreference + android:dependency="@string/pref_connectorOCROActive" + android:layout="@layout/text_preference" + android:text="@string/init_oc_ro_description" /> + + <cgeo.geocaching.settings.OAuthPreference + android:dependency="@string/pref_connectorOCROActive" + android:key="@string/pref_fakekey_ocro_authorization" /> + </PreferenceCategory> + <PreferenceCategory android:title="@string/settings_information" > + <cgeo.geocaching.settings.CapabilitiesPreference + android:title="@string/settings_features" + cgeo:connector="OR" /> + + <Preference + android:key="@string/pref_fakekey_ocro_website" + android:title="@string/settings_open_website" /> + </PreferenceCategory> + </PreferenceScreen> <PreferenceScreen android:title="@string/settings_title_ec" android:key="@string/preference_screen_ec"> <PreferenceCategory android:title="@string/settings_settings" > <CheckBoxPreference @@ -182,7 +266,7 @@ android:title="@string/settings_open_website" /> </PreferenceCategory> </PreferenceScreen> - <PreferenceScreen android:title="@string/settings_title_ox" > + <PreferenceScreen android:title="@string/settings_title_ox" android:key="@string/preference_screen_ox"> <PreferenceCategory android:title="@string/settings_settings" > <CheckBoxPreference android:defaultValue="false" diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java index 82543b0..683579f 100644 --- a/main/src/cgeo/geocaching/AbstractPopupActivity.java +++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java @@ -14,13 +14,12 @@ import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.CacheDetailsCreator; import cgeo.geocaching.ui.LoggingUI; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.lang3.StringUtils; import rx.Observable; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import rx.functions.Func0; -import rx.schedulers.Schedulers; import android.graphics.Rect; import android.os.Bundle; @@ -80,13 +79,13 @@ public abstract class AbstractPopupActivity extends AbstractActivity implements if (!cache.supportsGCVote()) { return; } - AndroidObservable.bindActivity(this, Observable.defer(new Func0<Observable<GCVoteRating>>() { + RxUtils.subscribeOnIOThenUI(Observable.defer(new Func0<Observable<GCVoteRating>>() { @Override public Observable<GCVoteRating> call() { final GCVoteRating rating = GCVote.getRating(cache.getGuid(), geocode); return rating != null ? Observable.just(rating) : Observable.<GCVoteRating>empty(); } - }).subscribeOn(Schedulers.io())).subscribe(new Action1<GCVoteRating>() { + }), new Action1<GCVoteRating>() { @Override public void call(final GCVoteRating rating) { cache.setRating(rating.getRating()); diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index e95d250..a8fa8ee 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -45,6 +45,7 @@ import cgeo.geocaching.utils.CryptUtils; import cgeo.geocaching.utils.ImageUtils; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; +import cgeo.geocaching.utils.RxUtils; import cgeo.geocaching.utils.SimpleCancellableHandler; import cgeo.geocaching.utils.SimpleHandler; import cgeo.geocaching.utils.TextUtils; @@ -61,7 +62,6 @@ import rx.Observer; import rx.Scheduler.Inner; import rx.Subscriber; import rx.Subscription; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import rx.schedulers.Schedulers; @@ -878,7 +878,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc view = (ScrollView) getLayoutInflater().inflate(R.layout.cachedetail_details_page, null); // Start loading preview map - AndroidObservable.bindActivity(CacheDetailActivity.this, previewMap.subscribeOn(Schedulers.io())).subscribe(new Action1<BitmapDrawable>() { + RxUtils.subscribeOnIOThenUI(previewMap, new Action1<BitmapDrawable>() { @Override public void call(final BitmapDrawable image) { final Bitmap bitmap = image.getBitmap(); @@ -1605,71 +1605,70 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } }); - AndroidObservable.bindActivity(this, producer.subscribeOn(Schedulers.io())) - .subscribe(new Observer<Spanned>() { - @Override - public void onCompleted() { - if (null != loadingIndicatorView) { - loadingIndicatorView.setVisibility(View.GONE); - } - } + RxUtils.subscribeOnIOThenUI(producer, new Observer<Spanned>() { + @Override + public void onCompleted() { + if (null != loadingIndicatorView) { + loadingIndicatorView.setVisibility(View.GONE); + } + } - @Override - public void onError(final Throwable throwable) { - showToast(res.getString(R.string.err_load_descr_failed)); - } + @Override + public void onError(final Throwable throwable) { + showToast(res.getString(R.string.err_load_descr_failed)); + } - @Override - public void onNext(final Spanned description) { - if (StringUtils.isNotBlank(descriptionString)) { - try { - descriptionView.setText(description, TextView.BufferType.SPANNABLE); - } catch (final Exception e) { - // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 - Log.e("Android bug setting text: ", e); - // remove the formatting by converting to a simple string - descriptionView.setText(description.toString()); - } - descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); - fixTextColor(descriptionString); - descriptionView.setVisibility(View.VISIBLE); - registerForContextMenu(descriptionView); + @Override + public void onNext(final Spanned description) { + if (StringUtils.isNotBlank(descriptionString)) { + try { + descriptionView.setText(description, TextView.BufferType.SPANNABLE); + } catch (final Exception e) { + // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 + Log.e("Android bug setting text: ", e); + // remove the formatting by converting to a simple string + descriptionView.setText(description.toString()); + } + descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); + fixTextColor(descriptionString); + descriptionView.setVisibility(View.VISIBLE); + registerForContextMenu(descriptionView); + } + } + + /** + * Handle caches with black font color in dark skin and white font color in light skin + * by changing background color of the view + * + * @param text + * to be checked + */ + private void fixTextColor(final String text) { + int backcolor; + if (Settings.isLightSkin()) { + backcolor = color.white; + + for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; } } + } else { + backcolor = color.black; - /** - * Handle caches with black font color in dark skin and white font color in light skin - * by changing background color of the view - * - * @param text - * to be checked - */ - private void fixTextColor(final String text) { - int backcolor; - if (Settings.isLightSkin()) { - backcolor = color.white; - - for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - descriptionView.setBackgroundResource(color.darker_gray); - return; - } - } - } else { - backcolor = color.black; - - for (final Pattern pattern : DARK_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - descriptionView.setBackgroundResource(color.darker_gray); - return; - } - } + for (final Pattern pattern : DARK_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; } - descriptionView.setBackgroundResource(backcolor); } - }); + } + descriptionView.setBackgroundResource(backcolor); + } + }); } private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> { diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java index 6b639e4..b2404d9 100644 --- a/main/src/cgeo/geocaching/CacheListActivity.java +++ b/main/src/cgeo/geocaching/CacheListActivity.java @@ -1179,11 +1179,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA @Override public void run() { - final long startTime = System.currentTimeMillis(); + long baseTime = System.currentTimeMillis(); final String deviceCode = StringUtils.defaultString(Settings.getWebDeviceCode()); final Parameters params = new Parameters("code", deviceCode); - while (!handler.isCancelled() && System.currentTimeMillis() - startTime < 3 * 60000) { // maximum: 3 minutes + while (!handler.isCancelled() && System.currentTimeMillis() - baseTime < 3 * 60000) { // maximum: 3 minutes // Download new code final HttpResponse responseFromWeb = Network.getRequest("http://send2.cgeo.org/read.html", params); @@ -1195,6 +1195,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA Geocache.storeCache(null, response, listIdLFW, false, null); handler.sendMessage(handler.obtainMessage(MSG_LOADED, response)); + baseTime = System.currentTimeMillis(); } else if ("RG".equals(response)) { //Server returned RG (registration) and this device no longer registered. Settings.setWebNameCode(null, null); diff --git a/main/src/cgeo/geocaching/CgeoApplication.java b/main/src/cgeo/geocaching/CgeoApplication.java index eda8420..09aee93 100644 --- a/main/src/cgeo/geocaching/CgeoApplication.java +++ b/main/src/cgeo/geocaching/CgeoApplication.java @@ -42,7 +42,7 @@ public class CgeoApplication extends Application { public synchronized Observable<IGeoData> geoDataObservable() { if (geoDataObservable == null) { - final ConnectableObservable<IGeoData> onDemand = GeoDataProvider.create(this).publish(); + final ConnectableObservable<IGeoData> onDemand = GeoDataProvider.create(this).replay(1); onDemand.subscribe(new Action1<IGeoData>() { @Override public void call(final IGeoData geoData) { @@ -56,7 +56,7 @@ public class CgeoApplication extends Application { public synchronized Observable<Float> directionObservable() { if (directionObservable == null) { - final ConnectableObservable<Float> onDemand = DirectionProvider.create(this).publish(); + final ConnectableObservable<Float> onDemand = DirectionProvider.create(this).replay(1); onDemand.subscribe(new Action1<Float>() { @Override public void call(final Float direction) { diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java index f627d7d..7e676b0 100644 --- a/main/src/cgeo/geocaching/DataStore.java +++ b/main/src/cgeo/geocaching/DataStore.java @@ -20,16 +20,16 @@ import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.dialog.Dialogs; import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MiscUtils; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import rx.functions.Func0; import rx.functions.Func1; -import rx.schedulers.Schedulers; import rx.util.async.Async; import android.app.Activity; @@ -393,7 +393,7 @@ public class DataStore { */ public static void moveDatabase(final Activity fromActivity) { final ProgressDialog dialog = ProgressDialog.show(fromActivity, fromActivity.getString(R.string.init_dbmove_dbmove), fromActivity.getString(R.string.init_dbmove_running), true, false); - AndroidObservable.bindActivity(fromActivity, Async.fromFunc0(new Func0<Boolean>() { + RxUtils.subscribeOnIOThenUI(Async.fromCallable(new Func0<Boolean>() { @Override public Boolean call() { if (!LocalStorage.isExternalStorageAvailable()) { @@ -418,7 +418,7 @@ public class DataStore { init(); return true; } - })).subscribeOn(Schedulers.io()).subscribe(new Action1<Boolean>() { + }), new Action1<Boolean>() { @Override public void call(final Boolean success) { dialog.dismiss(); @@ -1313,7 +1313,7 @@ public class DataStore { */ private static void removeOutdatedWaypointsOfCache(final @NonNull Geocache cache, final @NonNull Collection<String> remainingWaypointIds) { final String idList = StringUtils.join(remainingWaypointIds, ','); - database.delete(dbTableWaypoints, "geocode = ? AND _id NOT in (" + idList + ")", new String[] { cache.getGeocode() }); + database.delete(dbTableWaypoints, "geocode = ? AND _id NOT in (" + idList + ")", new String[]{cache.getGeocode()}); } /** @@ -1558,8 +1558,8 @@ public class DataStore { return new HashSet<Geocache>(); } - Set<Geocache> result = new HashSet<Geocache>(); - Set<String> remaining = new HashSet<String>(geocodes); + final Set<Geocache> result = new HashSet<Geocache>(); + final List<String> remaining = new LinkedList<String>(geocodes); if (loadFlags.contains(LoadFlag.LOAD_CACHE_BEFORE)) { for (String geocode : new HashSet<String>(remaining)) { @@ -1579,7 +1579,7 @@ public class DataStore { loadFlags.contains(LoadFlag.LOAD_INVENTORY) || loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - final Set<Geocache> cachesFromDB = loadCachesFromGeocodes(remaining, loadFlags); + final Collection<Geocache> cachesFromDB = loadCachesFromGeocodes(remaining, loadFlags); result.addAll(cachesFromDB); for (final Geocache cache : cachesFromDB) { remaining.remove(cache.getGeocode()); @@ -1605,15 +1605,11 @@ public class DataStore { /** * Load caches. * - * @param geocodes + * @param allGeocodes * @param loadFlags * @return Set of loaded caches. Never null. */ - private static Set<Geocache> loadCachesFromGeocodes(final Set<String> geocodes, final EnumSet<LoadFlag> loadFlags) { - if (CollectionUtils.isEmpty(geocodes)) { - return Collections.emptySet(); - } - + private static Collection<Geocache> loadCachesFromGeocodes(final List<String> allGeocodes, final EnumSet<LoadFlag> loadFlags) { // do not log the entire collection of geo codes to the debug log. This can be more than 100 KB of text for large lists! init(); @@ -1628,68 +1624,73 @@ public class DataStore { } query.append(" WHERE ").append(dbTableCaches).append('.'); - query.append(DataStore.whereGeocodeIn(geocodes)); - Cursor cursor = database.rawQuery(query.toString(), null); - try { - final Set<Geocache> caches = new HashSet<Geocache>(); - int logIndex = -1; + final String queryBegin = query.toString(); + final List<Geocache> result = new ArrayList<Geocache>(allGeocodes.size()); - while (cursor.moveToNext()) { - Geocache cache = DataStore.createCacheFromDatabaseContent(cursor); + for (List<String> geocodes: MiscUtils.buffer(allGeocodes, 50)) { + final Cursor cursor = database.rawQuery(queryBegin + DataStore.whereGeocodeIn(geocodes), null); + try { + final Set<Geocache> caches = new HashSet<Geocache>(); + int logIndex = -1; - if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { - cache.setAttributes(loadAttributes(cache.getGeocode())); - } + while (cursor.moveToNext()) { + final Geocache cache = DataStore.createCacheFromDatabaseContent(cursor); - if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { - final List<Waypoint> waypoints = loadWaypoints(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(waypoints)) { - cache.setWaypoints(waypoints, false); + if (loadFlags.contains(LoadFlag.LOAD_ATTRIBUTES)) { + cache.setAttributes(loadAttributes(cache.getGeocode())); } - } - if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { - final List<Image> spoilers = loadSpoilers(cache.getGeocode()); - cache.setSpoilers(spoilers); - } + if (loadFlags.contains(LoadFlag.LOAD_WAYPOINTS)) { + final List<Waypoint> waypoints = loadWaypoints(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(waypoints)) { + cache.setWaypoints(waypoints, false); + } + } - if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { - cache.setLogs(loadLogs(cache.getGeocode())); - final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); - if (MapUtils.isNotEmpty(logCounts)) { - cache.getLogCounts().clear(); - cache.getLogCounts().putAll(logCounts); + if (loadFlags.contains(LoadFlag.LOAD_SPOILERS)) { + final List<Image> spoilers = loadSpoilers(cache.getGeocode()); + cache.setSpoilers(spoilers); } - } - if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { - final List<Trackable> inventory = loadInventory(cache.getGeocode()); - if (CollectionUtils.isNotEmpty(inventory)) { - if (cache.getInventory() == null) { - cache.setInventory(new ArrayList<Trackable>()); - } else { - cache.getInventory().clear(); + if (loadFlags.contains(LoadFlag.LOAD_LOGS)) { + cache.setLogs(loadLogs(cache.getGeocode())); + final Map<LogType, Integer> logCounts = loadLogCounts(cache.getGeocode()); + if (MapUtils.isNotEmpty(logCounts)) { + cache.getLogCounts().clear(); + cache.getLogCounts().putAll(logCounts); } - cache.getInventory().addAll(inventory); } - } - if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { - if (logIndex < 0) { - logIndex = cursor.getColumnIndex("log"); + if (loadFlags.contains(LoadFlag.LOAD_INVENTORY)) { + final List<Trackable> inventory = loadInventory(cache.getGeocode()); + if (CollectionUtils.isNotEmpty(inventory)) { + if (cache.getInventory() == null) { + cache.setInventory(new ArrayList<Trackable>()); + } else { + cache.getInventory().clear(); + } + cache.getInventory().addAll(inventory); + } } - cache.setLogOffline(!cursor.isNull(logIndex)); - } - cache.addStorageLocation(StorageLocation.DATABASE); - cacheCache.putCacheInCache(cache); - caches.add(cache); + if (loadFlags.contains(LoadFlag.LOAD_OFFLINE_LOG)) { + if (logIndex < 0) { + logIndex = cursor.getColumnIndex("log"); + } + cache.setLogOffline(!cursor.isNull(logIndex)); + } + cache.addStorageLocation(StorageLocation.DATABASE); + cacheCache.putCacheInCache(cache); + + caches.add(cache); + } + result.addAll(caches); + } finally { + cursor.close(); } - return caches; - } finally { - cursor.close(); } + return result; } @@ -2892,7 +2893,9 @@ public class DataStore { for (int i = 0; i < WAYPOINT_COLUMNS.length; i++) { query.append(i > 0 ? ", " : "").append(dbTableWaypoints).append('.').append(WAYPOINT_COLUMNS[i]).append(' '); } - query.append(" FROM ").append(dbTableWaypoints).append(", ").append(dbTableCaches).append(" WHERE ").append(dbTableWaypoints).append(".geocode == ").append(dbTableCaches).append(".geocode and ").append(where); + query.append(" FROM ").append(dbTableWaypoints).append(", ").append(dbTableCaches).append(" WHERE ").append(dbTableWaypoints) + .append(".geocode == ").append(dbTableCaches).append(".geocode and ").append(where) + .append(" LIMIT " + (Settings.SHOW_WP_THRESHOLD_MAX * 2)); // Hardcoded limit to avoid memory overflow return cursorToColl(database.rawQuery(query.toString(), null), new HashSet<Waypoint>(), new Func1<Cursor, Waypoint>() { @Override diff --git a/main/src/cgeo/geocaching/Intents.java b/main/src/cgeo/geocaching/Intents.java index 5c969a1..a55c22a 100644 --- a/main/src/cgeo/geocaching/Intents.java +++ b/main/src/cgeo/geocaching/Intents.java @@ -33,4 +33,20 @@ public class Intents { private static final String PREFIX_ACTION = "cgeo.geocaching.intent.action."; public static final String ACTION_GEOCACHE = PREFIX_ACTION + "GEOCACHE"; public static final String ACTION_TRACKABLE = PREFIX_ACTION + "TRACKABLE"; + + private static final String PREFIX_OAUTH = "cgeo.geocaching.intent.oauth."; + public static final String EXTRA_OAUTH_HOST = PREFIX_OAUTH + "host"; + public static final String EXTRA_OAUTH_PATH_REQUEST = PREFIX_OAUTH + "request"; + public static final String EXTRA_OAUTH_PATH_AUTHORIZE = PREFIX_OAUTH + "authorize"; + public static final String EXTRA_OAUTH_PATH_ACCESS = PREFIX_OAUTH + "access"; + public static final String EXTRA_OAUTH_HTTPS = PREFIX_OAUTH + "https"; + public static final String EXTRA_OAUTH_CONSUMER_KEY = PREFIX_OAUTH + "ConsumerKey"; + public static final String EXTRA_OAUTH_CONSUMER_SECRET = PREFIX_OAUTH + "ConsumerSecret"; + public static final String EXTRA_OAUTH_CALLBACK = PREFIX_OAUTH + "callback"; + + public static final String EXTRA_OAUTH_TITLE_RES_ID = PREFIX_OAUTH + "titleresId"; + public static final String EXTRA_OAUTH_TEMP_TOKEN_KEY_PREF = PREFIX_OAUTH + "tempKeyPref"; + public static final String EXTRA_OAUTH_TEMP_TOKEN_SECRET_PREF = PREFIX_OAUTH + "tempSecretPref"; + public static final String EXTRA_OAUTH_TOKEN_PUBLIC_KEY = PREFIX_OAUTH + "publicTokenPref"; + public static final String EXTRA_OAUTH_TOKEN_SECRET_KEY = PREFIX_OAUTH + "secretTokenPref"; } diff --git a/main/src/cgeo/geocaching/MainActivity.java b/main/src/cgeo/geocaching/MainActivity.java index 3295d04..b82614b 100644 --- a/main/src/cgeo/geocaching/MainActivity.java +++ b/main/src/cgeo/geocaching/MainActivity.java @@ -21,6 +21,7 @@ import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.ui.dialog.Dialogs; import cgeo.geocaching.utils.DatabaseBackupUtils; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import cgeo.geocaching.utils.Version; import com.google.zxing.integration.android.IntentIntegrator; @@ -29,9 +30,7 @@ import org.apache.commons.lang3.StringUtils; import rx.Observable; import rx.Observable.OnSubscribe; import rx.Subscriber; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; -import rx.schedulers.Schedulers; import rx.subscriptions.Subscriptions; import android.app.AlertDialog; @@ -551,10 +550,9 @@ public class MainActivity extends AbstractActivity { subscriber.onError(e); } } - }).subscribeOn(Schedulers.io()); - AndroidObservable.bindActivity(MainActivity.this, address) - .onErrorResumeNext(Observable.from(geo.getCoords().toString())) - .subscribe(new Action1<String>() { + }); + RxUtils.subscribeOnIOThenUI(address.onErrorResumeNext(Observable.from(geo.getCoords().toString())), + new Action1<String>() { @Override public void call(final String address) { navLocation.setText(address); diff --git a/main/src/cgeo/geocaching/PocketQueryList.java b/main/src/cgeo/geocaching/PocketQueryList.java index e624808..e748b29 100644 --- a/main/src/cgeo/geocaching/PocketQueryList.java +++ b/main/src/cgeo/geocaching/PocketQueryList.java @@ -2,13 +2,12 @@ package cgeo.geocaching; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.collections4.CollectionUtils; import rx.Observable; import rx.Observable.OnSubscribe; import rx.Subscriber; -import rx.android.observables.AndroidObservable; -import rx.schedulers.Schedulers; import rx.functions.Action1; import android.app.Activity; @@ -46,13 +45,13 @@ public final class PocketQueryList { public static void promptForListSelection(final Activity activity, final Action1<PocketQueryList> runAfterwards) { final Dialog waitDialog = ProgressDialog.show(activity, activity.getString(R.string.search_pocket_title), activity.getString(R.string.search_pocket_loading), true, true); - AndroidObservable.bindActivity(activity, Observable.create(new OnSubscribe<List<PocketQueryList>>() { + RxUtils.subscribeOnIOThenUI(Observable.create(new OnSubscribe<List<PocketQueryList>>() { @Override public void call(final Subscriber<? super List<PocketQueryList>> subscriber) { subscriber.onNext(GCParser.searchPocketQueryList()); subscriber.onCompleted(); } - }).subscribeOn(Schedulers.io())).subscribe(new Action1<List<PocketQueryList>>() { + }), new Action1<List<PocketQueryList>>() { @Override public void call(final List<PocketQueryList> pocketQueryLists) { waitDialog.dismiss(); diff --git a/main/src/cgeo/geocaching/StatusFragment.java b/main/src/cgeo/geocaching/StatusFragment.java index 5229f1e..a59316f 100644 --- a/main/src/cgeo/geocaching/StatusFragment.java +++ b/main/src/cgeo/geocaching/StatusFragment.java @@ -3,9 +3,9 @@ package cgeo.geocaching; import cgeo.geocaching.network.StatusUpdater; import cgeo.geocaching.network.StatusUpdater.Status; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import rx.Subscription; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import android.content.Intent; @@ -30,7 +30,7 @@ public class StatusFragment extends Fragment { final ViewGroup statusGroup = (ViewGroup) inflater.inflate(R.layout.status, container, false); final ImageView statusIcon = (ImageView) statusGroup.findViewById(R.id.status_icon); final TextView statusMessage = (TextView) statusGroup.findViewById(R.id.status_message); - statusSubscription = AndroidObservable.bindFragment(this, StatusUpdater.latestStatus).subscribe(new Action1<Status>() { + statusSubscription = RxUtils.subscribeOnIOThenUI(StatusUpdater.latestStatus, new Action1<Status>() { @Override public void call(final Status status) { if (status == null) { diff --git a/main/src/cgeo/geocaching/TrackableActivity.java b/main/src/cgeo/geocaching/TrackableActivity.java index 11f19f5..a14a397 100644 --- a/main/src/cgeo/geocaching/TrackableActivity.java +++ b/main/src/cgeo/geocaching/TrackableActivity.java @@ -20,12 +20,12 @@ import cgeo.geocaching.ui.UserNameClickListener; import cgeo.geocaching.ui.logs.TrackableLogsViewCreator; import cgeo.geocaching.utils.HtmlUtils; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import cgeo.geocaching.utils.UnknownTagsHandler; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; -import rx.android.observables.AndroidObservable; import rx.android.observables.ViewObservable; import rx.functions.Action1; @@ -524,14 +524,12 @@ public class TrackableActivity extends AbstractViewPagerActivity<TrackableActivi } }); - AndroidObservable.bindActivity(TrackableActivity.this, - new HtmlImage(geocode, true, 0, false).fetchDrawable(trackable.getImage())) - .subscribe(new Action1<BitmapDrawable>() { - @Override - public void call(final BitmapDrawable bitmapDrawable) { - trackableImage.setImageDrawable(bitmapDrawable); - } - }); + RxUtils.subscribeThenUI(new HtmlImage(geocode, true, 0, false).fetchDrawable(trackable.getImage()), new Action1<BitmapDrawable>() { + @Override + public void call(final BitmapDrawable bitmapDrawable) { + trackableImage.setImageDrawable(bitmapDrawable); + } + }); imageView.addView(trackableImage); } diff --git a/main/src/cgeo/geocaching/activity/AbstractActivity.java b/main/src/cgeo/geocaching/activity/AbstractActivity.java index f57ae41..542dd05 100644 --- a/main/src/cgeo/geocaching/activity/AbstractActivity.java +++ b/main/src/cgeo/geocaching/activity/AbstractActivity.java @@ -4,10 +4,10 @@ import butterknife.ButterKnife; import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.R; -import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.network.Cookies; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.utils.ClipboardUtils; +import cgeo.geocaching.utils.EditUtils; import cgeo.geocaching.utils.HtmlUtils; import cgeo.geocaching.utils.TranslationUtils; @@ -86,11 +86,16 @@ public abstract class AbstractActivity extends FragmentActivity implements IAbst } protected static void disableSuggestions(final EditText edit) { - Compatibility.disableSuggestions(edit); + EditUtils.disableSuggestions(edit); } protected void restartActivity() { - Compatibility.restartActivity(this); + final Intent intent = getIntent(); + overridePendingTransition(0, 0); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + finish(); + overridePendingTransition(0, 0); + startActivity(intent); } @Override diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java deleted file mode 100644 index 1189ff5..0000000 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8.java +++ /dev/null @@ -1,41 +0,0 @@ -package cgeo.geocaching.compatibility; - -import cgeo.geocaching.utils.Log; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.backup.BackupManager; -import android.os.Environment; -import android.view.Surface; - -import java.io.File; - -@TargetApi(8) -public class AndroidLevel8 implements AndroidLevel8Interface { - - @Override - public void dataChanged(final String name) { - Log.i("Requesting settings backup with settings manager"); - BackupManager.dataChanged(name); - } - - @Override - public int getRotationOffset(final Activity activity) { - switch (activity.getWindowManager().getDefaultDisplay().getRotation()) { - case Surface.ROTATION_90: - return 90; - case Surface.ROTATION_180: - return 180; - case Surface.ROTATION_270: - return 270; - default: - return 0; - } - } - - @Override - public File getExternalPictureDir() { - return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES); - } -} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java deleted file mode 100644 index 6d5781f..0000000 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Emulation.java +++ /dev/null @@ -1,38 +0,0 @@ -package cgeo.geocaching.compatibility; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Environment; -import android.view.Display; - -import java.io.File; - -@TargetApi(value = 7) -public class AndroidLevel8Emulation implements AndroidLevel8Interface { - - @Override - public void dataChanged(final String name) { - // do nothing - } - - @Override - public int getRotationOffset(Activity activity) { - final Display display = activity.getWindowManager().getDefaultDisplay(); - - // the non deprecated method is available in API 8+ only, so we cannot deal better with this - @SuppressWarnings("deprecation") - final int rotation = display.getOrientation(); - - if (rotation == Configuration.ORIENTATION_LANDSCAPE) { - return 90; - } - return 0; - } - - @Override - public File getExternalPictureDir() { - // Use externalStorage/Pictures as default - return new File(Environment.getExternalStorageDirectory(), "Pictures"); - } -} diff --git a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java b/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java deleted file mode 100644 index 2ba3708..0000000 --- a/main/src/cgeo/geocaching/compatibility/AndroidLevel8Interface.java +++ /dev/null @@ -1,11 +0,0 @@ -package cgeo.geocaching.compatibility; - -import android.app.Activity; - -import java.io.File; - -public interface AndroidLevel8Interface { - public void dataChanged(final String name); - public int getRotationOffset(final Activity activity); - public File getExternalPictureDir(); -}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/compatibility/Compatibility.java b/main/src/cgeo/geocaching/compatibility/Compatibility.java index 31c9e31..a293cfd 100644 --- a/main/src/cgeo/geocaching/compatibility/Compatibility.java +++ b/main/src/cgeo/geocaching/compatibility/Compatibility.java @@ -1,89 +1,25 @@ package cgeo.geocaching.compatibility; -import cgeo.geocaching.activity.AbstractActivity; -import cgeo.geocaching.utils.AngleUtils; -import cgeo.geocaching.utils.Log; - -import org.apache.commons.lang3.reflect.MethodUtils; import org.eclipse.jdt.annotation.NonNull; import android.app.Activity; -import android.content.Intent; import android.graphics.Point; import android.os.Build; -import android.text.InputType; -import android.widget.EditText; - -import java.io.File; public final class Compatibility { private final static int sdkVersion = Build.VERSION.SDK_INT; - private final static boolean isLevel8 = sdkVersion >= 8; - private final static boolean isLevel5 = sdkVersion >= 5; - private final static AndroidLevel8Interface level8; private final static AndroidLevel11Interface level11; private final static AndroidLevel13Interface level13; private final static AndroidLevel19Interface level19; static { - level8 = isLevel8 ? new AndroidLevel8() : new AndroidLevel8Emulation(); level11 = sdkVersion >= 11 ? new AndroidLevel11() : new AndroidLevel11Emulation(); level13 = sdkVersion >= 13 ? new AndroidLevel13() : new AndroidLevel13Emulation(); level19 = sdkVersion >= 19 ? new AndroidLevel19() : new AndroidLevel19Emulation(); } - /** - * Add 90, 180 or 270 degrees to the given rotation. - * - * @param directionNowPre - * the direction in degrees before adjustment - * @param activity - * the activity whose rotation is used to adjust the direction - * @return the adjusted direction, in the [0, 360[ range - */ - public static float getDirectionNow(final float directionNowPre, final Activity activity) { - return AngleUtils.normalize(directionNowPre + level8.getRotationOffset(activity)); - } - - public static void dataChanged(final String name) { - level8.dataChanged(name); - } - - public static void disableSuggestions(EditText edit) { - if (isLevel5) { - edit.setInputType(edit.getInputType() - | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS - | InputType.TYPE_TEXT_VARIATION_FILTER); - } - else { - edit.setInputType(edit.getInputType() - | InputType.TYPE_TEXT_VARIATION_FILTER); - } - } - - private static void overridePendingTransition(final Activity activity, int enterAnim, int exitAnim) { - try { - MethodUtils.invokeMethod(activity, "overridePendingTransition", enterAnim, exitAnim); - } catch (Exception e) { - Log.e("cannot call overridePendingTransition", e); - } - } - - public static void restartActivity(AbstractActivity activity) { - final Intent intent = activity.getIntent(); - if (isLevel5) { - overridePendingTransition(activity, 0, 0); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - } - activity.finish(); - if (isLevel5) { - overridePendingTransition(activity, 0, 0); - } - activity.startActivity(intent); - } - public static void invalidateOptionsMenu(final Activity activity) { level11.invalidateOptionsMenu(activity); } @@ -96,10 +32,6 @@ public final class Compatibility { return level13.getDisplaySize(); } - public static File getExternalPictureDir() { - return level8.getExternalPictureDir(); - } - public static void importGpxFromStorageAccessFramework(final @NonNull Activity activity, int requestCodeImportGpx) { level19.importGpxFromStorageAccessFramework(activity, requestCodeImportGpx); } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 35eae81..1f23df8 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -50,11 +50,18 @@ public final class ConnectorFactory { new OCConnector("OpenCaching.IT", "www.opencaching.it", "OC"), new OCConnector("OpenCaching.JP", "www.opencaching.jp", "OJ"), new OCConnector("OpenCaching.NO/SE", "www.opencaching.se", "OS"), - new OCApiConnector("OpenCaching.NL", "www.opencaching.nl", "OB", "PdzU8jzIlcfMADXaYN8j", "CC BY-SA 3.0", ApiSupport.current), + new OCApiLiveConnector("opencaching.nl", "www.opencaching.nl", "OB", "CC BY-SA 3.0", + R.string.oc_nl_okapi_consumer_key, R.string.oc_nl_okapi_consumer_secret, + R.string.pref_connectorOCNLActive, R.string.pref_ocnl_tokenpublic, R.string.pref_ocnl_tokensecret, ApiSupport.current), new OCApiLiveConnector("opencaching.pl", "www.opencaching.pl", "OP", "CC BY-SA 3.0", R.string.oc_pl_okapi_consumer_key, R.string.oc_pl_okapi_consumer_secret, R.string.pref_connectorOCPLActive, R.string.pref_ocpl_tokenpublic, R.string.pref_ocpl_tokensecret, ApiSupport.current), - new OCApiConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA", "CC BY-NC-SA 2.5", ApiSupport.current), + new OCApiLiveConnector("opencaching.us", "www.opencaching.us", "OU", "CC BY-NC-SA 2.5", + R.string.oc_us_okapi_consumer_key, R.string.oc_us_okapi_consumer_secret, + R.string.pref_connectorOCUSActive, R.string.pref_ocus_tokenpublic, R.string.pref_ocus_tokensecret, ApiSupport.current), + new OCApiLiveConnector("opencaching.ro", "www.opencaching.ro", "OR", "CC BY-SA 3.0", + R.string.oc_ro_okapi_consumer_key, R.string.oc_ro_okapi_consumer_secret, + R.string.pref_connectorOCROActive, R.string.pref_ocro_tokenpublic, R.string.pref_ocro_tokensecret, ApiSupport.current), new OXConnector(), new GeocachingAustraliaConnector(), new GeopeitusConnector(), diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java index 06d6411..bf021b9 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java +++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java @@ -88,6 +88,13 @@ public class GCLoggingManager extends AbstractLoggingManager implements LoaderMa date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), log, trackableLogs); + if (postResult.left == StatusCode.NO_ERROR) { + if (logType == LogType.TEMP_DISABLE_LISTING) { + cache.setDisabled(true); + } else if (logType == LogType.ENABLE_LISTING) { + cache.setDisabled(false); + } + } return new LogResult(postResult.left, postResult.right); } catch (Exception e) { Log.e("GCLoggingManager.postLog", e); diff --git a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java index 934cc88..280069f 100644 --- a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java +++ b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java @@ -4,12 +4,10 @@ import cgeo.geocaching.R; import cgeo.geocaching.loaders.RecaptchaReceiver; import cgeo.geocaching.network.Network; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.io.IOUtils; - import rx.Observable; -import rx.android.observables.AndroidObservable; -import rx.schedulers.Schedulers; import rx.functions.Action1; import rx.functions.Func0; @@ -39,17 +37,36 @@ public class RecaptchaHandler extends Handler { } private void loadChallenge(final ImageView imageView, final View reloadButton) { - getCaptcha().subscribe(new Action1<Bitmap>() { + final Observable<Bitmap> captcha = Observable.defer(new Func0<Observable<? extends Bitmap>>() { + @Override + public Observable<? extends Bitmap> call() { + final String url = "http://www.google.com/recaptcha/api/image?c=" + recaptchaReceiver.getChallenge(); + final InputStream is = Network.getResponseStream(Network.getRequest(url)); + if (is != null) { + try { + final Bitmap img = BitmapFactory.decodeStream(is); + return Observable.from(img); + } catch (final Exception e) { + Log.e("RecaptchaHandler.getCaptcha", e); + return Observable.error(e); + } finally { + IOUtils.closeQuietly(is); + } + } + return Observable.empty(); + } + }); + RxUtils.subscribeOnIOThenUI(captcha, new Action1<Bitmap>() { @Override public void call(final Bitmap bitmap) { imageView.setImageBitmap(bitmap); } }, new Action1<Throwable>() { - @Override - public void call(final Throwable throwable) { - // Do nothing - } - }); + @Override + public void call(final Throwable throwable) { + // Do nothing + } + }); reloadButton.setEnabled(true); } @@ -88,27 +105,4 @@ public class RecaptchaHandler extends Handler { } } - private Observable<Bitmap> getCaptcha() { - return AndroidObservable.bindActivity(activity, - Observable.defer(new Func0<Observable<? extends Bitmap>>() { - @Override - public Observable<? extends Bitmap> call() { - final String url = "http://www.google.com/recaptcha/api/image?c=" + recaptchaReceiver.getChallenge(); - final InputStream is = Network.getResponseStream(Network.getRequest(url)); - if (is != null) { - try { - final Bitmap img = BitmapFactory.decodeStream(is); - return Observable.from(img); - } catch (final Exception e) { - Log.e("RecaptchaHandler.getCaptcha", e); - return Observable.error(e); - } finally { - IOUtils.closeQuietly(is); - } - } - return Observable.empty(); - } - }).subscribeOn(Schedulers.io())); - } - } diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java b/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java new file mode 100644 index 0000000..131ddad --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OCAuthParams.java @@ -0,0 +1,70 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.Intents; +import cgeo.geocaching.R; +import cgeo.geocaching.network.OAuthAuthorizationActivity.OAuthParameters; + +import org.eclipse.jdt.annotation.NonNull; + +import android.content.Intent; + +public class OCAuthParams extends OAuthParameters { + + public static final OCAuthParams OC_DE_AUTH_PARAMS = new OCAuthParams("www.opencaching.de", false, + R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret, "callback://www.cgeo.org/opencaching.de/", + R.string.auth_ocde, R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret, R.string.pref_temp_ocde_token_public, R.string.pref_temp_ocde_token_secret); + + public static final OCAuthParams OC_NL_AUTH_PARAMS = new OCAuthParams("www.opencaching.nl", false, + R.string.oc_nl_okapi_consumer_key, R.string.oc_nl_okapi_consumer_secret, "callback://www.cgeo.org/opencaching.nl/", + R.string.auth_ocnl, R.string.pref_ocnl_tokenpublic, R.string.pref_ocnl_tokensecret, R.string.pref_temp_ocnl_token_public, R.string.pref_temp_ocnl_token_secret); + + public static final OCAuthParams OC_PL_AUTH_PARAMS = new OCAuthParams("www.opencaching.pl", false, + R.string.oc_pl_okapi_consumer_key, R.string.oc_pl_okapi_consumer_secret, "callback://www.cgeo.org/opencaching.pl/", + R.string.auth_ocpl, R.string.pref_ocpl_tokenpublic, R.string.pref_ocpl_tokensecret, R.string.pref_temp_ocpl_token_public, R.string.pref_temp_ocpl_token_secret); + + public static final OCAuthParams OC_US_AUTH_PARAMS = new OCAuthParams("www.opencaching.us", false, + R.string.oc_us_okapi_consumer_key, R.string.oc_us_okapi_consumer_secret, "callback://www.cgeo.org/opencaching.us/", + R.string.auth_ocus, R.string.pref_ocus_tokenpublic, R.string.pref_ocus_tokensecret, R.string.pref_temp_ocus_token_public, R.string.pref_temp_ocus_token_secret); + + public static final OCAuthParams OC_RO_AUTH_PARAMS = new OCAuthParams("www.opencaching.ro", false, + R.string.oc_ro_okapi_consumer_key, R.string.oc_ro_okapi_consumer_secret, "callback://www.cgeo.org/opencaching.ro/", + R.string.auth_ocro, R.string.pref_ocro_tokenpublic, R.string.pref_ocro_tokensecret, R.string.pref_temp_ocro_token_public, R.string.pref_temp_ocro_token_secret); + + public final int authTitleResId; + public final int tokenPublicPrefKey; + public final int tokenSecretPrefKey; + public final int tempTokenPublicPrefKey; + public final int tempTokenSecretPrefKey; + + public OCAuthParams(@NonNull String host, boolean https, int consumerKeyResId, int consumerSecretResId, @NonNull String callback, + int authTitleResId, int tokenPublicPrefKey, int tokenSecretPrefKey, int tempTokePublicPrefKey, int tempTokenSecretPrefKey) { + super(host, "/okapi/services/oauth/request_token", + "/okapi/services/oauth/authorize", + "/okapi/services/oauth/access_token", + https, + CgeoApplication.getInstance().getString(consumerKeyResId), + CgeoApplication.getInstance().getString(consumerSecretResId), + callback); + this.authTitleResId = authTitleResId; + this.tokenPublicPrefKey = tokenPublicPrefKey; + this.tokenSecretPrefKey = tokenSecretPrefKey; + this.tempTokenPublicPrefKey = tempTokePublicPrefKey; + this.tempTokenSecretPrefKey = tempTokenSecretPrefKey; + } + + @Override + public void setOAuthExtras(Intent intent) { + super.setOAuthExtras(intent); + + if (intent != null) { + intent.putExtra(Intents.EXTRA_OAUTH_TITLE_RES_ID, authTitleResId); + intent.putExtra(Intents.EXTRA_OAUTH_TOKEN_PUBLIC_KEY, tokenPublicPrefKey); + intent.putExtra(Intents.EXTRA_OAUTH_TOKEN_SECRET_KEY, tokenSecretPrefKey); + intent.putExtra(Intents.EXTRA_OAUTH_TEMP_TOKEN_KEY_PREF, tempTokenPublicPrefKey); + intent.putExtra(Intents.EXTRA_OAUTH_TEMP_TOKEN_SECRET_PREF, tempTokenSecretPrefKey); + } + } + + +} diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java index 19f4447..eb7e7a1 100644 --- a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java @@ -1,6 +1,6 @@ package cgeo.geocaching.connector.oc; -import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.Intents; import cgeo.geocaching.R; import cgeo.geocaching.connector.oc.OkapiError.OkapiErrors; import cgeo.geocaching.network.OAuthAuthorizationActivity; @@ -12,43 +12,51 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.eclipse.jdt.annotation.Nullable; -public abstract class OCAuthorizationActivity extends OAuthAuthorizationActivity { +import android.os.Bundle; - final IOCAuthParams authParams; +public class OCAuthorizationActivity extends OAuthAuthorizationActivity { - public OCAuthorizationActivity(IOCAuthParams authParams) { - super(authParams.getSite(), - "/okapi/services/oauth/request_token", - "/okapi/services/oauth/authorize", - "/okapi/services/oauth/access_token", - false, - CgeoApplication.getInstance().getResources().getString(authParams.getCKResId()), - CgeoApplication.getInstance().getResources().getString(authParams.getCSResId()), - authParams.getCallbackUri()); - this.authParams = authParams; + private int titleResId; + private int tokenPublicPrefKey; + private int tokenSecretPrefKey; + private int tempTokenPublicPrefKey; + private int tempTokenSecretPrefKey; + + @Override + public void onCreate(Bundle savedInstanceState) { + + Bundle extras = getIntent().getExtras(); + if (extras != null) { + titleResId = extras.getInt(Intents.EXTRA_OAUTH_TITLE_RES_ID); + tokenPublicPrefKey = extras.getInt(Intents.EXTRA_OAUTH_TOKEN_PUBLIC_KEY); + tokenSecretPrefKey = extras.getInt(Intents.EXTRA_OAUTH_TOKEN_SECRET_KEY); + tempTokenPublicPrefKey = extras.getInt(Intents.EXTRA_OAUTH_TEMP_TOKEN_KEY_PREF); + tempTokenSecretPrefKey = extras.getInt(Intents.EXTRA_OAUTH_TEMP_TOKEN_SECRET_PREF); + } + super.onCreate(savedInstanceState); } @Override protected ImmutablePair<String, String> getTempTokens() { - return Settings.getTokenPair(authParams.getTempTokenPublicPrefKey(), authParams.getTempTokenSecretPrefKey()); + return Settings.getTokenPair(tempTokenPublicPrefKey, tempTokenSecretPrefKey); } @Override protected void setTempTokens(@Nullable final String tokenPublic, @Nullable final String tokenSecret) { - Settings.setTokens(authParams.getTempTokenPublicPrefKey(), tokenPublic, authParams.getTempTokenSecretPrefKey(), tokenSecret); + Settings.setTokens(tempTokenPublicPrefKey, tokenPublic, tempTokenSecretPrefKey, tokenSecret); } @Override protected void setTokens(@Nullable final String tokenPublic, @Nullable final String tokenSecret, final boolean enable) { - Settings.setTokens(authParams.getTokenPublicPrefKey(), tokenPublic, authParams.getTokenSecretPrefKey(), tokenSecret); + Settings.setTokens(tokenPublicPrefKey, tokenPublic, tokenSecretPrefKey, tokenSecret); if (tokenPublic != null) { - Settings.setTokens(authParams.getTempTokenPublicPrefKey(), null, authParams.getTempTokenSecretPrefKey(), null); + Settings.setTokens(tempTokenPublicPrefKey, null, tempTokenSecretPrefKey, null); } } @Override protected String getAuthTitle() { - return res.getString(authParams.getAuthTitleResId()); + return res.getString(titleResId); } @Override @@ -67,5 +75,4 @@ public abstract class OCAuthorizationActivity extends OAuthAuthorizationActivity } return StringUtils.EMPTY; } - } diff --git a/main/src/cgeo/geocaching/connector/oc/OCDEAuthParams.java b/main/src/cgeo/geocaching/connector/oc/OCDEAuthParams.java deleted file mode 100644 index 17c1cb8..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCDEAuthParams.java +++ /dev/null @@ -1,51 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.R; - -public class OCDEAuthParams implements IOCAuthParams { - - @Override - public String getSite() { - return "www.opencaching.de"; - } - - @Override - public int getCKResId() { - return R.string.oc_de_okapi_consumer_key; - } - - @Override - public int getCSResId() { - return R.string.oc_de_okapi_consumer_secret; - } - - @Override - public int getAuthTitleResId() { - return R.string.auth_ocde; - } - - @Override - public int getTokenPublicPrefKey() { - return R.string.pref_ocde_tokenpublic; - } - - @Override - public int getTokenSecretPrefKey() { - return R.string.pref_ocde_tokensecret; - } - - @Override - public int getTempTokenPublicPrefKey() { - return R.string.pref_temp_ocde_token_public; - } - - @Override - public int getTempTokenSecretPrefKey() { - return R.string.pref_temp_ocde_token_secret; - } - - @Override - public String getCallbackUri() { - return "callback://www.cgeo.org/opencaching.de/"; - } -} diff --git a/main/src/cgeo/geocaching/connector/oc/OCDEAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCDEAuthorizationActivity.java deleted file mode 100644 index 1d2aa49..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCDEAuthorizationActivity.java +++ /dev/null @@ -1,8 +0,0 @@ -package cgeo.geocaching.connector.oc; - -public final class OCDEAuthorizationActivity extends OCAuthorizationActivity { - - public OCDEAuthorizationActivity() { - super(new OCDEAuthParams()); - } -} diff --git a/main/src/cgeo/geocaching/connector/oc/OCPLAuthParams.java b/main/src/cgeo/geocaching/connector/oc/OCPLAuthParams.java deleted file mode 100644 index dfe03e5..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCPLAuthParams.java +++ /dev/null @@ -1,51 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.R; - -public class OCPLAuthParams implements IOCAuthParams { - - @Override - public String getSite() { - return "www.opencaching.pl"; - } - - @Override - public int getCKResId() { - return R.string.oc_pl_okapi_consumer_key; - } - - @Override - public int getCSResId() { - return R.string.oc_pl_okapi_consumer_secret; - } - - @Override - public int getAuthTitleResId() { - return R.string.auth_ocpl; - } - - @Override - public int getTokenPublicPrefKey() { - return R.string.pref_ocpl_tokenpublic; - } - - @Override - public int getTokenSecretPrefKey() { - return R.string.pref_ocpl_tokensecret; - } - - @Override - public int getTempTokenPublicPrefKey() { - return R.string.pref_temp_ocpl_token_public; - } - - @Override - public int getTempTokenSecretPrefKey() { - return R.string.pref_temp_ocpl_token_secret; - } - - @Override - public String getCallbackUri() { - return "callback://www.cgeo.org/opencaching.pl/"; - } -} diff --git a/main/src/cgeo/geocaching/connector/oc/OCPLAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCPLAuthorizationActivity.java deleted file mode 100644 index 30ea150..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCPLAuthorizationActivity.java +++ /dev/null @@ -1,8 +0,0 @@ -package cgeo.geocaching.connector.oc; - -public final class OCPLAuthorizationActivity extends OCAuthorizationActivity { - - public OCPLAuthorizationActivity() { - super(new OCPLAuthParams()); - } -} diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index f06a42f..9f2f89e 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -42,6 +42,7 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.eclipse.jdt.annotation.NonNull; import rx.Scheduler; import rx.Subscription; import rx.functions.Action1; @@ -785,15 +786,16 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto /** * Restart the current activity if the map provider has changed, or change the map source if needed. * - * @param mapSource + * @param newSource * the new map source, which can be the same as the current one * @return true if a restart is needed, false otherwise */ - private boolean changeMapSource(final MapSource mapSource) { - final boolean restartRequired = !MapProviderFactory.isSameActivity(MapProviderFactory.getMapSource(currentSourceId), mapSource); + private boolean changeMapSource(@NonNull final MapSource newSource) { + final MapSource oldSource = MapProviderFactory.getMapSource(currentSourceId); + final boolean restartRequired = oldSource == null || !MapProviderFactory.isSameActivity(oldSource, newSource); - Settings.setMapSource(mapSource); - currentSourceId = mapSource.getNumericalId(); + Settings.setMapSource(newSource); + currentSourceId = newSource.getNumericalId(); if (restartRequired) { mapRestart(); diff --git a/main/src/cgeo/geocaching/maps/MapProviderFactory.java b/main/src/cgeo/geocaching/maps/MapProviderFactory.java index b928a1e..890274d 100644 --- a/main/src/cgeo/geocaching/maps/MapProviderFactory.java +++ b/main/src/cgeo/geocaching/maps/MapProviderFactory.java @@ -10,6 +10,8 @@ import cgeo.geocaching.settings.Settings; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; import android.view.Menu; import android.view.SubMenu; @@ -51,7 +53,7 @@ public class MapProviderFactory { return mapSources; } - public static boolean isSameActivity(final MapSource source1, final MapSource source2) { + public static boolean isSameActivity(@NonNull final MapSource source1, @NonNull final MapSource source2) { final MapProvider provider1 = source1.getMapProvider(); final MapProvider provider2 = source2.getMapProvider(); return provider1 == provider2 && provider1.isSameActivity(source1, source2); @@ -75,6 +77,7 @@ public class MapProviderFactory { * @param id the map source id * @return the map source, or <tt>null</tt> if <tt>id</tt> does not correspond to a registered map source */ + @Nullable public static MapSource getMapSource(int id) { for (MapSource mapSource : mapSources) { if (mapSource.getNumericalId() == id) { diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java index 5d713eb..8ee2ba7 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -10,9 +10,9 @@ import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.FileUtils; import cgeo.geocaching.utils.ImageUtils; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import ch.boye.httpclientandroidlib.HttpResponse; -import ch.boye.httpclientandroidlib.androidextra.Base64; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -42,9 +42,6 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -127,9 +124,8 @@ public class HtmlImage implements Html.ImageGetter { return drawable.toBlockingObservable().lastOrDefault(null); } - // Caches are loaded from disk on Schedulers.computation() to avoid using more threads than processors - // on the phone while decoding the image. Downloads happen on downloadScheduler, in parallel with image - // decoding. + // Caches are loaded from disk on a computation scheduler to avoid using more threads than cores while decoding + // the image. Downloads happen on downloadScheduler, in parallel with image decoding. public Observable<BitmapDrawable> fetchDrawable(final String url) { if (StringUtils.isBlank(url) || ImageUtils.containsPattern(url, BLOCKED)) { @@ -143,7 +139,7 @@ public class HtmlImage implements Html.ImageGetter { @Override public void call(final Subscriber<? super BitmapDrawable> subscriber) { subscription.add(subscriber); - subscriber.add(Schedulers.computation().schedule(new Action1<Inner>() { + subscriber.add(RxUtils.computationScheduler.schedule(new Action1<Inner>() { @Override public void call(final Inner inner) { final Pair<BitmapDrawable, Boolean> loaded = loadFromDisk(); @@ -172,14 +168,15 @@ public class HtmlImage implements Html.ImageGetter { return new ImmutablePair<BitmapDrawable, Boolean>(bitmap != null ? ImageUtils.scaleBitmapToFitDisplay(bitmap) : null, - loadResult.getRight()); + loadResult.getRight() + ); } private void downloadAndSave(final Subscriber<? super BitmapDrawable> subscriber) { final File file = LocalStorage.getStorageFile(pseudoGeocode, url, true, true); if (url.startsWith("data:image/")) { if (url.contains(";base64,")) { - saveBase64ToFile(url, file); + ImageUtils.decodeBase64ToFile(StringUtils.substringAfter(url, ";base64,"), file); } else { Log.e("HtmlImage.getDrawable: unable to decode non-base64 inline image"); subscriber.onCompleted(); @@ -195,7 +192,7 @@ public class HtmlImage implements Html.ImageGetter { if (onlySave) { subscriber.onCompleted(); } else { - Schedulers.computation().schedule(new Action1<Inner>() { + RxUtils.computationScheduler.schedule(new Action1<Inner>() { @Override public void call(final Inner inner) { final Pair<BitmapDrawable, Boolean> loaded = loadFromDisk(); @@ -254,20 +251,6 @@ public class HtmlImage implements Html.ImageGetter { return false; } - private static void saveBase64ToFile(final String url, final File file) { - // TODO: when we use SDK level 8 or above, we can use the streaming version of the base64 - // Android utilities. - OutputStream out = null; - try { - out = new FileOutputStream(file); - out.write(Base64.decode(StringUtils.substringAfter(url, ";base64,"), Base64.DEFAULT)); - } catch (final IOException e) { - Log.e("HtmlImage.saveBase64ToFile: cannot write file for decoded inline image", e); - } finally { - IOUtils.closeQuietly(out); - } - } - /** * Make a fresh copy of the file to reset its timestamp. On some storage, it is impossible * to modify the modified time after the fact, in which case a brand new file must be diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java index 35ab668..ec6ec4f 100644 --- a/main/src/cgeo/geocaching/network/Network.java +++ b/main/src/cgeo/geocaching/network/Network.java @@ -43,7 +43,6 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; -import java.nio.charset.Charset; public abstract class Network { @@ -54,13 +53,6 @@ public abstract class Network { private static final String PATTERN_PASSWORD = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+"; - /** - * charset for requests - * - * @see "http://docs.oracle.com/javase/1.5.0/docs/api/java/nio/charset/Charset.html" - */ - private static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); - private final static HttpParams clientParams = new BasicHttpParams(); static { @@ -145,7 +137,7 @@ public abstract class Network { final MultipartEntity entity = new MultipartEntity(); for (final NameValuePair param : params) { try { - entity.addPart(param.getName(), new StringBody(param.getValue(), CHARSET_UTF8)); + entity.addPart(param.getName(), new StringBody(param.getValue(), TextUtils.CHARSET_UTF8)); } catch (final UnsupportedEncodingException e) { Log.e("Network.postRequest: unsupported encoding for parameter " + param.getName(), e); return null; diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java index a5a2383..e74751b 100644 --- a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java @@ -2,8 +2,10 @@ package cgeo.geocaching.network; import butterknife.InjectView; +import cgeo.geocaching.Intents; import cgeo.geocaching.R; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.BundleUtils; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; @@ -39,14 +41,14 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity { private static final int STATUS_SUCCESS = 1; private static final int STATUS_ERROR_EXT_MSG = 2; - @NonNull final private String host; - @NonNull final private String pathRequest; - @NonNull final private String pathAuthorize; - @NonNull final private String pathAccess; - private final boolean https; - @NonNull final private String consumerKey; - @NonNull final private String consumerSecret; - @NonNull final private String callback; + @NonNull private String host = StringUtils.EMPTY; + @NonNull private String pathRequest = StringUtils.EMPTY; + @NonNull private String pathAuthorize = StringUtils.EMPTY; + @NonNull private String pathAccess = StringUtils.EMPTY; + private boolean https = false; + @NonNull private String consumerKey = StringUtils.EMPTY; + @NonNull private String consumerSecret = StringUtils.EMPTY; + @NonNull private String callback = StringUtils.EMPTY; private String OAtoken = null; private String OAtokenSecret = null; private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)"); @@ -56,6 +58,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity { @InjectView(R.id.auth_2) protected TextView auth_2; private ProgressDialog requestTokenDialog = null; private ProgressDialog changeTokensDialog = null; + private Handler requestTokenHandler = new Handler() { @Override @@ -81,6 +84,7 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity { } }; + private Handler changeTokensHandler = new Handler() { @Override @@ -100,29 +104,22 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity { } }; - public OAuthAuthorizationActivity - (@NonNull String host, - @NonNull String pathRequest, - @NonNull String pathAuthorize, - @NonNull String pathAccess, - boolean https, - @NonNull String consumerKey, - @NonNull String consumerSecret, - @NonNull String callback) { - this.host = host; - this.pathRequest = pathRequest; - this.pathAuthorize = pathAuthorize; - this.pathAccess = pathAccess; - this.https = https; - this.consumerKey = consumerKey; - this.consumerSecret = consumerSecret; - this.callback = callback; - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.authorization_activity, true); + Bundle extras = getIntent().getExtras(); + if (extras != null) { + host = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_HOST, host); + pathRequest = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_PATH_REQUEST, pathRequest); + pathAuthorize = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_PATH_AUTHORIZE, pathAuthorize); + pathAccess = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_PATH_ACCESS, pathAccess); + https = extras.getBoolean(Intents.EXTRA_OAUTH_HTTPS, https); + consumerKey = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_CONSUMER_KEY, consumerKey); + consumerSecret = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_CONSUMER_SECRET, consumerSecret); + callback = BundleUtils.getString(extras, Intents.EXTRA_OAUTH_CALLBACK, callback); + } + setTitle(getAuthTitle()); auth_1.setText(getAuthExplainShort()); @@ -355,4 +352,47 @@ public abstract class OAuthAuthorizationActivity extends AbstractActivity { protected String getAuthAuthorize() { return res.getString(R.string.auth_authorize, getAuthTitle()); } + + public static class OAuthParameters { + @NonNull public final String host; + @NonNull public final String pathRequest; + @NonNull public final String pathAuthorize; + @NonNull public final String pathAccess; + public final boolean https; + @NonNull public final String consumerKey; + @NonNull public final String consumerSecret; + @NonNull public final String callback; + + public OAuthParameters(@NonNull String host, + @NonNull String pathRequest, + @NonNull String pathAuthorize, + @NonNull String pathAccess, + boolean https, + @NonNull String consumerKey, + @NonNull String consumerSecret, + @NonNull String callback) { + this.host = host; + this.pathRequest = pathRequest; + this.pathAuthorize = pathAuthorize; + this.pathAccess = pathAccess; + this.https = https; + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + this.callback = callback; + } + + public void setOAuthExtras(Intent intent) { + if (intent != null) { + intent.putExtra(Intents.EXTRA_OAUTH_HOST, host); + intent.putExtra(Intents.EXTRA_OAUTH_PATH_REQUEST, pathRequest); + intent.putExtra(Intents.EXTRA_OAUTH_PATH_AUTHORIZE, pathAuthorize); + intent.putExtra(Intents.EXTRA_OAUTH_PATH_ACCESS, pathAccess); + intent.putExtra(Intents.EXTRA_OAUTH_HTTPS, https); + intent.putExtra(Intents.EXTRA_OAUTH_CONSUMER_KEY, consumerKey); + intent.putExtra(Intents.EXTRA_OAUTH_CONSUMER_SECRET, consumerSecret); + intent.putExtra(Intents.EXTRA_OAUTH_CALLBACK, callback); + } + } + + } } diff --git a/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java index 885ed48..45559f4 100644 --- a/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java +++ b/main/src/cgeo/geocaching/search/AutoCompleteAdapter.java @@ -1,7 +1,6 @@ package cgeo.geocaching.search; import org.apache.commons.lang3.StringUtils; - import rx.functions.Func1; import android.content.Context; @@ -36,7 +35,7 @@ public class AutoCompleteAdapter extends ArrayAdapter<String> { @Override public Filter getFilter() { - Filter filter = new Filter() { + return new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { @@ -67,6 +66,5 @@ public class AutoCompleteAdapter extends ArrayAdapter<String> { } } }; - return filter; } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/sensors/DirectionProvider.java b/main/src/cgeo/geocaching/sensors/DirectionProvider.java index 4f11a35..788d5bd 100644 --- a/main/src/cgeo/geocaching/sensors/DirectionProvider.java +++ b/main/src/cgeo/geocaching/sensors/DirectionProvider.java @@ -28,8 +28,8 @@ public class DirectionProvider { static class Listener implements SensorEventListener, StartableHandlerThread.Callback { private int count = 0; - private SensorManager sensorManager; + private SensorManager sensorManager; @Override public void onSensorChanged(final SensorEvent event) { subject.onNext(event.values[0]); @@ -71,10 +71,10 @@ public class DirectionProvider { private static final StartableHandlerThread handlerThread = new StartableHandlerThread("DirectionProvider thread", Process.THREAD_PRIORITY_BACKGROUND, new Listener()); + static { handlerThread.start(); } - static public Observable<Float> create(final Context context) { return Observable.create(new OnSubscribe<Float>() { @Override diff --git a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java index dd61cb1..c10cb48 100644 --- a/main/src/cgeo/geocaching/sensors/GeoDirHandler.java +++ b/main/src/cgeo/geocaching/sensors/GeoDirHandler.java @@ -16,7 +16,7 @@ import rx.subscriptions.CompositeSubscription; * GeoData and Direction handler. * <p> * To use this class, override {@link #updateGeoDir(IGeoData, float)}. You need to start the handler using - * {@link #start()}. A good place to do so might be the {@code onResume} method of the Activity. Stop the Handler + * {@link #start(int)}. A good place to do so might be the {@code onResume} method of the Activity. Stop the Handler * accordingly in {@code onPause}. * * The direction is always relative to the top of the device (natural direction), and that it must diff --git a/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java index 8a9d1c7..298270b 100644 --- a/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java +++ b/main/src/cgeo/geocaching/settings/AbstractCheckCredentialsPreference.java @@ -5,13 +5,12 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.network.Cookies; import cgeo.geocaching.ui.dialog.Dialogs; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import rx.functions.Func0; -import rx.schedulers.Schedulers; import rx.util.async.Async; import android.app.ProgressDialog; @@ -38,7 +37,7 @@ public abstract class AbstractCheckCredentialsPreference extends AbstractClickab protected abstract ImmutablePair<String, String> getCredentials(); - protected abstract ImmutablePair<StatusCode, Drawable> login(); + protected abstract ImmutablePair<StatusCode, ? extends Drawable> login(); private class LoginCheckClickListener implements OnPreferenceClickListener { final private SettingsActivity activity; @@ -65,14 +64,14 @@ public abstract class AbstractCheckCredentialsPreference extends AbstractClickab loginDialog.setCancelable(false); Cookies.clearCookies(); - AndroidObservable.bindActivity(activity, Async.start(new Func0<ImmutablePair<StatusCode, Drawable>>() { + RxUtils.subscribeOnIOThenUI(Async.start(new Func0<ImmutablePair<StatusCode, ? extends Drawable>>() { @Override - public ImmutablePair<StatusCode, Drawable> call() { + public ImmutablePair<StatusCode, ? extends Drawable> call() { return login(); } - }, Schedulers.io())).subscribe(new Action1<ImmutablePair<StatusCode, Drawable>>() { + }), new Action1<ImmutablePair<StatusCode, ? extends Drawable>>() { @Override - public void call(final ImmutablePair<StatusCode, Drawable> loginInfo) { + public void call(final ImmutablePair<StatusCode, ? extends Drawable> loginInfo) { loginDialog.dismiss(); if (loginInfo.getLeft() == StatusCode.NO_ERROR) { Dialogs.message(activity, R.string.init_login_popup, R.string.init_login_popup_ok, loginInfo.getRight()); @@ -81,7 +80,8 @@ public abstract class AbstractCheckCredentialsPreference extends AbstractClickab res.getString(R.string.init_login_popup_failed_reason) + " " + loginInfo.getLeft().getErrorString(res) - + "."); + + "." + ); } activity.initBasicMemberPreferences(); } diff --git a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java index e36e007..35df787 100644 --- a/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java +++ b/main/src/cgeo/geocaching/settings/CheckBoxWithPopupPreference.java @@ -18,6 +18,7 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference { private String text; private String url; private String urlButton; + private OnPreferenceChangeListener baseOnPrefChangeListener = null; public CheckBoxWithPopupPreference(Context context) { super(context); @@ -53,10 +54,17 @@ public class CheckBoxWithPopupPreference extends CheckBoxPreference { @Override protected View onCreateView(ViewGroup parent) { + if (baseOnPrefChangeListener == null) { + baseOnPrefChangeListener = getOnPreferenceChangeListener(); + } + // show dialog when checkbox enabled setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(final Preference preference, Object newValue) { + if (baseOnPrefChangeListener != null) { + baseOnPrefChangeListener.onPreferenceChange(preference, newValue); + } if (!(Boolean) newValue) { return true; } diff --git a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java index 8257fdd..2a05f47 100644 --- a/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java +++ b/main/src/cgeo/geocaching/settings/CheckGcCredentialsPreference.java @@ -25,14 +25,14 @@ public class CheckGcCredentialsPreference extends AbstractCheckCredentialsPrefer } @Override - protected ImmutablePair<StatusCode, Drawable> login() { + protected ImmutablePair<StatusCode, ? extends Drawable> login() { final StatusCode loginResult = GCLogin.getInstance().login(); switch (loginResult) { case NO_ERROR: GCLogin.detectGcCustomDate(); - return new ImmutablePair<StatusCode, Drawable>(StatusCode.NO_ERROR, GCLogin.getInstance().downloadAvatarAndGetMemberStatus()); + return ImmutablePair.of(StatusCode.NO_ERROR, GCLogin.getInstance().downloadAvatarAndGetMemberStatus()); default: - return new ImmutablePair<StatusCode, Drawable>(loginResult, null); + return ImmutablePair.of(loginResult, null); } } } diff --git a/main/src/cgeo/geocaching/settings/OAuthPreference.java b/main/src/cgeo/geocaching/settings/OAuthPreference.java index df77197..54f8023 100644 --- a/main/src/cgeo/geocaching/settings/OAuthPreference.java +++ b/main/src/cgeo/geocaching/settings/OAuthPreference.java @@ -2,8 +2,9 @@ package cgeo.geocaching.settings; import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.R; -import cgeo.geocaching.connector.oc.OCDEAuthorizationActivity; -import cgeo.geocaching.connector.oc.OCPLAuthorizationActivity; +import cgeo.geocaching.connector.oc.OCAuthParams; +import cgeo.geocaching.connector.oc.OCAuthorizationActivity; +import cgeo.geocaching.network.OAuthAuthorizationActivity.OAuthParameters; import cgeo.geocaching.twitter.TwitterAuthorizationActivity; import android.content.Context; @@ -16,17 +17,22 @@ public class OAuthPreference extends AbstractClickablePreference { private static final int NO_KEY = -1; private enum OAuthActivityMapping { - NONE(NO_KEY, null), - OCDE(R.string.pref_fakekey_ocde_authorization, OCDEAuthorizationActivity.class), - OCPL(R.string.pref_fakekey_ocpl_authorization, OCPLAuthorizationActivity.class), - TWITTER(R.string.pref_fakekey_twitter_authorization, TwitterAuthorizationActivity.class); + NONE(NO_KEY, null, null), + OCDE(R.string.pref_fakekey_ocde_authorization, OCAuthorizationActivity.class, OCAuthParams.OC_DE_AUTH_PARAMS), + OCPL(R.string.pref_fakekey_ocpl_authorization, OCAuthorizationActivity.class, OCAuthParams.OC_PL_AUTH_PARAMS), + OCNL(R.string.pref_fakekey_ocnl_authorization, OCAuthorizationActivity.class, OCAuthParams.OC_NL_AUTH_PARAMS), + OCUS(R.string.pref_fakekey_ocus_authorization, OCAuthorizationActivity.class, OCAuthParams.OC_US_AUTH_PARAMS), + OCRO(R.string.pref_fakekey_ocro_authorization, OCAuthorizationActivity.class, OCAuthParams.OC_RO_AUTH_PARAMS), + TWITTER(R.string.pref_fakekey_twitter_authorization, TwitterAuthorizationActivity.class, TwitterAuthorizationActivity.TWITTER_OAUTH_PARAMS); public final int prefKeyId; public final Class<?> authActivity; + public final OAuthParameters authParams; - OAuthActivityMapping(int prefKeyId, Class<?> clazz) { + OAuthActivityMapping(int prefKeyId, Class<?> authActivity, OAuthParameters authParams) { this.prefKeyId = prefKeyId; - this.authActivity = clazz; + this.authActivity = authActivity; + this.authParams = authParams; } } @@ -54,13 +60,14 @@ public class OAuthPreference extends AbstractClickablePreference { @Override protected OnPreferenceClickListener getOnPreferenceClickListener(final SettingsActivity activity) { - activity.setOcAuthTitle(oAuthMapping.prefKeyId); + activity.setAuthTitle(oAuthMapping.prefKeyId); return new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - if (oAuthMapping.authActivity != null) { + if (oAuthMapping.authActivity != null && oAuthMapping.authParams != null) { Intent authIntent = new Intent(preference.getContext(), oAuthMapping.authActivity); + oAuthMapping.authParams.setOAuthExtras(authIntent); activity.startActivityForResult(authIntent, oAuthMapping.prefKeyId); } diff --git a/main/src/cgeo/geocaching/settings/OCPreferenceKeys.java b/main/src/cgeo/geocaching/settings/OCPreferenceKeys.java new file mode 100644 index 0000000..96f49e2 --- /dev/null +++ b/main/src/cgeo/geocaching/settings/OCPreferenceKeys.java @@ -0,0 +1,89 @@ +package cgeo.geocaching.settings; + +import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.R; +import cgeo.geocaching.connector.oc.OCAuthParams; + +import android.util.SparseArray; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public enum OCPreferenceKeys { + + OC_DE("oc.de", R.string.pref_connectorOCActive, R.string.preference_screen_ocde, + R.string.pref_fakekey_ocde_authorization, R.string.pref_fakekey_ocde_website, + R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret, OCAuthParams.OC_DE_AUTH_PARAMS), + OC_PL("oc.pl", R.string.pref_connectorOCPLActive, R.string.preference_screen_ocpl, + R.string.pref_fakekey_ocpl_authorization, R.string.pref_fakekey_ocpl_website, + R.string.pref_ocpl_tokenpublic, R.string.pref_ocpl_tokensecret, OCAuthParams.OC_PL_AUTH_PARAMS), + OC_US("oc.us", R.string.pref_connectorOCUSActive, R.string.preference_screen_ocus, + R.string.pref_fakekey_ocus_authorization, R.string.pref_fakekey_ocus_website, + R.string.pref_ocus_tokenpublic, R.string.pref_ocus_tokensecret, OCAuthParams.OC_US_AUTH_PARAMS), + OC_NL("oc.nl", R.string.pref_connectorOCNLActive, R.string.preference_screen_ocnl, + R.string.pref_fakekey_ocnl_authorization, R.string.pref_fakekey_ocnl_website, + R.string.pref_ocnl_tokenpublic, R.string.pref_ocnl_tokensecret, OCAuthParams.OC_NL_AUTH_PARAMS), + OC_RO("oc.ro", R.string.pref_connectorOCROActive, R.string.preference_screen_ocro, + R.string.pref_fakekey_ocro_authorization, R.string.pref_fakekey_ocro_website, + R.string.pref_ocro_tokenpublic, R.string.pref_ocro_tokensecret, OCAuthParams.OC_RO_AUTH_PARAMS); + + + private OCPreferenceKeys(final String siteId, final int isActivePrefId, final int prefScreenId, final int websitePrefId, + final int authPrefId, final int publicTokenPrefId, final int privateTokenPrefId, final OCAuthParams authParams) { + this.siteId = siteId; + this.isActivePrefId = isActivePrefId; + this.prefScreenId = prefScreenId; + this.websitePrefId = websitePrefId; + this.authPrefId = authPrefId; + this.publicTokenPrefId = publicTokenPrefId; + this.privateTokenPrefId = privateTokenPrefId; + this.authParams = authParams; + } + + private static final SparseArray<OCPreferenceKeys> FIND_BY_ISACTIVE_ID; + private static final Map<String, OCPreferenceKeys> FIND_BY_ISACTIVE_KEY; + private static final SparseArray<OCPreferenceKeys> FIND_BY_AUTH_PREF_ID; + + static { + FIND_BY_ISACTIVE_ID = new SparseArray<OCPreferenceKeys>(values().length); + FIND_BY_AUTH_PREF_ID = new SparseArray<OCPreferenceKeys>(values().length); + Map<String, OCPreferenceKeys> byIsactiveKey = new HashMap<String, OCPreferenceKeys>(); + for (OCPreferenceKeys key : values()) { + FIND_BY_ISACTIVE_ID.put(key.isActivePrefId, key); + FIND_BY_AUTH_PREF_ID.put(key.authPrefId, key); + byIsactiveKey.put(CgeoApplication.getInstance().getString(key.isActivePrefId), key); + } + FIND_BY_ISACTIVE_KEY = Collections.unmodifiableMap(byIsactiveKey); + } + + public static boolean isOCPreference(final int prefId) { + return FIND_BY_ISACTIVE_ID.get(prefId) != null; + } + + public static boolean isOCPreference(final String prefKey) { + return FIND_BY_ISACTIVE_KEY.containsKey(prefKey); + } + + public static OCPreferenceKeys getById(final int prefId) { + return FIND_BY_ISACTIVE_ID.get(prefId); + } + + public static OCPreferenceKeys getByAuthId(final int authPrefId) { + return FIND_BY_AUTH_PREF_ID.get(authPrefId); + } + + public static OCPreferenceKeys getByKey(final String prefKey) { + return FIND_BY_ISACTIVE_KEY.get(prefKey); + } + + public final String siteId; + public final int isActivePrefId; + public final int prefScreenId; + public final int websitePrefId; + public final int authPrefId; + public final int publicTokenPrefId; + public final int privateTokenPrefId; + public final OCAuthParams authParams; + +} diff --git a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java index 49239bc..1b18438 100644 --- a/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java +++ b/main/src/cgeo/geocaching/settings/RegisterSend2CgeoPreference.java @@ -6,14 +6,13 @@ import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.dialog.Dialogs; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import ch.boye.httpclientandroidlib.HttpResponse; import org.apache.commons.lang3.StringUtils; import rx.Observable; -import rx.android.observables.AndroidObservable; import rx.functions.Action1; import rx.functions.Func0; -import rx.schedulers.Schedulers; import android.app.ProgressDialog; import android.content.Context; @@ -53,30 +52,29 @@ public class RegisterSend2CgeoPreference extends AbstractClickablePreference { activity.getString(R.string.init_sendToCgeo_registering), true); progressDialog.setCancelable(false); - AndroidObservable.bindActivity(activity, - Observable.defer(new Func0<Observable<Integer>>() { - @Override - public Observable<Integer> call() { - final String nam = StringUtils.defaultString(deviceName); - final String cod = StringUtils.defaultString(deviceCode); - - final Parameters params = new Parameters("name", nam, "code", cod); - HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params); - - if (response != null && response.getStatusLine().getStatusCode() == 200) { - //response was OK - final String[] strings = StringUtils.split(Network.getResponseData(response), ','); - Settings.setWebNameCode(nam, strings[0]); - try { - return Observable.from(Integer.parseInt(strings[1].trim())); - } catch (final Exception e) { - Log.e("RegisterSend2CgeoPreference", e); - } - } - - return Observable.empty(); + RxUtils.subscribeOnIOThenUI(Observable.defer(new Func0<Observable<Integer>>() { + @Override + public Observable<Integer> call() { + final String nam = StringUtils.defaultString(deviceName); + final String cod = StringUtils.defaultString(deviceCode); + + final Parameters params = new Parameters("name", nam, "code", cod); + HttpResponse response = Network.getRequest("http://send2.cgeo.org/auth.html", params); + + if (response != null && response.getStatusLine().getStatusCode() == 200) { + //response was OK + final String[] strings = StringUtils.split(Network.getResponseData(response), ','); + Settings.setWebNameCode(nam, strings[0]); + try { + return Observable.from(Integer.parseInt(strings[1].trim())); + } catch (final Exception e) { + Log.e("RegisterSend2CgeoPreference", e); } - }).firstOrDefault(0).subscribeOn(Schedulers.io())).subscribe(new Action1<Integer>() { + } + + return Observable.empty(); + } + }).firstOrDefault(0), new Action1<Integer>() { @Override public void call(final Integer pin) { progressDialog.dismiss(); diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java index 6c3c984..7a4dfdd 100644 --- a/main/src/cgeo/geocaching/settings/Settings.java +++ b/main/src/cgeo/geocaching/settings/Settings.java @@ -462,7 +462,7 @@ public class Settings { } public static CoordInputFormatEnum getCoordInputFormat() { - return CoordInputFormatEnum.fromInt(getInt(R.string.pref_coordinputformat, 0)); + return CoordInputFormatEnum.fromInt(getInt(R.string.pref_coordinputformat, CoordInputFormatEnum.Min.ordinal())); } public static void setCoordInputFormat(final CoordInputFormatEnum format) { @@ -599,6 +599,7 @@ public class Settings { putInt(R.string.pref_lastmaplon, mapViewCenter.getLongitudeE6()); } + @NonNull public static synchronized MapSource getMapSource() { if (mapSource != null) { return mapSource; diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java index 76f48e2..dc1a39d 100644 --- a/main/src/cgeo/geocaching/settings/SettingsActivity.java +++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java @@ -8,7 +8,6 @@ import cgeo.geocaching.SelectMapfileActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; -import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.gc.GCLogin; import cgeo.geocaching.files.SimpleDirChooser; @@ -21,6 +20,7 @@ import org.apache.commons.lang3.StringUtils; import org.openintents.intents.FileManagerIntents; import android.app.ProgressDialog; +import android.app.backup.BackupManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -111,7 +111,8 @@ public class SettingsActivity extends PreferenceActivity { @Override protected void onPause() { - Compatibility.dataChanged(getPackageName()); + Log.i("Requesting settings backup with settings manager"); + BackupManager.dataChanged(getPackageName()); super.onPause(); } @@ -153,16 +154,22 @@ public class SettingsActivity extends PreferenceActivity { } private void initServicePreferences() { - getPreference(R.string.pref_connectorOCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); - getPreference(R.string.pref_connectorOCPLActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); + for (OCPreferenceKeys key : OCPreferenceKeys.values()) { + getPreference(key.isActivePrefId).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); + setWebsite(key.websitePrefId, key.authParams.host); + setServiceScreenSummary(getPreferenceManager(), key.isActivePrefId); + } getPreference(R.string.pref_connectorGCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); + getPreference(R.string.pref_connectorOXActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); getPreference(R.string.pref_connectorECActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER); setWebsite(R.string.pref_fakekey_gc_website, GCConnector.getInstance().getHost()); - setWebsite(R.string.pref_fakekey_ocde_website, "opencaching.de"); - setWebsite(R.string.pref_fakekey_ocpl_website, "opencaching.pl"); + setWebsite(R.string.pref_fakekey_ox_website, "opencaching.com"); setWebsite(R.string.pref_fakekey_ec_website, "extremcaching.com"); setWebsite(R.string.pref_fakekey_gcvote_website, "gcvote.com"); setWebsite(R.string.pref_fakekey_sendtocgeo_website, "send2.cgeo.org"); + setServiceScreenSummary(getPreferenceManager(), R.string.pref_connectorGCActive); + setServiceScreenSummary(getPreferenceManager(), R.string.pref_connectorOXActive); + setServiceScreenSummary(getPreferenceManager(), R.string.pref_connectorECActive); } private void setWebsite(final int preferenceKey, final String host) { @@ -176,6 +183,36 @@ public class SettingsActivity extends PreferenceActivity { }); } + private static String getServiceSummary(boolean status) { + return status ? CgeoApplication.getInstance().getString(R.string.settings_service_active) : StringUtils.EMPTY; + } + + private static void setServiceScreenSummary(PreferenceManager preferenceManager, final int preferenceKey) { + + String summary = StringUtils.EMPTY; + + switch (preferenceKey) { + case R.string.pref_connectorGCActive: + summary = getServiceSummary(Settings.isGCConnectorActive()); + preferenceManager.findPreference(getKey(R.string.preference_screen_gc)).setSummary(summary); + break; + case R.string.pref_connectorOXActive: + summary = getServiceSummary(Settings.isOXConnectorActive()); + preferenceManager.findPreference(getKey(R.string.preference_screen_ox)).setSummary(summary); + break; + case R.string.pref_connectorECActive: + summary = getServiceSummary(Settings.isECConnectorActive()); + preferenceManager.findPreference(getKey(R.string.preference_screen_ec)).setSummary(summary); + break; + default: + if (OCPreferenceKeys.isOCPreference(preferenceKey)) { + OCPreferenceKeys prefKey = OCPreferenceKeys.getById(preferenceKey); + summary = getServiceSummary(Settings.isOCConnectorActive(prefKey.isActivePrefId)); + preferenceManager.findPreference(getKey(prefKey.prefScreenId)).setSummary(summary); + } + } + } + private static String getKey(final int prefKeyId) { return CgeoApplication.getInstance().getString(prefKeyId); } @@ -389,6 +426,10 @@ public class SettingsActivity extends PreferenceActivity { */ void redrawScreen(final int key) { final Preference preference = getPreference(key); + redrawScreen(preference); + } + + static void redrawScreen(final Preference preference) { if (!(preference instanceof PreferenceScreen)) { return; } @@ -403,14 +444,14 @@ public class SettingsActivity extends PreferenceActivity { Settings.putString(R.string.pref_webDeviceName, Settings.getWebDeviceName()); } - public void setOcAuthTitle(int prefKeyId) { - //TODO: Generalize! + public void setAuthTitle(int prefKeyId) { switch (prefKeyId) { case R.string.pref_fakekey_ocde_authorization: - setOCDEAuthTitle(); - break; case R.string.pref_fakekey_ocpl_authorization: - setOCPLAuthTitle(); + case R.string.pref_fakekey_ocnl_authorization: + case R.string.pref_fakekey_ocus_authorization: + case R.string.pref_fakekey_ocro_authorization: + setOCAuthTitle(OCPreferenceKeys.getByAuthId(prefKeyId)); break; case R.string.pref_fakekey_twitter_authorization: setTwitterAuthTitle(); @@ -420,18 +461,13 @@ public class SettingsActivity extends PreferenceActivity { } } - void setOCDEAuthTitle() { - getPreference(R.string.pref_fakekey_ocde_authorization) - .setTitle(getString(Settings.hasOCAuthorization(R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret) - ? R.string.settings_reauthorize - : R.string.settings_authorize)); - } - - void setOCPLAuthTitle() { - getPreference(R.string.pref_fakekey_ocpl_authorization) - .setTitle(getString(Settings.hasOCAuthorization(R.string.pref_ocpl_tokenpublic, R.string.pref_ocpl_tokensecret) - ? R.string.settings_reauthorize - : R.string.settings_authorize)); + void setOCAuthTitle(final OCPreferenceKeys key) { + if (key != null) { + getPreference(key.authPrefId) + .setTitle(getString(Settings.hasOCAuthorization(key.publicTokenPrefId, key.privateTokenPrefId) + ? R.string.settings_reauthorize + : R.string.settings_authorize)); + } } void setTwitterAuthTitle() { @@ -486,12 +522,15 @@ public class SettingsActivity extends PreferenceActivity { getPreference(R.string.pref_mapDirectory).setSummary(StringUtils.defaultString(Settings.getMapFileDirectory())); break; case R.string.pref_fakekey_ocde_authorization: - setOCDEAuthTitle(); - redrawScreen(R.string.preference_screen_ocde); - break; case R.string.pref_fakekey_ocpl_authorization: - setOCPLAuthTitle(); - redrawScreen(R.string.preference_screen_ocpl); + case R.string.pref_fakekey_ocnl_authorization: + case R.string.pref_fakekey_ocus_authorization: + case R.string.pref_fakekey_ocro_authorization: + OCPreferenceKeys key = OCPreferenceKeys.getByAuthId(requestCode); + if (key != null) { + setOCAuthTitle(key); + redrawScreen(key.prefScreenId); + } break; case R.string.pref_fakekey_twitter_authorization: setTwitterAuthTitle(); @@ -534,8 +573,29 @@ public class SettingsActivity extends PreferenceActivity { } Settings.setMapSource(mapSource); preference.setSummary(mapSource.getName()); - } else if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorOCPLActive) || isPreference(preference, R.string.pref_connectorGCActive) || isPreference(preference, R.string.pref_connectorECActive)) { - // // reset log-in status if connector activation was changed + } else if (isPreference(preference, R.string.pref_connectorOCActive) + || isPreference(preference, R.string.pref_connectorOCPLActive) + || isPreference(preference, R.string.pref_connectorOCNLActive) + || isPreference(preference, R.string.pref_connectorOCUSActive) + || isPreference(preference, R.string.pref_connectorOCROActive) + || isPreference(preference, R.string.pref_connectorGCActive) + || isPreference(preference, R.string.pref_connectorOXActive) + || isPreference(preference, R.string.pref_connectorECActive)) { + // update summary + boolean boolVal = ((Boolean) value).booleanValue(); + String summary = getServiceSummary(boolVal); + if (OCPreferenceKeys.isOCPreference(preference.getKey())) { + OCPreferenceKeys prefKey = OCPreferenceKeys.getByKey(preference.getKey()); + preference.getPreferenceManager().findPreference(getKey(prefKey.prefScreenId)).setSummary(summary); + } else if (isPreference(preference, R.string.pref_connectorGCActive)) { + preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_gc)).setSummary(summary); + } else if (isPreference(preference, R.string.pref_connectorOXActive)) { + preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_ox)).setSummary(summary); + } else if (isPreference(preference, R.string.pref_connectorECActive)) { + preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_ec)).setSummary(summary); + } + redrawScreen(preference.getPreferenceManager().findPreference(getKey(R.string.preference_screen_services))); + // reset log-in status if connector activation was changed CgeoApplication.getInstance().forceRelog(); } else if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in @@ -631,6 +691,13 @@ public class SettingsActivity extends PreferenceActivity { super.setPreferenceScreen(preferenceScreen); } + @SuppressWarnings("deprecation") + @Override + public PreferenceManager getPreferenceManager() { + // TODO replace with fragment based code + return super.getPreferenceManager(); + } + private static boolean isPreference(final Preference preference, int preferenceKeyId) { return getKey(preferenceKeyId).equals(preference.getKey()); } diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index b813389..97332d3 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -9,16 +9,15 @@ import org.eclipse.jdt.annotation.Nullable; public class TwitterAuthorizationActivity extends OAuthAuthorizationActivity { - public TwitterAuthorizationActivity() { - super("api.twitter.com", - "/oauth/request_token", - "/oauth/authorize", - "/oauth/access_token", - true, - Settings.getKeyConsumerPublic(), - Settings.getKeyConsumerSecret(), - "callback://www.cgeo.org/twitter/"); - } + public static final OAuthParameters TWITTER_OAUTH_PARAMS = new OAuthParameters( + "api.twitter.com", + "/oauth/request_token", + "/oauth/authorize", + "/oauth/access_token", + true, + Settings.getKeyConsumerPublic(), + Settings.getKeyConsumerSecret(), + "callback://www.cgeo.org/twitter/"); @Override protected final ImmutablePair<String, String> getTempTokens() { diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index ca4e825..d827e3e 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -379,6 +379,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { final TouchListener touchListener = new TouchListener(cache, v); v.setOnClickListener(touchListener); + v.setOnLongClickListener(touchListener); v.setOnTouchListener(touchListener); holder.checkbox.setVisibility(selectMode ? View.VISIBLE : View.GONE); @@ -535,62 +536,48 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { } } - private class TouchListener implements View.OnClickListener, View.OnTouchListener { + private class TouchListener implements View.OnClickListener, View.OnLongClickListener, View.OnTouchListener { - private boolean touch = true; - private final GestureDetector gestureDetector; private final Geocache cache; + private final GestureDetector gestureDetector; public TouchListener(final Geocache cache, final View view) { this.cache = cache; - final FlingGesture dGesture = new FlingGesture(cache, view); - gestureDetector = new GestureDetector(getContext(), dGesture); + gestureDetector = new GestureDetector(getContext(), new FlingGesture(cache)); } - // tap on item + // Tap on item @Override - public void onClick(View view) { - if (!touch) { - touch = true; - return; - } - + public void onClick(final View view) { if (isSelectMode()) { cache.setStatusChecked(!cache.isStatusChecked()); notifyDataSetChanged(); - return; + } else { + CacheDetailActivity.startActivity(getContext(), cache.getGeocode(), cache.getName()); } + } - // load cache details - CacheDetailActivity.startActivity(getContext(), cache.getGeocode(), cache.getName()); + // Long tap on item + @Override + public boolean onLongClick(final View view) { + view.showContextMenu(); + return true; } - // swipe on item + // Swipe on item @Override - public boolean onTouch(View view, MotionEvent event) { - if (gestureDetector.onTouchEvent(event)) { - touch = false; - return true; - } + public boolean onTouch(final View view, final MotionEvent event) { + return gestureDetector.onTouchEvent(event); - return false; } } private class FlingGesture extends GestureDetector.SimpleOnGestureListener { private final Geocache cache; - private final View view; - public FlingGesture(final Geocache cache, final View view) { + public FlingGesture(final Geocache cache) { this.cache = cache; - this.view = view; - } - - // long tap on item - @Override - public void onLongPress(MotionEvent e) { - view.showContextMenu(); } @Override diff --git a/main/src/cgeo/geocaching/ui/CompassView.java b/main/src/cgeo/geocaching/ui/CompassView.java index eaaf711..f7111f7 100644 --- a/main/src/cgeo/geocaching/ui/CompassView.java +++ b/main/src/cgeo/geocaching/ui/CompassView.java @@ -16,7 +16,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.util.AttributeSet; -import android.util.FloatMath; import android.view.View; import java.util.concurrent.TimeUnit; @@ -158,19 +157,19 @@ public class CompassView extends View { * @return the new value */ static protected float smoothUpdate(float goal, float actual) { - final float diff = AngleUtils.difference(actual, goal); + final double diff = AngleUtils.difference(actual, goal); - float offset = 0; + double offset = 0; // If the difference is smaller than 1 degree, do nothing as it // causes the arrow to vibrate. Round away from 0. if (diff > 1.0) { - offset = FloatMath.ceil(diff / 10.0f); // for larger angles, rotate faster + offset = Math.ceil(diff / 10.0); // for larger angles, rotate faster } else if (diff < 1.0) { - offset = FloatMath.floor(diff / 10.0f); + offset = Math.floor(diff / 10.0); } - return AngleUtils.normalize(actual + offset); + return AngleUtils.normalize((float) (actual + offset)); } @Override diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java index 31a61b5..d1b2a64 100644 --- a/main/src/cgeo/geocaching/ui/ImagesList.java +++ b/main/src/cgeo/geocaching/ui/ImagesList.java @@ -6,11 +6,11 @@ import cgeo.geocaching.files.LocalStorage; import cgeo.geocaching.list.StoredList; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import rx.Subscription; -import rx.android.observables.AndroidObservable; import rx.functions.Action0; import rx.functions.Action1; import rx.subscriptions.CompositeSubscription; @@ -30,12 +30,14 @@ import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; +import android.webkit.MimeTypeMap; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.Collection; import java.util.LinkedList; @@ -116,13 +118,12 @@ public class ImagesList { final ImageView imageView = (ImageView) inflater.inflate(R.layout.image_item, null); assert(imageView != null); - subscriptions.add(AndroidObservable.bindActivity(activity, imgGetter.fetchDrawable(img.getUrl())) - .subscribe(new Action1<BitmapDrawable>() { - @Override - public void call(final BitmapDrawable image) { - display(imageView, image, img, rowView); - } - })); + subscriptions.add(RxUtils.subscribeThenUI(imgGetter.fetchDrawable(img.getUrl()), new Action1<BitmapDrawable>() { + @Override + public void call(final BitmapDrawable image) { + display(imageView, image, img, rowView); + } + })); rowView.addView(imageView); imagesView.addView(rowView); } @@ -141,7 +142,7 @@ public class ImagesList { imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { - viewImageInStandardApp(image); + viewImageInStandardApp(img, image); } }); activity.registerForContextMenu(imageView); @@ -181,7 +182,7 @@ public class ImagesList { public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.image_open_file: - viewImageInStandardApp(currentDrawable); + viewImageInStandardApp(currentImage, currentDrawable); return true; case R.id.image_open_browser: if (currentImage != null) { @@ -193,26 +194,35 @@ public class ImagesList { } } - private void viewImageInStandardApp(final BitmapDrawable image) { + private static String mimeTypeForUrl(final String url) { + return StringUtils.defaultString(MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url)), "image/*"); + } + + private static File saveToTemporaryJPGFile(final BitmapDrawable image) throws FileNotFoundException { final File file = LocalStorage.getStorageFile(null, "temp.jpg", false, true); BufferedOutputStream stream = null; try { stream = new BufferedOutputStream(new FileOutputStream(file)); image.getBitmap().compress(CompressFormat.JPEG, 100, stream); - } catch (Exception e) { - Log.e("ImagesList.viewImageInStandardApp", e); - return; } finally { IOUtils.closeQuietly(stream); } + file.deleteOnExit(); + return file; + } - final Intent intent = new Intent(); - intent.setAction(android.content.Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), "image/jpeg"); - activity.startActivity(intent); - - if (file.exists()) { - file.deleteOnExit(); + private void viewImageInStandardApp(final Image img, final BitmapDrawable image) { + try { + final Intent intent = new Intent().setAction(android.content.Intent.ACTION_VIEW); + final File file = LocalStorage.getStorageFile(geocode, img.getUrl(), true, true); + if (file.exists()) { + intent.setDataAndType(Uri.fromFile(file), mimeTypeForUrl(img.getUrl())); + } else { + intent.setDataAndType(Uri.fromFile(saveToTemporaryJPGFile(image)), "image/jpeg"); + } + activity.startActivity(intent); + } catch (Exception e) { + Log.e("ImagesList.viewImageInStandardApp", e); } } diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java index c150434..cb52319 100644 --- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java +++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java @@ -5,11 +5,11 @@ import cgeo.geocaching.sensors.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.settings.Settings.CoordInputFormatEnum; +import cgeo.geocaching.utils.EditUtils; import org.apache.commons.lang3.StringUtils; @@ -103,14 +103,14 @@ public class CoordinatesInputDialog extends NoTitleDialog { eLonSec.addTextChangedListener(new TextChanged(eLonSec)); eLonSub.addTextChangedListener(new TextChanged(eLonSub)); - Compatibility.disableSuggestions(eLatDeg); - Compatibility.disableSuggestions(eLatMin); - Compatibility.disableSuggestions(eLatSec); - Compatibility.disableSuggestions(eLatSub); - Compatibility.disableSuggestions(eLonDeg); - Compatibility.disableSuggestions(eLonMin); - Compatibility.disableSuggestions(eLonSec); - Compatibility.disableSuggestions(eLonSub); + EditUtils.disableSuggestions(eLatDeg); + EditUtils.disableSuggestions(eLatMin); + EditUtils.disableSuggestions(eLatSec); + EditUtils.disableSuggestions(eLatSub); + EditUtils.disableSuggestions(eLonDeg); + EditUtils.disableSuggestions(eLonMin); + EditUtils.disableSuggestions(eLonSec); + EditUtils.disableSuggestions(eLonSub); bLat.setOnClickListener(new ButtonClickListener()); bLon.setOnClickListener(new ButtonClickListener()); diff --git a/main/src/cgeo/geocaching/utils/BundleUtils.java b/main/src/cgeo/geocaching/utils/BundleUtils.java new file mode 100644 index 0000000..9c4255b --- /dev/null +++ b/main/src/cgeo/geocaching/utils/BundleUtils.java @@ -0,0 +1,17 @@ +package cgeo.geocaching.utils; + +import org.eclipse.jdt.annotation.NonNull; + +import android.os.Bundle; + +public class BundleUtils { + + @NonNull + public static String getString(Bundle bundle, @NonNull String key, @NonNull String defaultValue) { + String res = bundle.getString(key); + if (res != null) { + return res; + } + return defaultValue; + } +} diff --git a/main/src/cgeo/geocaching/utils/EditUtils.java b/main/src/cgeo/geocaching/utils/EditUtils.java index d975df9..0bfe2ea 100644 --- a/main/src/cgeo/geocaching/utils/EditUtils.java +++ b/main/src/cgeo/geocaching/utils/EditUtils.java @@ -1,5 +1,6 @@ package cgeo.geocaching.utils; +import android.text.InputType; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; @@ -41,4 +42,9 @@ public final class EditUtils { } + public static void disableSuggestions(EditText edit) { + edit.setInputType(edit.getInputType() + | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS + | InputType.TYPE_TEXT_VARIATION_FILTER); + } } diff --git a/main/src/cgeo/geocaching/utils/ImageUtils.java b/main/src/cgeo/geocaching/utils/ImageUtils.java index 0d8bec8..e226703 100644 --- a/main/src/cgeo/geocaching/utils/ImageUtils.java +++ b/main/src/cgeo/geocaching/utils/ImageUtils.java @@ -3,6 +3,7 @@ package cgeo.geocaching.utils; import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.compatibility.Compatibility; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; @@ -15,11 +16,16 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.media.ExifInterface; import android.net.Uri; +import android.os.Environment; +import android.util.Base64; +import android.util.Base64InputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; @@ -183,11 +189,13 @@ public final class ImageUtils { sampleOptions.inSampleSize = sampleSize; } final Bitmap decodedImage = BitmapFactory.decodeFile(filePath, sampleOptions); - for (int i = 0; i < ORIENTATIONS.length; i++) { - if (orientation == ORIENTATIONS[i]) { - final Matrix matrix = new Matrix(); - matrix.postRotate(ROTATION[i]); - return Bitmap.createBitmap(decodedImage, 0, 0, decodedImage.getWidth(), decodedImage.getHeight(), matrix, true); + if (decodedImage != null) { + for (int i = 0; i < ORIENTATIONS.length; i++) { + if (orientation == ORIENTATIONS[i]) { + final Matrix matrix = new Matrix(); + matrix.postRotate(ROTATION[i]); + return Bitmap.createBitmap(decodedImage, 0, 0, decodedImage.getWidth(), decodedImage.getHeight(), matrix, true); + } } } return decodedImage; @@ -202,8 +210,8 @@ public final class ImageUtils { public static File getOutputImageFile() { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. + final File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "cgeo"); - File mediaStorageDir = new File(Compatibility.getExternalPictureDir(), "cgeo"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. @@ -244,4 +252,38 @@ public final class ImageUtils { } return false; } + + /** + * Decode a base64-encoded string and save the result into a file. + * + * @param inString the encoded string + * @param outFile the file to save the decoded result into + */ + public static void decodeBase64ToFile(final String inString, final File outFile) { + FileOutputStream out = null; + try { + out = new FileOutputStream(outFile); + decodeBase64ToStream(inString, out); + } catch (final IOException e) { + Log.e("HtmlImage.decodeBase64ToFile: cannot write file for decoded inline image", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + /** + * Decode a base64-encoded string and save the result into a stream. + * + * @param inString the encoded string + * @param outFile the file to save the decoded result into + */ + public static void decodeBase64ToStream(final String inString, final OutputStream out) throws IOException { + Base64InputStream in = null; + try { + in = new Base64InputStream(new ByteArrayInputStream(inString.getBytes(TextUtils.CHARSET_ASCII)), Base64.DEFAULT); + IOUtils.copy(in, out); + } finally { + IOUtils.closeQuietly(in); + } + } } diff --git a/main/src/cgeo/geocaching/utils/MiscUtils.java b/main/src/cgeo/geocaching/utils/MiscUtils.java new file mode 100644 index 0000000..122c4eb --- /dev/null +++ b/main/src/cgeo/geocaching/utils/MiscUtils.java @@ -0,0 +1,40 @@ +package cgeo.geocaching.utils; + +import org.apache.commons.collections4.iterators.IteratorIterable; +import org.apache.commons.lang3.NotImplementedException; + +import java.util.Iterator; +import java.util.List; + +final public class MiscUtils { + + private MiscUtils() {} // Do not instantiate + + public static <T> Iterable<List<T>> buffer(final List<T> original, final int n) { + if (n <= 0) { + throw new IllegalArgumentException("buffer size must be positive"); + } + return new IteratorIterable<List<T>>(new Iterator<List<T>>() { + final int size = original.size(); + int next = 0; + + @Override + public boolean hasNext() { + return next < size; + } + + @Override + public List<T> next() { + final List<T> result = original.subList(next, Math.min(next + n, size)); + next += n; + return result; + } + + @Override + public void remove() { + throw new NotImplementedException("remove"); + } + }); + } + +} diff --git a/main/src/cgeo/geocaching/utils/RxUtils.java b/main/src/cgeo/geocaching/utils/RxUtils.java new file mode 100644 index 0000000..9926bab --- /dev/null +++ b/main/src/cgeo/geocaching/utils/RxUtils.java @@ -0,0 +1,51 @@ +package cgeo.geocaching.utils; + +import rx.Observable; +import rx.Observer; +import rx.Scheduler; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.schedulers.Schedulers; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class RxUtils { + + // Utility class, not to be instanciated + private RxUtils() {} + + final static private int cores = Runtime.getRuntime().availableProcessors(); + public final static Scheduler computationScheduler = Schedulers.executor(new ThreadPoolExecutor(1, cores, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>())); + + public static <T> Subscription subscribeThenUI(final Observable<T> observable, final Observer<T> observer) { + return observable.observeOn(AndroidSchedulers.mainThread()).subscribe(observer); + } + + public static <T> Subscription subscribeThenUI(final Observable<T> observable, final Action1<T> action) { + return observable.observeOn(AndroidSchedulers.mainThread()).subscribe(action); + } + + public static <T> Subscription subscribeThenUI(final Observable<T> observable, final Action1<T> action, final Action1<Throwable> onError) { + return observable.observeOn(AndroidSchedulers.mainThread()).subscribe(action, onError); + } + + public static <T> Observable<T> onIO(final Observable<T> observable) { + return observable.subscribeOn(Schedulers.io()); + } + + public static <T> Subscription subscribeOnIOThenUI(final Observable<T> observable, final Observer<T> observer) { + return subscribeThenUI(onIO(observable), observer); + } + + public static <T> Subscription subscribeOnIOThenUI(final Observable<T> observable, final Action1<T> action) { + return subscribeThenUI(onIO(observable), action); + } + + public static <T> Subscription subscribeOnIOThenUI(final Observable<T> observable, final Action1<T> action, final Action1<Throwable> onError) { + return subscribeThenUI(onIO(observable), action, onError); + } + +} diff --git a/main/src/cgeo/geocaching/utils/TextUtils.java b/main/src/cgeo/geocaching/utils/TextUtils.java index c4e1128..ef09f32 100644 --- a/main/src/cgeo/geocaching/utils/TextUtils.java +++ b/main/src/cgeo/geocaching/utils/TextUtils.java @@ -6,6 +6,7 @@ package cgeo.geocaching.utils; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.eclipse.jdt.annotation.Nullable; +import java.nio.charset.Charset; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,6 +15,9 @@ import java.util.regex.Pattern; */ public final class TextUtils { + public static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); + public static final Charset CHARSET_ASCII = Charset.forName("US-ASCII"); + private static final Pattern PATTERN_REMOVE_NONPRINTABLE = Pattern.compile("\\p{Cntrl}"); private TextUtils() { diff --git a/main/templates/keys.xml b/main/templates/keys.xml index e667df5..2c41a2a 100644 --- a/main/templates/keys.xml +++ b/main/templates/keys.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<resources> +<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Google Maps --> <string name="maps_api_key" translatable="false">@maps.api.key@</string> @@ -10,4 +10,16 @@ <!-- Opencaching.pl --> <string name="oc_pl_okapi_consumer_key" translatable="false">@ocpl.okapi.consumer.key@</string> <string name="oc_pl_okapi_consumer_secret" translatable="false">@ocpl.okapi.consumer.secret@</string> + <!-- disable unused resource warning until remaining implementation has been merged --> + <!-- Opencaching.us --> + <string name="oc_us_okapi_consumer_key" translatable="false">@ocus.okapi.consumer.key@</string> + <string name="oc_us_okapi_consumer_secret" translatable="false">@ocus.okapi.consumer.secret@</string> + + <!-- Opencaching.nl --> + <string name="oc_nl_okapi_consumer_key" translatable="false">@ocnl.okapi.consumer.key@</string> + <string name="oc_nl_okapi_consumer_secret" translatable="false">@ocnl.okapi.consumer.secret@</string> + + <!-- Opencaching.ro --> + <string name="oc_ro_okapi_consumer_key" translatable="false">@ocro.okapi.consumer.key@</string> + <string name="oc_ro_okapi_consumer_secret" translatable="false">@ocro.okapi.consumer.secret@</string> </resources> diff --git a/main/templates/private.properties b/main/templates/private.properties index 0c40fda..2451048 100644 --- a/main/templates/private.properties +++ b/main/templates/private.properties @@ -30,3 +30,24 @@ ocde.okapi.consumer.secret= ocpl.okapi.consumer.key= ocpl.okapi.consumer.secret= + +# These keys allow c:geo to be registered at openaching.us and +# to search and log caches in your name +# You can request your own at http://www.opencaching.us/okapi/signup.html + +ocus.okapi.consumer.key= +ocus.okapi.consumer.secret= + +# These keys allow c:geo to be registered at openaching.nl and +# to search and log caches in your name +# You can request your own at http://www.opencaching.nl/okapi/signup.html + +ocnl.okapi.consumer.key= +ocnl.okapi.consumer.secret= + +# These keys allow c:geo to be registered at openaching.ro and +# to search and log caches in your name +# You can request your own at http://oc.opencaching.ro/okapi/signup.html + +ocro.okapi.consumer.key= +ocro.okapi.consumer.secret= |
