summaryrefslogtreecommitdiff
path: root/location/java/android
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2021-09-23 17:48:22 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-09-23 17:48:22 +0000
commit6b21c0accce193ca4e6589f69718b07736a5e9f3 (patch)
tree1e8bec1f6992f36c162374c0b8b7a60ad123fb50 /location/java/android
parent83d7e36d540ef4bba4940f3a56e61c85a61b7007 (diff)
parent03e0b8936267e58ff747219b183348372690108f (diff)
Merge "Add asynchronous geocoding API"
Diffstat (limited to 'location/java/android')
-rw-r--r--location/java/android/location/Geocoder.java309
-rw-r--r--location/java/android/location/GeocoderParams.java20
2 files changed, 235 insertions, 94 deletions
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 51586d708018..e4a0d0caceca 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -16,8 +16,11 @@
package android.location;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -27,24 +30,21 @@ import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
- * A class for handling geocoding and reverse geocoding. Geocoding is
- * the process of transforming a street address or other description
- * of a location into a (latitude, longitude) coordinate. Reverse
- * geocoding is the process of transforming a (latitude, longitude)
- * coordinate into a (partial) address. The amount of detail in a
- * reverse geocoded location description may vary, for example one
- * might contain the full street address of the closest building, while
- * another might contain only a city name and postal code.
+ * A class for handling geocoding and reverse geocoding. Geocoding is the process of transforming a
+ * street address or other description of a location into a (latitude, longitude) coordinate.
+ * Reverse geocoding is the process of transforming a (latitude, longitude) coordinate into a
+ * (partial) address. The amount of detail in a reverse geocoded location description may vary, for
+ * example one might contain the full street address of the closest building, while another might
+ * contain only a city name and postal code.
*
- * The Geocoder class requires a backend service that is not included in
- * the core android framework. The Geocoder query methods will return an
- * empty list if there no backend service in the platform. Use the
- * isPresent() method to determine whether a Geocoder implementation
- * exists.
+ * The Geocoder class requires a backend service that is not included in the core android framework.
+ * The Geocoder query methods will return an empty list if there no backend service in the platform.
+ * Use the isPresent() method to determine whether a Geocoder implementation exists.
*
* <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
* availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful or
@@ -52,20 +52,26 @@ import java.util.concurrent.TimeUnit;
*/
public final class Geocoder {
+ /** A listener for asynchronous geocoding results. */
+ public interface GeocodeListener {
+ /** Invoked when geocoding completes successfully. May return an empty list. */
+ void onGeocode(@NonNull List<Address> addresses);
+ /** Invoked when geocoding fails, with a brief error message. */
+ default void onError(@Nullable String errorMessage) {}
+ }
+
private static final long TIMEOUT_MS = 60000;
private final GeocoderParams mParams;
private final ILocationManager mService;
/**
- * Returns true if the Geocoder methods getFromLocation and
- * getFromLocationName are implemented. Lack of network
- * connectivity may still cause these methods to return null or
- * empty lists.
+ * Returns true if there is a geocoder implementation present that may return results. If true,
+ * there is still no guarantee that any individual geocoding attempt will succeed.
*/
public static boolean isPresent() {
- IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
- ILocationManager lm = ILocationManager.Stub.asInterface(b);
+ ILocationManager lm = Objects.requireNonNull(ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE)));
try {
return lm.geocoderIsPresent();
} catch (RemoteException e) {
@@ -74,40 +80,35 @@ public final class Geocoder {
}
/**
- * Constructs a Geocoder whose responses will be localized for the
- * given Locale.
- *
- * @param context the Context of the calling Activity
- * @param locale the desired Locale for the query results
- *
- * @throws NullPointerException if Locale is null
+ * Constructs a Geocoder localized for the default locale.
*/
- public Geocoder(Context context, Locale locale) {
- mParams = new GeocoderParams(context, locale);
- mService = ILocationManager.Stub.asInterface(
- ServiceManager.getService(Context.LOCATION_SERVICE));
+ public Geocoder(@NonNull Context context) {
+ this(context, Locale.getDefault());
}
/**
- * Constructs a Geocoder whose responses will be localized for the
- * default system Locale.
- *
- * @param context the Context of the calling Activity
+ * Constructs a Geocoder localized for the given locale.
*/
- public Geocoder(Context context) {
- this(context, Locale.getDefault());
+ public Geocoder(@NonNull Context context, @NonNull Locale locale) {
+ mParams = new GeocoderParams(context, locale);
+ mService = ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE));
}
/**
* Returns an array of Addresses that attempt to describe the area immediately surrounding the
* given latitude and longitude. The returned addresses should be localized for the locale
- * provided to this class's constructor. Results may be obtained by means of a network lookup
- * and this method may take some time to return, and so should not be called on the main thread.
+ * provided to this class's constructor.
*
- * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
* availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
* or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
- * purposes.
+ * purposes.</p>
+ *
+ * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+ * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+ * asynchronous version of this API. If that is not possible, this should be run on a background
+ * thread to avoid blocking other operations.</p>
*
* @param latitude the latitude a point for the search
* @param longitude the longitude a point for the search
@@ -116,22 +117,51 @@ public final class Geocoder {
* @return a list of Address objects. Returns null or empty list if no matches were
* found or there is no backend service available.
*
- * @throws IllegalArgumentException if latitude is
- * less than -90 or greater than 90
- * @throws IllegalArgumentException if longitude is
- * less than -180 or greater than 180
- * @throws IOException if the network is unavailable or any other
- * I/O problem occurs
+ * @throws IllegalArgumentException if latitude or longitude is invalid
+ * @throws IOException if there is a failure
+ *
+ * @deprecated Use {@link #getFromLocation(double, double, int, GeocodeListener)} instead to
+ * avoid blocking a thread waiting for results.
*/
- public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
+ @Deprecated
+ public @Nullable List<Address> getFromLocation(
+ @FloatRange(from = -90D, to = 90D) double latitude,
+ @FloatRange(from = -180D, to = 180D)double longitude,
+ @IntRange int maxResults)
throws IOException {
+ SynchronousGeocoder listener = new SynchronousGeocoder();
+ getFromLocation(latitude, longitude, maxResults, listener);
+ return listener.getResults();
+ }
+
+ /**
+ * Provides an array of Addresses that attempt to describe the area immediately surrounding the
+ * given latitude and longitude. The returned addresses should be localized for the locale
+ * provided to this class's constructor.
+ *
+ * <p class="warning"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.</p>
+ *
+ * @param latitude the latitude a point for the search
+ * @param longitude the longitude a point for the search
+ * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
+ * @param listener a listener for receiving results
+ *
+ * @throws IllegalArgumentException if latitude or longitude is invalid
+ */
+ public void getFromLocation(
+ @FloatRange(from = -90D, to = 90D) double latitude,
+ @FloatRange(from = -180D, to = 180D) double longitude,
+ @IntRange int maxResults,
+ @NonNull GeocodeListener listener) {
Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
try {
- GeocodeListener listener = new GeocodeListener();
- mService.getFromLocation(latitude, longitude, maxResults, mParams, listener);
- return listener.getResults();
+ mService.getFromLocation(latitude, longitude, maxResults, mParams,
+ new GeocoderImpl(listener));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -141,14 +171,17 @@ public final class Geocoder {
* Returns an array of Addresses that attempt to describe the named location, which may be a
* place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
* View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
- * localized for the locale provided to this class's constructor. Results may be obtained by
- * means of a network lookup and this method may take some time to return, and so should not be
- * called on the main thread.
+ * localized for the locale provided to this class's constructor.
*
* <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
* availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
* or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
- * purposes.
+ * purposes.</p>
+ *
+ * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+ * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+ * asynchronous version of this API. If that is not possible, this should be run on a background
+ * thread to avoid blocking other operations.</p>
*
* @param locationName a user-supplied description of a location
* @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
@@ -157,20 +190,47 @@ public final class Geocoder {
* found or there is no backend service available.
*
* @throws IllegalArgumentException if locationName is null
- * @throws IOException if the network is unavailable or any other
- * I/O problem occurs
+ * @throws IOException if there is a failure
+ *
+ * @deprecated Use {@link #getFromLocationName(String, int, GeocodeListener)} instead to avoid
+ * blocking a thread waiting for results.
*/
- public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException {
+ @Deprecated
+ public @Nullable List<Address> getFromLocationName(
+ @NonNull String locationName,
+ @IntRange int maxResults) throws IOException {
return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
}
/**
+ * Provides an array of Addresses that attempt to describe the named location, which may be a
+ * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+ * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+ * localized for the locale provided to this class's constructor.
+ *
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.</p>
+ *
+ * @param locationName a user-supplied description of a location
+ * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
+ * @param listener a listener for receiving results
+ *
+ * @throws IllegalArgumentException if locationName is null
+ */
+ public void getFromLocationName(
+ @NonNull String locationName,
+ @IntRange int maxResults,
+ @NonNull GeocodeListener listener) {
+ getFromLocationName(locationName, maxResults, 0, 0, 0, 0, listener);
+ }
+
+ /**
* Returns an array of Addresses that attempt to describe the named location, which may be a
* place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
* View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
- * localized for the locale provided to this class's constructor. Results may be obtained by
- * means of a network lookup and this method may take some time to return, and so should not be
- * called on the main thread.
+ * localized for the locale provided to this class's constructor.
*
* <p> You may specify a bounding box for the search results by including the latitude and
* longitude of the lower left point and upper right point of the box.
@@ -178,29 +238,78 @@ public final class Geocoder {
* <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
* availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
* or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
- * purposes.
+ * purposes.</p>
*
- * @param locationName a user-supplied description of a location
- * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended
- * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
- * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
- * @param upperRightLatitude the latitude of the upper right corner of the bounding box
+ * <p class="warning"><strong>Warning:</strong> This API may hit the network, and may block for
+ * excessive amounts of time, up to 60 seconds or more. It's strongly encouraged to use the
+ * asynchronous version of this API. If that is not possible, this should be run on a background
+ * thread to avoid blocking other operations.</p>
+ *
+ * @param locationName a user-supplied description of a location
+ * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are
+ * recommended
+ * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
+ * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
+ * @param upperRightLatitude the latitude of the upper right corner of the bounding box
* @param upperRightLongitude the longitude of the upper right corner of the bounding box
*
* @return a list of Address objects. Returns null or empty list if no matches were
* found or there is no backend service available.
*
* @throws IllegalArgumentException if locationName is null
- * @throws IllegalArgumentException if any latitude is
- * less than -90 or greater than 90
- * @throws IllegalArgumentException if any longitude is
- * less than -180 or greater than 180
- * @throws IOException if the network is unavailable or any other
- * I/O problem occurs
+ * @throws IllegalArgumentException if any latitude or longitude is invalid
+ * @throws IOException if there is a failure
+ *
+ * @deprecated Use {@link #getFromLocationName(String, int, double, double, double, double,
+ * GeocodeListener)} instead to avoid blocking a thread waiting for results.
*/
- public List<Address> getFromLocationName(String locationName, int maxResults,
- double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
- double upperRightLongitude) throws IOException {
+ @Deprecated
+ public @Nullable List<Address> getFromLocationName(
+ @NonNull String locationName,
+ @IntRange int maxResults,
+ @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
+ @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
+ @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
+ @FloatRange(from = -180D, to = 180D) double upperRightLongitude) throws IOException {
+ SynchronousGeocoder listener = new SynchronousGeocoder();
+ getFromLocationName(locationName, maxResults, lowerLeftLatitude, lowerLeftLongitude,
+ upperRightLatitude, upperRightLongitude, listener);
+ return listener.getResults();
+ }
+
+ /**
+ * Returns an array of Addresses that attempt to describe the named location, which may be a
+ * place name such as "Dalvik, Iceland", an address such as "1600 Amphitheatre Parkway, Mountain
+ * View, CA", an airport code such as "SFO", and so forth. The returned addresses should be
+ * localized for the locale provided to this class's constructor.
+ *
+ * <p> You may specify a bounding box for the search results by including the latitude and
+ * longitude of the lower left point and upper right point of the box.
+ *
+ * <p class="note"><strong>Warning:</strong> Geocoding services may provide no guarantees on
+ * availability or accuracy. Results are a best guess, and are not guaranteed to be meaningful
+ * or correct. Do <b>NOT</b> use this API for any safety-critical or regulatory compliance
+ * purposes.</p>
+ *
+ * @param locationName a user-supplied description of a location
+ * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are
+ * recommended
+ * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box
+ * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box
+ * @param upperRightLatitude the latitude of the upper right corner of the bounding box
+ * @param upperRightLongitude the longitude of the upper right corner of the bounding box
+ *
+ * @throws IllegalArgumentException if locationName is null
+ * @throws IllegalArgumentException if any latitude or longitude is invalid
+ */
+ public void getFromLocationName(
+ @NonNull String locationName,
+ @IntRange int maxResults,
+ @FloatRange(from = -90D, to = 90D) double lowerLeftLatitude,
+ @FloatRange(from = -180D, to = 180D) double lowerLeftLongitude,
+ @FloatRange(from = -90D, to = 90D) double upperRightLatitude,
+ @FloatRange(from = -180D, to = 180D) double upperRightLongitude,
+ @NonNull GeocodeListener listener) {
Preconditions.checkArgument(locationName != null);
Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
@@ -209,27 +318,59 @@ public final class Geocoder {
"upperRightLongitude");
try {
- GeocodeListener listener = new GeocodeListener();
mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude,
- upperRightLatitude, upperRightLongitude, maxResults, mParams, listener);
- return listener.getResults();
+ upperRightLatitude, upperRightLongitude, maxResults, mParams,
+ new GeocoderImpl(listener));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- private static class GeocodeListener extends IGeocodeListener.Stub {
+ private static class GeocoderImpl extends IGeocodeListener.Stub {
+
+ private GeocodeListener mListener;
+
+ GeocoderImpl(GeocodeListener listener) {
+ mListener = Objects.requireNonNull(listener);
+ }
+
+ @Override
+ public void onResults(String error, List<Address> addresses) throws RemoteException {
+ if (mListener == null) {
+ return;
+ }
+
+ GeocodeListener listener = mListener;
+ mListener = null;
+
+ if (error != null) {
+ listener.onError(error);
+ } else {
+ if (addresses == null) {
+ addresses = Collections.emptyList();
+ }
+ listener.onGeocode(addresses);
+ }
+ }
+ }
+
+ private static class SynchronousGeocoder implements GeocodeListener {
private final CountDownLatch mLatch = new CountDownLatch(1);
private String mError = null;
private List<Address> mResults = Collections.emptyList();
- GeocodeListener() {}
+ SynchronousGeocoder() {}
+
+ @Override
+ public void onGeocode(List<Address> addresses) {
+ mResults = addresses;
+ mLatch.countDown();
+ }
@Override
- public void onResults(String error, List<Address> results) {
- mError = error;
- mResults = results;
+ public void onError(String errorMessage) {
+ mError = errorMessage;
mLatch.countDown();
}
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index b00a9a99e75d..3ea6364e07c5 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -95,11 +95,11 @@ public class GeocoderParams implements Parcelable {
new Parcelable.Creator<GeocoderParams>() {
public GeocoderParams createFromParcel(Parcel in) {
int uid = in.readInt();
- String packageName = in.readString();
- String attributionTag = in.readString();
- String language = in.readString();
- String country = in.readString();
- String variant = in.readString();
+ String packageName = in.readString8();
+ String attributionTag = in.readString8();
+ String language = in.readString8();
+ String country = in.readString8();
+ String variant = in.readString8();
return new GeocoderParams(uid, packageName, attributionTag,
new Locale(language, country, variant));
@@ -116,10 +116,10 @@ public class GeocoderParams implements Parcelable {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mUid);
- parcel.writeString(mPackageName);
- parcel.writeString(mAttributionTag);
- parcel.writeString(mLocale.getLanguage());
- parcel.writeString(mLocale.getCountry());
- parcel.writeString(mLocale.getVariant());
+ parcel.writeString8(mPackageName);
+ parcel.writeString8(mAttributionTag);
+ parcel.writeString8(mLocale.getLanguage());
+ parcel.writeString8(mLocale.getCountry());
+ parcel.writeString8(mLocale.getVariant());
}
}