diff options
43 files changed, 603 insertions, 210 deletions
diff --git a/main/libs/androidannotations-api-3.2.jar.properties b/main/libs/androidannotations-api-3.2.jar.properties index ff6ac8c..6e05cd2 100644 --- a/main/libs/androidannotations-api-3.2.jar.properties +++ b/main/libs/androidannotations-api-3.2.jar.properties @@ -1 +1,2 @@ -src=src/androidannotations-api-3.2-sources.jar
\ No newline at end of file +src=src/androidannotations-api-3.2-sources.jar +doc=src/androidannotations-api-3.2-javadoc.jar
\ No newline at end of file diff --git a/main/libs/findbugs-annotations.jar b/main/libs/annotations-3.0.0.jar Binary files differindex 3641ad6..a2f68fe 100644 --- a/main/libs/findbugs-annotations.jar +++ b/main/libs/annotations-3.0.0.jar diff --git a/main/libs/annotations-3.0.0.jar.properties b/main/libs/annotations-3.0.0.jar.properties new file mode 100644 index 0000000..a32a2ea --- /dev/null +++ b/main/libs/annotations-3.0.0.jar.properties @@ -0,0 +1,2 @@ +src=src/annotations-3.0.0-sources.jar +doc=src/annotations-3.0.0-javadoc.jar diff --git a/main/libs/butterknife-6.0.0.jar.properties b/main/libs/butterknife-6.0.0.jar.properties new file mode 100644 index 0000000..d7282cc --- /dev/null +++ b/main/libs/butterknife-6.0.0.jar.properties @@ -0,0 +1,2 @@ +src=src/butterknife-6.0.0-sources.jar +doc=src/butterknife-6.0.0-javadoc.jar diff --git a/main/libs/src/androidannotations-api-3.2-javadoc.jar b/main/libs/src/androidannotations-api-3.2-javadoc.jar Binary files differnew file mode 100644 index 0000000..efdaf1f --- /dev/null +++ b/main/libs/src/androidannotations-api-3.2-javadoc.jar diff --git a/main/libs/src/annotations-3.0.0-javadoc.jar b/main/libs/src/annotations-3.0.0-javadoc.jar Binary files differnew file mode 100644 index 0000000..0098501 --- /dev/null +++ b/main/libs/src/annotations-3.0.0-javadoc.jar diff --git a/main/libs/src/annotations-3.0.0-sources.jar b/main/libs/src/annotations-3.0.0-sources.jar Binary files differnew file mode 100644 index 0000000..0098501 --- /dev/null +++ b/main/libs/src/annotations-3.0.0-sources.jar diff --git a/main/libs/src/butterknife-6.0.0-javadoc.jar b/main/libs/src/butterknife-6.0.0-javadoc.jar Binary files differnew file mode 100644 index 0000000..1aef6df --- /dev/null +++ b/main/libs/src/butterknife-6.0.0-javadoc.jar diff --git a/main/libs/src/butterknife-6.0.0-sources.jar b/main/libs/src/butterknife-6.0.0-sources.jar Binary files differnew file mode 100644 index 0000000..3b29f50 --- /dev/null +++ b/main/libs/src/butterknife-6.0.0-sources.jar diff --git a/main/project/libraries/.gitignore b/main/project/libraries/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/main/project/libraries/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/main/project/libraries/pom.xml b/main/project/libraries/pom.xml new file mode 100644 index 0000000..a86c3c7 --- /dev/null +++ b/main/project/libraries/pom.xml @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.cgeo</groupId> + <artifactId>library.check</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>c:geo dependency update check</name> + + <description>This project checks or updates c:geo dependencies. + Run 'mvn validate' to see available dependency updates. + Run 'mvn install' to actually update to the latest releases. You may need to refresh your IDE afterwards. + </description> + + <properties> + <AndroidAnnotationsVersion>3.2</AndroidAnnotationsVersion> + + <ButterKnifeVersion>6.0.0</ButterKnifeVersion> + + <CommonsCollections4Version>4.0</CommonsCollections4Version> + <CommonsIoVersion>2.4</CommonsIoVersion> + <CommonsLang3Version>3.3.2</CommonsLang3Version> + + <FindbugsAnnotationsVersion>3.0.0</FindbugsAnnotationsVersion> + + <JacksonAnnotationsVersion>2.4.4</JacksonAnnotationsVersion> + <JacksonCoreVersion>2.4.4</JacksonCoreVersion> + <JacksonDatabindVersion>2.4.4</JacksonDatabindVersion> + + <RXAndroidVersion>0.23.0</RXAndroidVersion> + <RXJavaVersion>1.0.3</RXJavaVersion> + <RXJavaAsyncUtilVersion>0.21.0</RXJavaAsyncUtilVersion> + </properties> + + <dependencies> + <dependency> + <groupId>org.androidannotations</groupId> + <artifactId>androidannotations</artifactId> + <version>${AndroidAnnotationsVersion}</version> + </dependency> + <dependency> + <groupId>org.androidannotations</groupId> + <artifactId>androidannotations-api</artifactId> + <version>${AndroidAnnotationsVersion}</version> + </dependency> + + <dependency> + <groupId>com.jakewharton</groupId> + <artifactId>butterknife</artifactId> + <version>${ButterKnifeVersion}</version> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + <version>${CommonsCollections4Version}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>${CommonsLang3Version}</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>${CommonsIoVersion}</version> + </dependency> + + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>annotations</artifactId> + <version>${FindbugsAnnotationsVersion}</version> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + <version>${JacksonAnnotationsVersion}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>${JacksonCoreVersion}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>${JacksonDatabindVersion}</version> + </dependency> + + <dependency> + <groupId>io.reactivex</groupId> + <artifactId>rxjava</artifactId> + <version>${RXJavaVersion}</version> + </dependency> + <dependency> + <groupId>io.reactivex</groupId> + <artifactId>rxjava-async-util</artifactId> + <version>${RXJavaAsyncUtilVersion}</version> + </dependency> + <dependency> + <groupId>io.reactivex</groupId> + <artifactId>rxandroid</artifactId> + <version>${RXAndroidVersion}</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>versions-maven-plugin</artifactId> + <version>2.1</version> + <executions> + <execution> + <id>display-property-updates</id> + <phase>validate</phase> + <goals> + <goal>display-property-updates</goal> + </goals> + </execution> + <execution> + <id>update-properties</id> + <phase>install</phase> + <goals> + <goal>update-properties</goal> + </goals> + <configuration> + <allowSnapshots>false</allowSnapshots> + <allowMajorUpdates>true</allowMajorUpdates> + <allowMinorUpdates>true</allowMinorUpdates> + <generateBackupPoms>true</generateBackupPoms> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.9</version> + <executions> + <execution> + <id>copy-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <outputDirectory>${basedir}/../../libs</outputDirectory> + <overWriteReleases>true</overWriteReleases> + <excludeTransitive>true</excludeTransitive> + </configuration> + </execution> + <execution> + <id>src-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <classifier>sources</classifier> + <outputDirectory>${basedir}/../../libs/src</outputDirectory> + <failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact> + <overWriteReleases>true</overWriteReleases> + <excludeTransitive>true</excludeTransitive> + </configuration> + </execution> + <execution> + <id>javadoc-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + <configuration> + <classifier>javadoc</classifier> + <outputDirectory>${basedir}/../../libs/src</outputDirectory> + <failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact> + <overWriteReleases>true</overWriteReleases> + <excludeTransitive>true</excludeTransitive> + </configuration> + </execution> + </executions> + </plugin> + <!-- unfinished: update properties files of source and javadoc + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.4</version> + <executions> + <execution> + <id>write-properties-files</id> + <phase>package</phase> + <configuration> + <tasks> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + --> + </plugins> + </build> +</project> diff --git a/main/res/drawable-hdpi/star_half.png b/main/res/drawable-hdpi/star_half.png Binary files differdeleted file mode 100644 index 000208c..0000000 --- a/main/res/drawable-hdpi/star_half.png +++ /dev/null diff --git a/main/res/drawable-ldpi/star_half.png b/main/res/drawable-ldpi/star_half.png Binary files differdeleted file mode 100644 index 97fa464..0000000 --- a/main/res/drawable-ldpi/star_half.png +++ /dev/null diff --git a/main/res/drawable-mdpi/star_half.png b/main/res/drawable-mdpi/star_half.png Binary files differdeleted file mode 100644 index 1ea9152..0000000 --- a/main/res/drawable-mdpi/star_half.png +++ /dev/null diff --git a/main/res/drawable/star_rating.xml b/main/res/drawable/star_rating.xml new file mode 100644 index 0000000..0d8a8e2 --- /dev/null +++ b/main/res/drawable/star_rating.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+android:id/background" + android:drawable="@drawable/star_off" /> + <item android:id="@+android:id/secondaryProgress" + android:drawable="@drawable/star_off" /> + <item android:id="@+android:id/progress" + android:drawable="@drawable/star_on" /> +</layer-list>
\ No newline at end of file diff --git a/main/res/layout/cache_information_item.xml b/main/res/layout/cache_information_item.xml index 1b766e4..d213e56 100644 --- a/main/res/layout/cache_information_item.xml +++ b/main/res/layout/cache_information_item.xml @@ -34,17 +34,17 @@ android:textIsSelectable="false" android:textSize="14sp" /> - <LinearLayout + <RatingBar android:id="@+id/stars" + style="@style/cacheRatingBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" + android:layout_gravity="center_horizontal" android:layout_toRightOf="@+id/value" android:baselineAligned="false" android:gravity="center_vertical" - android:orientation="horizontal" - android:visibility="gone" > - </LinearLayout> + android:visibility="gone" /> <TextView android:id="@+id/addition" diff --git a/main/res/layout/star_image.xml b/main/res/layout/star_image.xml deleted file mode 100644 index 809a17d..0000000 --- a/main/res/layout/star_image.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<ImageView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="12dip" - android:layout_height="12dip" - android:layout_gravity="center" - android:layout_margin="1dip" - android:gravity="center" - android:scaleType="fitXY" - android:src="@drawable/star_off" - tools:context=".ui.CacheDetailsCreator" /> diff --git a/main/res/values/changelog_master.xml b/main/res/values/changelog_master.xml index 1e3c3d4..04d2498 100644 --- a/main/res/values/changelog_master.xml +++ b/main/res/values/changelog_master.xml @@ -2,5 +2,7 @@ <resources> <!-- changelog for the master branch --> <string name="changelog_master" translatable="false"> + <b>Next feature release:</b>\n + \n </string> </resources> diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 4be3ab6..415a97f 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -142,6 +142,7 @@ <string name="err_login">No Login information stored</string> <string name="err_login_failed_toast">c:geo can\'t log in. c:geo works offline with Stored caches. Check Login settings or enable your internet connection.</string> <string name="err_unknown">Unknown error</string> + <string name="err_unknown_address">c:geo was unable to map this address to an existing location</string> <string name="err_comm">Unknown communication error</string> <string name="err_missing_auth">No username and/or password set.</string> <string name="err_wrong">Login information incorrect</string> @@ -362,6 +363,7 @@ <!-- settings --> <string name="settings_title_services">Services</string> + <string name="settings_summary_services">Configure user account information and access to optional services.</string> <string name="settings_title_appearance">Appearance</string> <string name="settings_title_cachedetails">Cache Details</string> <string name="settings_title_offlinedata">Offline Data</string> diff --git a/main/res/values/strings_not_translatable.xml b/main/res/values/strings_not_translatable.xml index 585500f..35fef08 100644 --- a/main/res/values/strings_not_translatable.xml +++ b/main/res/values/strings_not_translatable.xml @@ -81,6 +81,8 @@ · <a href="http://rrze-icon-set.berlios.de/index.html">RRZE Icon set</a> (<a href="http://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA 3.0</a>)\n · <a href="http://iconfindr.com/1mNr3rl">Layers icon by Cole Bemis</a> (<a href="http://creativecommons.org/licenses/by/3.0/">CC-BY 3.0</a>)\n · <a href="https://github.com/amlcurran/Showcaseview">ShowcaseView by Alex Curran</a> (<a href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</a>)\n + · <a href="http://www.mapquest.com/">Geocoding courtesy of MapQuest</a>\n + · <a href="http://www.openstreetmap.org/">Geocoding data from OpenStreetMap</a>\n </string> <!-- cache menu --> diff --git a/main/res/values/styles.xml b/main/res/values/styles.xml index be1e1a4..5f280f2 100644 --- a/main/res/values/styles.xml +++ b/main/res/values/styles.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<resources> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> <!-- system definitions --> @@ -338,4 +338,13 @@ <item name="android:src">@drawable/mark_green</item> </style> + <style name="cacheRatingBar" parent="@android:style/Widget.RatingBar"> + <item name="android:progressDrawable">@drawable/star_rating</item> + <item name="android:minHeight">12dip</item> + <item name="android:maxHeight">22dip</item> + <item name="android:max">5</item> + <item name="android:stepSize">0.5</item> + <item name="android:isIndicator">true</item> + </style> + </resources>
\ No newline at end of file diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml index 9648462..48d8a21 100644 --- a/main/res/xml/preferences.xml +++ b/main/res/xml/preferences.xml @@ -6,7 +6,8 @@ <PreferenceScreen android:icon="?attr/settings_cloud" android:key="@string/preference_screen_services" - android:title="@string/settings_title_services" > + android:title="@string/settings_title_services" + android:summary="@string/settings_summary_services"> <PreferenceCategory android:title="@string/settings_category_geocaching" > <PreferenceScreen android:key="@string/preference_screen_gc" diff --git a/main/src/cgeo/geocaching/AddressListActivity.java b/main/src/cgeo/geocaching/AddressListActivity.java index 4f71ab6..4f81f8b 100644 --- a/main/src/cgeo/geocaching/AddressListActivity.java +++ b/main/src/cgeo/geocaching/AddressListActivity.java @@ -1,14 +1,17 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractListActivity; -import cgeo.geocaching.location.Geocoder; +import cgeo.geocaching.location.AndroidGeocoder; +import cgeo.geocaching.location.GCGeocoder; +import cgeo.geocaching.location.MapQuestGeocoder; import cgeo.geocaching.ui.AddressListAdapter; -import org.apache.commons.collections4.CollectionUtils; +import rx.Observable; +import rx.android.observables.AndroidObservable; +import rx.functions.Action1; import android.app.ProgressDialog; import android.location.Address; -import android.os.AsyncTask; import android.os.Bundle; import java.util.List; @@ -19,47 +22,35 @@ public class AddressListActivity extends AbstractListActivity { public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.addresslist_activity); - // get parameters - final String keyword = getIntent().getStringExtra(Intents.EXTRA_KEYWORD); - - if (keyword == null) { - showToast(res.getString(R.string.err_search_address_forgot)); - finish(); - return; - } final AddressListAdapter adapter = new AddressListAdapter(this); setListAdapter(adapter); + final String keyword = getIntent().getStringExtra(Intents.EXTRA_KEYWORD); final ProgressDialog waitDialog = ProgressDialog.show(this, res.getString(R.string.search_address_started), keyword, true); waitDialog.setCancelable(true); - lookupAddressInBackground(keyword, adapter, waitDialog); } private void lookupAddressInBackground(final String keyword, final AddressListAdapter adapter, final ProgressDialog waitDialog) { - new AsyncTask<Void, Void, List<Address>>() { - + final Observable<Address> geocoderObservable = new AndroidGeocoder(this).getFromLocationName(keyword) + .onErrorResumeNext(MapQuestGeocoder.getFromLocationName(keyword)) + .onErrorResumeNext(GCGeocoder.getFromLocationName(keyword)); + AndroidObservable.bindActivity(this, geocoderObservable.toList()).subscribe(new Action1<List<Address>>() { @Override - protected List<Address> doInBackground(final Void... params) { - final Geocoder geocoder = new Geocoder(AddressListActivity.this); - return geocoder.getFromLocationName(keyword); - } - - @Override - protected void onPostExecute(final List<Address> addresses) { + public void call(final List<Address> addresses) { waitDialog.dismiss(); - if (CollectionUtils.isNotEmpty(addresses)) { - for (final Address address : addresses) { - adapter.add(address); // don't use addAll, it's only available with API >= 11 - } - } else { - finish(); - CacheListActivity.startActivityAddress(AddressListActivity.this, null, keyword); + for (final Address address : addresses) { + adapter.add(address); // don't use addAll, it's only available with API >= 11 } } - - }.execute(); + }, new Action1<Throwable>() { + @Override + public void call(final Throwable throwable) { + finish(); + showToast(res.getString(R.string.err_unknown_address)); + } + }); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java index c8f1101..1b6a268 100644 --- a/main/src/cgeo/geocaching/CacheListActivity.java +++ b/main/src/cgeo/geocaching/CacheListActivity.java @@ -27,7 +27,6 @@ import cgeo.geocaching.list.PseudoList; import cgeo.geocaching.list.StoredList; import cgeo.geocaching.loaders.AbstractSearchLoader; import cgeo.geocaching.loaders.AbstractSearchLoader.CacheListLoaderType; -import cgeo.geocaching.loaders.AddressGeocacheListLoader; import cgeo.geocaching.loaders.CoordsGeocacheListLoader; import cgeo.geocaching.loaders.FinderGeocacheListLoader; import cgeo.geocaching.loaders.HistoryGeocacheListLoader; @@ -1549,12 +1548,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA } else { title = coords.toString(); } - if (coords != null) { - loader = new CoordsGeocacheListLoader(app, coords); - } - else { - loader = new AddressGeocacheListLoader(app, address); - } + loader = new CoordsGeocacheListLoader(app, coords); break; case FINDER: final String username = extras.getString(Intents.EXTRA_USERNAME); diff --git a/main/src/cgeo/geocaching/DataStore.java b/main/src/cgeo/geocaching/DataStore.java index fae0d38..1081828 100644 --- a/main/src/cgeo/geocaching/DataStore.java +++ b/main/src/cgeo/geocaching/DataStore.java @@ -1103,7 +1103,9 @@ public class DataStore { for (final Geocache cache : caches) { final String geocode = cache.getGeocode(); final Geocache existingCache = existingCaches.get(geocode); - final boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null; + boolean dbUpdateRequired = !cache.gatherMissingFrom(existingCache) || cacheCache.getCacheFromCache(geocode) != null; + // parse the note AFTER merging the local information in + dbUpdateRequired |= cache.parseWaypointsFromNote(); cache.addStorageLocation(StorageLocation.CACHE); cacheCache.putCacheInCache(cache); diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java index 69babc4..d396b93 100644 --- a/main/src/cgeo/geocaching/Geocache.java +++ b/main/src/cgeo/geocaching/Geocache.java @@ -1368,12 +1368,15 @@ public class Geocache implements IWaypoint { /** * Detect coordinates in the personal note and convert them to user defined waypoints. Works by rule of thumb. */ - public void parseWaypointsFromNote() { + public boolean parseWaypointsFromNote() { + boolean changed = false; for (final Waypoint waypoint : Waypoint.parseWaypointsFromNote(StringUtils.defaultString(getPersonalNote()))) { if (!hasIdenticalWaypoint(waypoint.getCoords())) { addOrChangeWaypoint(waypoint, false); + changed = true; } } + return changed; } private boolean hasIdenticalWaypoint(final Geopoint point) { diff --git a/main/src/cgeo/geocaching/SearchActivity.java b/main/src/cgeo/geocaching/SearchActivity.java index 9de279d..1606350 100644 --- a/main/src/cgeo/geocaching/SearchActivity.java +++ b/main/src/cgeo/geocaching/SearchActivity.java @@ -373,7 +373,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin } private void findByGeocodeFn() { - final String geocodeText = StringUtils.trim(geocodeEditText.getText().toString()); + final String geocodeText = StringUtils.trimToEmpty(geocodeEditText.getText().toString()); if (StringUtils.isBlank(geocodeText) || geocodeText.equalsIgnoreCase("GC")) { Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_gccode); @@ -384,7 +384,7 @@ public class SearchActivity extends AbstractActionBarActivity implements Coordin } private void findTrackableFn() { - final String trackableText = StringUtils.trim(trackableEditText.getText().toString()); + final String trackableText = StringUtils.trimToEmpty(trackableEditText.getText().toString()); if (StringUtils.isBlank(trackableText) || trackableText.equalsIgnoreCase("TB")) { Dialogs.message(this, R.string.warn_search_help_title, R.string.warn_search_help_tb); diff --git a/main/src/cgeo/geocaching/Waypoint.java b/main/src/cgeo/geocaching/Waypoint.java index 5cfeb29..b4979e4 100644 --- a/main/src/cgeo/geocaching/Waypoint.java +++ b/main/src/cgeo/geocaching/Waypoint.java @@ -97,18 +97,11 @@ public class Waypoint implements IWaypoint { if (newPrefixes.containsKey(prefix)) { newPrefixes.get(prefix).merge(oldWaypoint); } else if (oldWaypoint.isUserDefined() || forceMerge) { - // personal note waypoints should always be taken from the new list only - if (!isPersonalNoteWaypoint(oldWaypoint)) { - newPoints.add(oldWaypoint); - } + newPoints.add(oldWaypoint); } } } - private static boolean isPersonalNoteWaypoint(final @NonNull Waypoint waypoint) { - return StringUtils.startsWith(waypoint.getName(), CgeoApplication.getInstance().getString(R.string.cache_personal_note) + " "); - } - public boolean isUserDefined() { return own || WaypointType.OWN == waypointType; } @@ -304,7 +297,7 @@ public class Waypoint implements IWaypoint { ((point.getLatitudeE6() % 1000) != 0 || (point.getLongitudeE6() % 1000) != 0)) { final String name = CgeoApplication.getInstance().getString(R.string.cache_personal_note) + " " + count; final String potentialWaypointType = note.substring(Math.max(0, matcher.start() - 15)); - final Waypoint waypoint = new Waypoint(name, parseWaypointType(potentialWaypointType), false); + final Waypoint waypoint = new Waypoint(name, parseWaypointType(potentialWaypointType), true); waypoint.setCoords(point); waypoints.add(waypoint); count++; diff --git a/main/src/cgeo/geocaching/activity/ActivityMixin.java b/main/src/cgeo/geocaching/activity/ActivityMixin.java index b135358..14a2fbf 100644 --- a/main/src/cgeo/geocaching/activity/ActivityMixin.java +++ b/main/src/cgeo/geocaching/activity/ActivityMixin.java @@ -157,6 +157,15 @@ public final class ActivityMixin { editText.setSelection(newCursor); } + /** + * This is the exact code from Google to implement Up navigation, with one exception: activity.isTaskRoot() was + * added as {@link NavUtils#shouldUpRecreateTask(Activity, Intent)} seems not to handle the case, that this activity + * was created from an intent by another app, and our own app is not yet running. The bug seems to be fixed in + * Android 4.4.something, however. + * + * @param activity + * @return + */ public static boolean navigateUp(@NonNull final Activity activity) { // see http://developer.android.com/training/implementing-navigation/ancestral.html final Intent upIntent = NavUtils.getParentActivityIntent(activity); @@ -164,7 +173,7 @@ public final class ActivityMixin { activity.finish(); return true; } - if (NavUtils.shouldUpRecreateTask(activity, upIntent)) { + if (NavUtils.shouldUpRecreateTask(activity, upIntent) || activity.isTaskRoot()) { // This activity is NOT part of this app's task, so create a new task // when navigating up, with a synthesized back stack. TaskStackBuilder.create(activity) diff --git a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java index 5d667c3..391fa90 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java @@ -2,6 +2,7 @@ package cgeo.geocaching.apps.cache.navi; import cgeo.geocaching.R; import cgeo.geocaching.location.Geopoint; +import cgeo.geocaching.utils.ProcessUtils; import android.app.Activity; import android.content.Intent; @@ -14,10 +15,19 @@ import android.net.Uri; */ class SygicNavigationApp extends AbstractPointNavigationApp { - private static final String PACKAGE = "com.sygic.aura"; + private static final String PACKAGE_NORMAL = "com.sygic.aura"; + /** + * there is a secondary edition of this app + */ + private static final String PACKAGE_VOUCHER = "com.sygic.aura_voucher"; SygicNavigationApp() { - super(getString(R.string.cache_menu_sygic), R.id.cache_app_sygic, null, PACKAGE); + super(getString(R.string.cache_menu_sygic), R.id.cache_app_sygic, null, PACKAGE_NORMAL); + } + + @Override + public boolean isInstalled() { + return ProcessUtils.isLaunchable(PACKAGE_NORMAL) || ProcessUtils.isLaunchable(PACKAGE_VOUCHER); } @Override diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index 33447c7..a0784a8 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -771,8 +771,6 @@ public abstract class GCParser { } } - cache.parseWaypointsFromNote(); - // last check for necessary cache conditions if (StringUtils.isBlank(cache.getGeocode())) { return UNKNOWN_PARSE_ERROR; @@ -940,30 +938,6 @@ public abstract class GCParser { return searchByAny(cacheType, isSearchForMyCaches(userName), showCaptcha, params, recaptchaReceiver); } - public static SearchResult searchByAddress(final String address, final CacheType cacheType, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) { - if (StringUtils.isBlank(address)) { - Log.e("GCParser.searchByAddress: No address given"); - return null; - } - - final ObjectNode response = Network.requestJSON("http://www.geocaching.com/api/geocode", new Parameters("q", address)); - if (response == null) { - return null; - } - - if (!StringUtils.equalsIgnoreCase(response.path("status").asText(), "success")) { - return null; - } - - final JsonNode data = response.path("data"); - final JsonNode latNode = data.get("lat"); - final JsonNode lngNode = data.get("lng"); - if (latNode == null || lngNode == null) { - return null; - } - return searchByCoords(new Geopoint(latNode.asDouble(), lngNode.asDouble()), cacheType, showCaptcha, recaptchaReceiver); - } - @Nullable public static Trackable searchTrackable(final String geocode, final String guid, final String id) { if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) { diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java index 26e0f78..a1f8029 100644 --- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java @@ -397,7 +397,6 @@ final class OkapiClient { } if (response.hasNonNull(CACHE_MY_NOTES)) { cache.setPersonalNote(response.get(CACHE_MY_NOTES).asText()); - cache.parseWaypointsFromNote(); } cache.setLogPasswordRequired(response.get(CACHE_REQ_PASSWORD).asBoolean()); diff --git a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java deleted file mode 100644 index e1573c9..0000000 --- a/main/src/cgeo/geocaching/loaders/AddressGeocacheListLoader.java +++ /dev/null @@ -1,23 +0,0 @@ -package cgeo.geocaching.loaders; - -import cgeo.geocaching.SearchResult; -import cgeo.geocaching.connector.gc.GCParser; -import cgeo.geocaching.settings.Settings; - -import android.content.Context; - -public class AddressGeocacheListLoader extends AbstractSearchLoader { - - private final String address; - - public AddressGeocacheListLoader(Context context, String address) { - super(context); - this.address = address; - } - - @Override - public SearchResult runSearch() { - return GCParser.searchByAddress(address, Settings.getCacheType(), Settings.isShowCaptcha(), this); - } - -} diff --git a/main/src/cgeo/geocaching/location/AndroidGeocoder.java b/main/src/cgeo/geocaching/location/AndroidGeocoder.java new file mode 100644 index 0000000..98ea285 --- /dev/null +++ b/main/src/cgeo/geocaching/location/AndroidGeocoder.java @@ -0,0 +1,59 @@ +package cgeo.geocaching.location; + +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; + +import org.apache.commons.collections4.CollectionUtils; +import org.eclipse.jdt.annotation.NonNull; + +import rx.Observable; +import rx.functions.Func0; + +import android.content.Context; +import android.location.Address; +import android.location.Geocoder; + +import java.util.List; +import java.util.Locale; + +/** + * Encapsulation of the Android {@link Geocoder} with default error handling. All methods of this class + * are blocking and will do network lookups. + * + */ +public class AndroidGeocoder { + private final Geocoder geocoder; + + public AndroidGeocoder(final Context context) { + geocoder = new Geocoder(context, Locale.getDefault()); + } + + /** + * Retrieve addresses from a textual location using Android geocoding API. The work happens on the network + * scheduler. + * + * @param keyword + * the location + * @return an observable containing zero or more locations + * + * @see Geocoder#getFromLocationName(String, int) + */ + public Observable<Address> getFromLocationName(@NonNull final String keyword) { + return Observable.defer(new Func0<Observable<Address>>() { + @Override + public Observable<Address> call() { + try { + final List<Address> addresses = geocoder.getFromLocationName(keyword, 20); + if (CollectionUtils.isEmpty(addresses)) { + return Observable.error(new RuntimeException("no result from Android geocoder")); + } + return Observable.from(addresses); + } catch (final Exception e) { + Log.i("Unable to use Android geocoder: " + e.getMessage()); + return Observable.error(e); + } + } + }).subscribeOn(RxUtils.networkScheduler); + } + +} diff --git a/main/src/cgeo/geocaching/location/GCGeocoder.java b/main/src/cgeo/geocaching/location/GCGeocoder.java new file mode 100644 index 0000000..549044f --- /dev/null +++ b/main/src/cgeo/geocaching/location/GCGeocoder.java @@ -0,0 +1,65 @@ +package cgeo.geocaching.location; + +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNull; + +import rx.Observable; +import rx.functions.Func0; + +import android.location.Address; + +import java.util.Locale; + +public class GCGeocoder { + + private GCGeocoder() { + // Do not instantiate + } + + /** + * Retrieve addresses from a textual location using geocaching.com geocoding API. The work happens on the network + * scheduler. + * + * @param address + * the location + * @return an observable containing zero or more locations + * + * @see android.location.Geocoder#getFromLocationName(String, int) + */ + public static Observable<Address> getFromLocationName(@NonNull final String address) { + return Observable.defer(new Func0<Observable<Address>>() { + @Override + public Observable<Address> call() { + if (!Settings.isGCConnectorActive()) { + return Observable.error(new RuntimeException("geocaching.com connector is not active")); + } + final ObjectNode response = Network.requestJSON("https://www.geocaching.com/api/geocode", new Parameters("q", address)); + if (response == null || !StringUtils.equalsIgnoreCase(response.path("status").asText(), "success")) { + return Observable.error(new RuntimeException("unable to use geocaching.com geocoder")); + } + + final JsonNode data = response.path("data"); + final Address geocodedAddress = new Address(Locale.getDefault()); + try { + geocodedAddress.setLatitude(data.get("lat").asDouble()); + geocodedAddress.setLongitude(data.get("lng").asDouble()); + geocodedAddress.setAddressLine(0, address); + return Observable.just(geocodedAddress); + } catch (final Exception e) { + Log.e("unable to decode answer from geocaching.com geocoder", e); + return Observable.error(e); + } + } + }).subscribeOn(RxUtils.networkScheduler); + } + +} diff --git a/main/src/cgeo/geocaching/location/Geocoder.java b/main/src/cgeo/geocaching/location/Geocoder.java deleted file mode 100644 index 1582daa..0000000 --- a/main/src/cgeo/geocaching/location/Geocoder.java +++ /dev/null @@ -1,61 +0,0 @@ -package cgeo.geocaching.location; - -import cgeo.geocaching.utils.Log; - -import org.apache.commons.lang3.StringUtils; -import org.eclipse.jdt.annotation.NonNull; - -import android.content.Context; -import android.location.Address; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -/** - * Encapsulation of the Android {@link android.location.Geocoder} with default error handling. All methods of this class - * are blocking and will do network lookups. - * - */ -public class Geocoder { - private final android.location.Geocoder geocoder; - - public Geocoder(final Context context) { - geocoder = new android.location.Geocoder(context, Locale.getDefault()); - } - - /** - * @param keyword - * @return - * - * @see android.location.Geocoder#getFromLocationName(String, int) - */ - public @NonNull List<Address> getFromLocationName(final String keyword) { - try { - return geocoder.getFromLocationName(keyword, 20); - } catch (final Exception e) { - handleException(e); - return Collections.emptyList(); - } - } - - public @NonNull List<Address> getFromLocation(final Geopoint coords) { - try { - return geocoder.getFromLocation(coords.getLatitude(), coords.getLongitude(), 20); - } catch (final IOException e) { - handleException(e); - return Collections.emptyList(); - } - } - - private static void handleException(final Exception e) { - // non Google devices come without the geocoder - if (StringUtils.containsIgnoreCase(e.getMessage(), "Service not Available")) { - Log.i("No geocoder available"); - } - else { - Log.e("Geocoder", e); - } - } -} diff --git a/main/src/cgeo/geocaching/location/GeopointParser.java b/main/src/cgeo/geocaching/location/GeopointParser.java index e73e787..a6b8e45 100644 --- a/main/src/cgeo/geocaching/location/GeopointParser.java +++ b/main/src/cgeo/geocaching/location/GeopointParser.java @@ -122,7 +122,7 @@ class GeopointParser { // Nothing found with "N 52...", try to match string as decimal degree parts (i.e. multiple doubles) try { - final String[] items = StringUtils.split(text.trim()); + final String[] items = StringUtils.split(StringUtils.trimToEmpty(text)); if (items.length > 0 && items.length <= 2) { final int index = (latlon == LatLon.LON ? items.length - 1 : 0); final String textPart = items[index]; diff --git a/main/src/cgeo/geocaching/location/MapQuestGeocoder.java b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java new file mode 100644 index 0000000..537ae40 --- /dev/null +++ b/main/src/cgeo/geocaching/location/MapQuestGeocoder.java @@ -0,0 +1,117 @@ +package cgeo.geocaching.location; + +import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNull; + +import rx.Observable; +import rx.Observable.OnSubscribe; +import rx.Subscriber; +import rx.functions.Func0; + +import android.location.Address; + +import java.util.Locale; + +public class MapQuestGeocoder { + + private static final String MAPQUEST_KEY = "Fmjtd|luurn1u2n9,bs=o5-9wynua"; + + private MapQuestGeocoder() { + // Do not instantiate + } + + /** + * Retrieve addresses from a textual location using MapQuest geocoding API. The work happens on the network + * scheduler. + * + * @param address + * the location + * @return an observable containing zero or more locations + * + * @see android.location.Geocoder#getFromLocationName(String, int) + */ + public static Observable<Address> getFromLocationName(@NonNull final String address) { + return Observable.defer(new Func0<Observable<Address>>() { + @Override + public Observable<Address> call() { + final ObjectNode response = Network.requestJSON("https://www.mapquestapi.com/geocoding/v1/address", + new Parameters("key", MAPQUEST_KEY, "location", address, "maxResults", "20", "thumbMaps", "false")); + if (response == null) { + Log.w("MapQuest decoder error: no response"); + return Observable.error(new RuntimeException("no answer from MapQuest geocoder")); + } + final int statusCode = response.path("info").path("statuscode").asInt(-1); + if (statusCode != 0) { + Log.w("MapQuest decoder error: statuscode is not 0"); + return Observable.error(new RuntimeException("no correct answer from MapQuest geocoder")); + } + return Observable.create(new OnSubscribe<Address>() { + @Override + public void call(final Subscriber<? super Address> subscriber) { + try { + for (final JsonNode address: response.get("results").get(0).get("locations")) { + subscriber.onNext(mapquestToAddress(address)); + } + subscriber.onCompleted(); + } catch (final Exception e) { + Log.e("Error decoding MapQuest address", e); + subscriber.onError(e); + } + } + }); + } + }).subscribeOn(RxUtils.networkScheduler); + } + + private static Address mapquestToAddress(final JsonNode mapquestAddress) { + final Address address = new Address(Locale.getDefault()); + for (int i = 1; i <= 6; i++) { + final String adminAreaName = "adminArea" + i; + setComponent(address, mapquestAddress, adminAreaName, mapquestAddress.path(adminAreaName + "Type").asText()); + } + setComponent(address, mapquestAddress, "postalCode", "PostalCode"); + int index = 0; + for (final String addressComponent: new String[]{ mapquestAddress.path("street").asText(), address.getSubLocality(), address.getLocality(), + address.getPostalCode(), address.getSubAdminArea(), address.getAdminArea(), address.getCountryCode() }) { + if (StringUtils.isNotBlank(addressComponent)) { + address.setAddressLine(index++, addressComponent); + } + } + address.setLatitude(mapquestAddress.get("latLng").get("lat").asDouble()); + address.setLongitude(mapquestAddress.get("latLng").get("lng").asDouble()); + return address; + } + + private static void setComponent(final Address address, final JsonNode mapquestAddress, final String adminArea, final String adminAreaType) { + final String content = StringUtils.trimToNull(mapquestAddress.path(adminArea).asText()); + switch (adminAreaType) { + case "City": + address.setLocality(content); + break; + case "Neighborhood": + address.setSubLocality(content); + break; + case "PostalCode": + address.setPostalCode(content); + break; + case "State": + address.setAdminArea(content); + break; + case "County": + address.setSubAdminArea(content); + break; + case "Country": + address.setCountryCode(content); + break; + } + } + +} diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java index b678d3b..8d2e13f 100644 --- a/main/src/cgeo/geocaching/settings/Settings.java +++ b/main/src/cgeo/geocaching/settings/Settings.java @@ -627,7 +627,7 @@ public class Settings { } public static boolean isMapTrail() { - return getBoolean(R.string.pref_maptrail, true); + return getBoolean(R.string.pref_maptrail, false); } public static void setMapTrail(final boolean showTrail) { diff --git a/main/src/cgeo/geocaching/ui/AddressListAdapter.java b/main/src/cgeo/geocaching/ui/AddressListAdapter.java index 691c8d2..455954a 100644 --- a/main/src/cgeo/geocaching/ui/AddressListAdapter.java +++ b/main/src/cgeo/geocaching/ui/AddressListAdapter.java @@ -9,6 +9,7 @@ import cgeo.geocaching.location.Geopoint; import cgeo.geocaching.location.Units; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNull; import android.app.Activity; import android.location.Address; @@ -23,7 +24,7 @@ import java.util.ArrayList; public class AddressListAdapter extends ArrayAdapter<Address> { final private LayoutInflater inflater; - final private Geopoint location; + @NonNull final private Geopoint location; protected static final class ViewHolder extends AbstractViewHolder { @InjectView(R.id.label) protected TextView label; @@ -72,7 +73,7 @@ public class AddressListAdapter extends ArrayAdapter<Address> { } private CharSequence getDistanceText(final Address address) { - if (location != null && address.hasLatitude() && address.hasLongitude()) { + if (address.hasLatitude() && address.hasLongitude()) { return Units.getDistanceFromKilometers(location.distanceTo(new Geopoint(address.getLatitude(), address.getLongitude()))); } diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java index 13887c0..7dd3847 100644 --- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java +++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java @@ -18,11 +18,9 @@ import org.eclipse.jdt.annotation.NonNull; import android.annotation.SuppressLint; import android.app.Activity; import android.content.res.Resources; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; +import android.widget.RatingBar; import android.widget.RelativeLayout; import android.widget.TextView; @@ -74,33 +72,18 @@ public final class CacheDetailsCreator { final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null, false); final TextView nameView = ButterKnife.findById(layout, R.id.name); lastValueView = ButterKnife.findById(layout, R.id.value); - final LinearLayout layoutStars = ButterKnife.findById(layout, R.id.stars); nameView.setText(activity.getResources().getString(nameId)); lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " " + String.format("%d", max)); - createStarImages(layoutStars, value, max); + + final RatingBar layoutStars = ButterKnife.findById(layout, R.id.stars); + layoutStars.setRating(value); layoutStars.setVisibility(View.VISIBLE); parentView.addView(layout); return layout; } - private void createStarImages(final ViewGroup starsContainer, final float value, final int max) { - final LayoutInflater inflater = LayoutInflater.from(activity); - - for (int i = 0; i < max; i++) { - final ImageView star = (ImageView) inflater.inflate(R.layout.star_image, starsContainer, false); - if (value - i >= 0.75) { - star.setImageResource(R.drawable.star_on); - } else if (value - i >= 0.25) { - star.setImageResource(R.drawable.star_half); - } else { - star.setImageResource(R.drawable.star_off); - } - starsContainer.addView(star); - } - } - public void addCacheState(final Geocache cache) { if (cache.isLogOffline() || cache.isArchived() || cache.isDisabled() || cache.isPremiumMembersOnly() || cache.isFound()) { final List<String> states = new ArrayList<>(5); diff --git a/tests/src/cgeo/geocaching/connector/gc/GCLoginTest.java b/tests/src/cgeo/geocaching/connector/gc/GCLoginTest.java index 07ba646..fc23ab3 100644 --- a/tests/src/cgeo/geocaching/connector/gc/GCLoginTest.java +++ b/tests/src/cgeo/geocaching/connector/gc/GCLoginTest.java @@ -6,10 +6,10 @@ import cgeo.geocaching.enumerations.StatusCode; import org.apache.commons.lang3.StringUtils; -import junit.framework.TestCase; - import android.test.suitebuilder.annotation.Suppress; +import junit.framework.TestCase; + public class GCLoginTest extends TestCase { final GCLogin instance = GCLogin.getInstance(); @@ -20,7 +20,7 @@ public class GCLoginTest extends TestCase { assertThat(instance.login()).isEqualTo(StatusCode.NO_ERROR); } - public void testHomeLocation() { + public static void testHomeLocation() { assertThat(StringUtils.isNotBlank(GCLogin.retrieveHomeLocation())).isTrue(); } diff --git a/tests/src/cgeo/geocaching/location/GeocoderTest.java b/tests/src/cgeo/geocaching/location/GeocoderTest.java new file mode 100644 index 0000000..f53c074 --- /dev/null +++ b/tests/src/cgeo/geocaching/location/GeocoderTest.java @@ -0,0 +1,48 @@ +package cgeo.geocaching.location; + +import static org.assertj.core.api.Assertions.assertThat; + +import cgeo.CGeoTestCase; +import cgeo.geocaching.CgeoApplication; + +import org.apache.commons.lang3.StringUtils; +import org.assertj.core.data.Offset; + +import rx.Observable; + +import android.annotation.TargetApi; +import android.location.Address; +import android.location.Geocoder; +import android.os.Build; + +public class GeocoderTest extends CGeoTestCase { + + private static final String TEST_ADDRESS = "46 rue Barrault, Paris, France"; + private static final double TEST_LATITUDE = 48.82677; + private static final double TEST_LONGITUDE = 2.34644; + private static final Offset<Double> TEST_OFFSET = Offset.offset(0.00050); + + @TargetApi(Build.VERSION_CODES.GINGERBREAD) + public static void testAndroidGeocoder() { + // Some emulators don't have access to Google Android geocoder + if (Geocoder.isPresent()) { + testGeocoder(new AndroidGeocoder(CgeoApplication.getInstance()).getFromLocationName(TEST_ADDRESS), "Android"); + } + } + + public static void testGCGeocoder() { + testGeocoder(GCGeocoder.getFromLocationName(TEST_ADDRESS), "GC"); + } + + public static void testMapQuestGeocoder() { + testGeocoder(MapQuestGeocoder.getFromLocationName(TEST_ADDRESS), "MapQuest"); + } + + public static void testGeocoder(final Observable<Address> addressObservable, final String geocoder) { + final Address address = addressObservable.toBlocking().first(); + assertThat(address.getLatitude()).as("latitude for " + geocoder + " geocoder").isCloseTo(TEST_LATITUDE, TEST_OFFSET); + assertThat(address.getLongitude()).as("longitude for " + geocoder + " geocoder").isCloseTo(TEST_LONGITUDE, TEST_OFFSET); + assertThat(StringUtils.lowerCase(address.getAddressLine(0))).as("street address for " + geocoder + " geocoder").startsWith("46 rue barrault"); + } + +} |