Merge "Refactor Geocoder Provider System APIs" into main
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index 26dc700..adcc3df 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -133,8 +133,6 @@
Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ICountryListener$Stub;-><init>()V
-Landroid/location/IGeocodeProvider$Stub;-><init>()V
-Landroid/location/IGeocodeProvider$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/IGeocodeProvider;
Landroid/location/ILocationListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ILocationListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/location/ILocationListener$Stub;-><init>()V
diff --git a/location/api/current.txt b/location/api/current.txt
index 5ed8c3c..85e9f65 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -88,12 +88,12 @@
public final class Geocoder {
ctor public Geocoder(@NonNull android.content.Context);
ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
- method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
- method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
- method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
- method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
- method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
- method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
+ method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int) throws java.io.IOException;
+ method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int, @NonNull android.location.Geocoder.GeocodeListener);
+ method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange(from=1) int) throws java.io.IOException;
+ method public void getFromLocationName(@NonNull String, @IntRange(from=1) int, @NonNull android.location.Geocoder.GeocodeListener);
+ method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange(from=1) int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
+ method public void getFromLocationName(@NonNull String, @IntRange(from=1) int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
method public static boolean isPresent();
}
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index b1cf96d..2e7a541 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -591,6 +591,36 @@
package android.location.provider {
+ @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ForwardGeocodeRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getCallingAttributionTag();
+ method @NonNull public String getCallingPackage();
+ method public int getCallingUid();
+ method @NonNull public java.util.Locale getLocale();
+ method @NonNull public String getLocationName();
+ method @FloatRange(from=-90.0, to=90.0) public double getLowerLeftLatitude();
+ method @FloatRange(from=-180.0, to=180.0) public double getLowerLeftLongitude();
+ method @IntRange(from=1) public int getMaxResults();
+ method @FloatRange(from=-90.0, to=90.0) public double getUpperRightLatitude();
+ method @FloatRange(from=-180.0, to=180.0) public double getUpperRightLongitude();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ForwardGeocodeRequest> CREATOR;
+ }
+
+ public static final class ForwardGeocodeRequest.Builder {
+ ctor public ForwardGeocodeRequest.Builder(@NonNull String, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=1) int, @NonNull java.util.Locale, int, @NonNull String);
+ method @NonNull public android.location.provider.ForwardGeocodeRequest build();
+ method @NonNull public android.location.provider.ForwardGeocodeRequest.Builder setCallingAttributionTag(@NonNull String);
+ }
+
+ @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public abstract class GeocodeProviderBase {
+ ctor public GeocodeProviderBase(@NonNull android.content.Context, @NonNull String);
+ method @NonNull public final android.os.IBinder getBinder();
+ method public abstract void onForwardGeocode(@NonNull android.location.provider.ForwardGeocodeRequest, @NonNull android.os.OutcomeReceiver<java.util.List<android.location.Address>,java.lang.Exception>);
+ method public abstract void onReverseGeocode(@NonNull android.location.provider.ReverseGeocodeRequest, @NonNull android.os.OutcomeReceiver<java.util.List<android.location.Address>,java.lang.Exception>);
+ field public static final String ACTION_GEOCODE_PROVIDER = "com.android.location.service.GeocodeProvider";
+ }
+
public abstract class LocationProviderBase {
ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
method @Nullable public final android.os.IBinder getBinder();
@@ -642,5 +672,24 @@
method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
}
+ @FlaggedApi(Flags.FLAG_NEW_GEOCODER) public final class ReverseGeocodeRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getCallingAttributionTag();
+ method @NonNull public String getCallingPackage();
+ method public int getCallingUid();
+ method @FloatRange(from=-90.0, to=90.0) public double getLatitude();
+ method @NonNull public java.util.Locale getLocale();
+ method @FloatRange(from=-180.0, to=180.0) public double getLongitude();
+ method @IntRange(from=1) public int getMaxResults();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ReverseGeocodeRequest> CREATOR;
+ }
+
+ public static final class ReverseGeocodeRequest.Builder {
+ ctor public ReverseGeocodeRequest.Builder(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange(from=0) int, @NonNull java.util.Locale, int, @NonNull String);
+ method @NonNull public android.location.provider.ReverseGeocodeRequest build();
+ method @NonNull public android.location.provider.ReverseGeocodeRequest.Builder setCallingAttributionTag(@NonNull String);
+ }
+
}
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index a158344..cdde7c6 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -21,11 +21,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.ReverseGeocodeRequest;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import com.android.internal.util.Preconditions;
-
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@@ -33,6 +35,7 @@
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A class for handling geocoding and reverse geocoding. Geocoding is the process of transforming a
@@ -42,9 +45,12 @@
* 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.
+ * <p>Use the isPresent() method to determine whether a Geocoder implementation exists on the
+ * current device. If no implementation is present, any attempt to geocode will result in an error.
+ *
+ * <p>Geocoder implementations are only required to make a best effort to return results in the
+ * chosen locale. Note that geocoder implementations may return results in other locales if they
+ * have no information available for the chosen locale.
*
* <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,45 +58,53 @@
*/
public final class Geocoder {
- /** A listener for asynchronous geocoding results. */
+ /**
+ * A listener for asynchronous geocoding results. Only one of the methods will ever be invoked
+ * per geocoding attempt. There are no guarantees on how long it will take for a method to be
+ * invoked, nor any guarantees on the format or availability of error information.
+ */
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. */
+
+ /** Invoked when geocoding fails, with an optional error message. */
default void onError(@Nullable String errorMessage) {}
}
- private static final long TIMEOUT_MS = 60000;
+ private static final long TIMEOUT_MS = 15000;
- private final GeocoderParams mParams;
+ private final Context mContext;
+ private final Locale mLocale;
private final ILocationManager mService;
/**
- * 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.
+ * Returns true if there is a geocoder implementation present on the device that may return
+ * results. If true, there is still no guarantee that any individual geocoding attempt will
+ * succeed.
*/
public static boolean isPresent() {
ILocationManager lm = Objects.requireNonNull(ILocationManager.Stub.asInterface(
ServiceManager.getService(Context.LOCATION_SERVICE)));
try {
- return lm.geocoderIsPresent();
+ return lm.isGeocodeAvailable();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- /**
- * Constructs a Geocoder localized for the default locale.
- */
+ /** Constructs a Geocoder localized for {@link Locale#getDefault()}. */
public Geocoder(@NonNull Context context) {
this(context, Locale.getDefault());
}
/**
- * Constructs a Geocoder localized for the given locale.
+ * Constructs a Geocoder localized for the given locale. Note that geocoder implementations will
+ * only make a best effort to return results in the given locale, and there is no guarantee that
+ * returned results will be in the specific locale.
*/
public Geocoder(@NonNull Context context, @NonNull Locale locale) {
- mParams = new GeocoderParams(context, locale);
+ mContext = Objects.requireNonNull(context);
+ mLocale = Objects.requireNonNull(locale);
mService = ILocationManager.Stub.asInterface(
ServiceManager.getService(Context.LOCATION_SERVICE));
}
@@ -103,31 +117,28 @@
* <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>
+ * purposes.
*
* <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>
+ * excessive amounts of time. 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.
*
* @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
- *
- * @return a list of Address objects. Returns null or empty list if no matches were
- * found or there is no backend service available.
- *
+ * @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 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.
+ * avoid blocking a thread waiting for results.
*/
@Deprecated
public @Nullable List<Address> getFromLocation(
@FloatRange(from = -90D, to = 90D) double latitude,
- @FloatRange(from = -180D, to = 180D)double longitude,
- @IntRange int maxResults)
+ @FloatRange(from = -180D, to = 180D) double longitude,
+ @IntRange(from = 1) int maxResults)
throws IOException {
SynchronousGeocoder listener = new SynchronousGeocoder();
getFromLocation(latitude, longitude, maxResults, listener);
@@ -142,26 +153,32 @@
* <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>
+ * purposes.
*
* @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,
+ @IntRange(from = 1) int maxResults,
@NonNull GeocodeListener listener) {
- Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
- Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
-
+ ReverseGeocodeRequest.Builder b =
+ new ReverseGeocodeRequest.Builder(
+ latitude,
+ longitude,
+ maxResults,
+ mLocale,
+ Process.myUid(),
+ mContext.getPackageName());
+ if (mContext.getAttributionTag() != null) {
+ b.setCallingAttributionTag(mContext.getAttributionTag());
+ }
try {
- mService.getFromLocation(latitude, longitude, maxResults, mParams,
- new GeocoderImpl(listener));
+ mService.reverseGeocode(b.build(), new GeocodeCallbackImpl(listener));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -176,29 +193,25 @@
* <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>
+ * purposes.
*
* <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>
+ * excessive amounts of time. 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.
*
* @param locationName a user-supplied description of a location
* @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended
- *
- * @return a list of Address objects. Returns null or empty list if no matches were
- * found or there is no backend service available.
- *
+ * @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 IOException if there is a failure
- *
* @deprecated Use {@link #getFromLocationName(String, int, GeocodeListener)} instead to avoid
- * blocking a thread waiting for results.
+ * blocking a thread waiting for results.
*/
@Deprecated
public @Nullable List<Address> getFromLocationName(
- @NonNull String locationName,
- @IntRange int maxResults) throws IOException {
+ @NonNull String locationName, @IntRange(from = 1) int maxResults) throws IOException {
return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
}
@@ -211,17 +224,16 @@
* <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>
+ * purposes.
*
* @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,
+ @IntRange(from = 1) int maxResults,
@NonNull GeocodeListener listener) {
getFromLocationName(locationName, maxResults, 0, 0, 0, 0, listener);
}
@@ -232,45 +244,42 @@
* 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
+ * <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>
+ * purposes.
*
* <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>
+ * excessive amounts of time. 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.
*
- * @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 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.
- *
+ * @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 or longitude is invalid
- * @throws IOException if there is a failure
- *
+ * @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.
+ * GeocodeListener)} instead to avoid blocking a thread waiting for results.
*/
@Deprecated
public @Nullable List<Address> getFromLocationName(
@NonNull String locationName,
- @IntRange int maxResults,
+ @IntRange(from = 1) 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 {
+ @FloatRange(from = -180D, to = 180D) double upperRightLongitude)
+ throws IOException {
SynchronousGeocoder listener = new SynchronousGeocoder();
getFromLocationName(locationName, maxResults, lowerLeftLatitude, lowerLeftLongitude,
upperRightLatitude, upperRightLongitude, listener);
@@ -283,75 +292,79 @@
* 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
+ * <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>
+ * purposes.
*
- * @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 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
- * @param listener a listener for receiving results
- *
+ * @param listener a listener for receiving results
* @throws IllegalArgumentException if locationName is null
* @throws IllegalArgumentException if any latitude or longitude is invalid
*/
public void getFromLocationName(
@NonNull String locationName,
- @IntRange int maxResults,
+ @IntRange(from = 1) 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");
- Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
- Preconditions.checkArgumentInRange(upperRightLongitude, -180.0, 180.0,
- "upperRightLongitude");
-
+ ForwardGeocodeRequest.Builder b =
+ new ForwardGeocodeRequest.Builder(
+ locationName,
+ lowerLeftLatitude,
+ lowerLeftLongitude,
+ upperRightLatitude,
+ upperRightLongitude,
+ maxResults,
+ mLocale,
+ Process.myUid(),
+ mContext.getPackageName());
+ if (mContext.getAttributionTag() != null) {
+ b.setCallingAttributionTag(mContext.getAttributionTag());
+ }
try {
- mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude,
- upperRightLatitude, upperRightLongitude, maxResults, mParams,
- new GeocoderImpl(listener));
+ mService.forwardGeocode(b.build(), new GeocodeCallbackImpl(listener));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- private static class GeocoderImpl extends IGeocodeListener.Stub {
+ private static class GeocodeCallbackImpl extends IGeocodeCallback.Stub {
- private GeocodeListener mListener;
+ @Nullable private GeocodeListener mListener;
- GeocoderImpl(GeocodeListener listener) {
+ GeocodeCallbackImpl(GeocodeListener listener) {
mListener = Objects.requireNonNull(listener);
}
@Override
- public void onResults(String error, List<Address> addresses) throws RemoteException {
+ public void onError(@Nullable String error) {
if (mListener == null) {
return;
}
- GeocodeListener listener = mListener;
+ mListener.onError(error);
mListener = null;
+ }
- if (error != null) {
- listener.onError(error);
- } else {
- if (addresses == null) {
- addresses = Collections.emptyList();
- }
- listener.onGeocode(addresses);
+ @Override
+ public void onResults(List<Address> addresses) {
+ if (mListener == null) {
+ return;
}
+
+ mListener.onGeocode(addresses);
+ mListener = null;
}
}
@@ -364,21 +377,21 @@
SynchronousGeocoder() {}
@Override
- public void onGeocode(List<Address> addresses) {
+ public void onGeocode(@NonNull List<Address> addresses) {
mResults = addresses;
mLatch.countDown();
}
@Override
- public void onError(String errorMessage) {
- mError = errorMessage;
+ public void onError(@Nullable String error) {
+ mError = error;
mLatch.countDown();
}
public List<Address> getResults() throws IOException {
try {
if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- mError = "Service not Available";
+ throw new IOException(new TimeoutException());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl
deleted file mode 100644
index e661ca6..0000000
--- a/location/java/android/location/IGeocodeProvider.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.location;
-
-import android.location.Address;
-import android.location.IGeocodeListener;
-import android.location.GeocoderParams;
-
-/**
- * An interface for location providers implementing the Geocoder services.
- *
- * {@hide}
- */
-interface IGeocodeProvider {
-
- oneway void getFromLocation(double latitude, double longitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener);
- oneway void getFromLocationName(String locationName, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
- double upperRightLongitude, int maxResults, in GeocoderParams params, in IGeocodeListener listener);
-}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 72761ef..c96c118 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -19,13 +19,11 @@
import android.app.PendingIntent;
import android.location.Address;
import android.location.Criteria;
-import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssAntennaInfo;
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
-import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
@@ -37,8 +35,11 @@
import android.location.Location;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
+import android.location.provider.ReverseGeocodeRequest;
import android.os.Bundle;
import android.os.ICancellationSignal;
import android.os.PackageTagsList;
@@ -68,13 +69,9 @@
void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
void removeGeofence(in PendingIntent intent);
- boolean geocoderIsPresent();
- void getFromLocation(double latitude, double longitude, int maxResults,
- in GeocoderParams params, in IGeocodeListener listener);
- void getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- in GeocoderParams params, in IGeocodeListener listener);
+ boolean isGeocodeAvailable();
+ void reverseGeocode(in ReverseGeocodeRequest request, in IGeocodeCallback callback);
+ void forwardGeocode(in ForwardGeocodeRequest request, in IGeocodeCallback callback);
GnssCapabilities getGnssCapabilities();
int getGnssYearOfHardware();
diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig
index 0fa641b..156be38 100644
--- a/location/java/android/location/flags/location.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -1,6 +1,13 @@
package: "android.location.flags"
flag {
+ name: "new_geocoder"
+ namespace: "location"
+ description: "Flag for new Geocoder APIs"
+ bug: "229872126"
+}
+
+flag {
name: "location_bypass"
namespace: "location"
description: "Enable location bypass appops behavior"
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/provider/ForwardGeocodeRequest.aidl
similarity index 74%
copy from location/java/android/location/GeocoderParams.aidl
copy to location/java/android/location/provider/ForwardGeocodeRequest.aidl
index 2484e20..acd6190 100644
--- a/location/java/android/location/GeocoderParams.aidl
+++ b/location/java/android/location/provider/ForwardGeocodeRequest.aidl
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2010, The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.location;
+package android.location.provider;
-parcelable GeocoderParams;
+parcelable ForwardGeocodeRequest;
diff --git a/location/java/android/location/provider/ForwardGeocodeRequest.java b/location/java/android/location/provider/ForwardGeocodeRequest.java
new file mode 100644
index 0000000..8f227b1
--- /dev/null
+++ b/location/java/android/location/provider/ForwardGeocodeRequest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import static java.lang.Math.max;
+
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.location.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Forward geocode (ie from address to lat/lng) provider request.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public final class ForwardGeocodeRequest implements Parcelable {
+
+ private final String mLocationName;
+ private final double mLowerLeftLatitude;
+ private final double mLowerLeftLongitude;
+ private final double mUpperRightLatitude;
+ private final double mUpperRightLongitude;
+ private final int mMaxResults;
+ private final Locale mLocale;
+ private final int mCallingUid;
+ private final String mCallingPackage;
+ @Nullable private final String mCallingAttributionTag;
+
+ private ForwardGeocodeRequest(
+ @NonNull String locationName,
+ double lowerLeftLatitude,
+ double lowerLeftLongitude,
+ double upperRightLatitude,
+ double upperRightLongitude,
+ int maxResults,
+ @NonNull Locale locale,
+ int callingUid,
+ @NonNull String callingPackage,
+ @Nullable String callingAttributionTag) {
+ Preconditions.checkArgument(locationName != null, "locationName must not be null");
+ Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
+ Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
+ Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
+ Preconditions.checkArgumentInRange(
+ upperRightLongitude, -180.0, 180.0, "upperRightLongitude");
+
+ mLocationName = locationName;
+ mLowerLeftLatitude = lowerLeftLatitude;
+ mLowerLeftLongitude = lowerLeftLongitude;
+ mUpperRightLatitude = upperRightLatitude;
+ mUpperRightLongitude = upperRightLongitude;
+ mMaxResults = max(maxResults, 1);
+ mLocale = Objects.requireNonNull(locale);
+
+ mCallingUid = callingUid;
+ mCallingPackage = Objects.requireNonNull(callingPackage);
+ mCallingAttributionTag = callingAttributionTag;
+ }
+
+ /**
+ * The location name to be forward geocoded. An arbitrary user string that could have any value.
+ */
+ @NonNull
+ public String getLocationName() {
+ return mLocationName;
+ }
+
+ /** The lower left latitude of the bounding box that should constrain forward geocoding. */
+ @FloatRange(from = -90.0, to = 90.0)
+ public double getLowerLeftLatitude() {
+ return mLowerLeftLatitude;
+ }
+
+ /** The lower left longitude of the bounding box that should constrain forward geocoding. */
+ @FloatRange(from = -180.0, to = 180.0)
+ public double getLowerLeftLongitude() {
+ return mLowerLeftLongitude;
+ }
+
+ /** The upper right latitude of the bounding box that should constrain forward geocoding. */
+ @FloatRange(from = -90.0, to = 90.0)
+ public double getUpperRightLatitude() {
+ return mUpperRightLatitude;
+ }
+
+ /** The upper right longitude of the bounding box that should constrain forward geocoding. */
+ @FloatRange(from = -180.0, to = 180.0)
+ public double getUpperRightLongitude() {
+ return mUpperRightLongitude;
+ }
+
+ /** The maximum number of forward geocoding results that should be returned. */
+ @IntRange(from = 1)
+ public int getMaxResults() {
+ return mMaxResults;
+ }
+
+ /** The locale that results should be localized to (best effort). */
+ @NonNull
+ public Locale getLocale() {
+ return mLocale;
+ }
+
+ /** The UID of the caller this geocoding request is happening on behalf of. */
+ public int getCallingUid() {
+ return mCallingUid;
+ }
+
+ /** The package of the caller this geocoding request is happening on behalf of. */
+ @NonNull
+ public String getCallingPackage() {
+ return mCallingPackage;
+ }
+
+ /** The attribution tag of the caller this geocoding request is happening on behalf of. */
+ @Nullable
+ public String getCallingAttributionTag() {
+ return mCallingAttributionTag;
+ }
+
+ public static final @NonNull Creator<ForwardGeocodeRequest> CREATOR =
+ new Creator<>() {
+ @Override
+ public ForwardGeocodeRequest createFromParcel(Parcel in) {
+ return new ForwardGeocodeRequest(
+ Objects.requireNonNull(in.readString8()),
+ in.readDouble(),
+ in.readDouble(),
+ in.readDouble(),
+ in.readDouble(),
+ in.readInt(),
+ new Locale(in.readString8(), in.readString8(), in.readString8()),
+ in.readInt(),
+ Objects.requireNonNull(in.readString8()),
+ in.readString8());
+ }
+
+ @Override
+ public ForwardGeocodeRequest[] newArray(int size) {
+ return new ForwardGeocodeRequest[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeString8(mLocationName);
+ parcel.writeDouble(mLowerLeftLatitude);
+ parcel.writeDouble(mLowerLeftLongitude);
+ parcel.writeDouble(mUpperRightLatitude);
+ parcel.writeDouble(mUpperRightLongitude);
+ parcel.writeInt(mMaxResults);
+ parcel.writeString8(mLocale.getLanguage());
+ parcel.writeString8(mLocale.getCountry());
+ parcel.writeString8(mLocale.getVariant());
+ parcel.writeInt(mCallingUid);
+ parcel.writeString8(mCallingPackage);
+ parcel.writeString8(mCallingAttributionTag);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof ForwardGeocodeRequest that) {
+ return mLowerLeftLatitude == that.mLowerLeftLatitude
+ && mLowerLeftLongitude == that.mLowerLeftLongitude
+ && mUpperRightLatitude == that.mUpperRightLatitude
+ && mUpperRightLongitude == that.mUpperRightLongitude
+ && mMaxResults == that.mMaxResults
+ && mCallingUid == that.mCallingUid
+ && mLocale.equals(that.mLocale)
+ && mCallingPackage.equals(that.mCallingPackage)
+ && mLocationName.equals(that.mLocationName)
+ && Objects.equals(mCallingAttributionTag, that.mCallingAttributionTag);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mLocationName,
+ mLowerLeftLatitude,
+ mLowerLeftLongitude,
+ mUpperRightLatitude,
+ mUpperRightLongitude,
+ mMaxResults,
+ mLocale,
+ mCallingUid,
+ mCallingPackage,
+ mCallingAttributionTag);
+ }
+
+ /** A Builder for {@link ReverseGeocodeRequest}s. */
+ public static final class Builder {
+
+ private final String mLocationName;
+ private final double mLowerLeftLatitude;
+ private final double mLowerLeftLongitude;
+ private final double mUpperRightLatitude;
+ private final double mUpperRightLongitude;
+ private final int mMaxResults;
+ private final Locale mLocale;
+
+ private final int mCallingUid;
+ private final String mCallingPackage;
+ @Nullable private String mCallingAttributionTag;
+
+ /** Creates a new Builder instance with the given parameters. */
+ public Builder(
+ @NonNull String locationName,
+ @FloatRange(from = -90.0, to = 90.0) double lowerLeftLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double lowerLeftLongitude,
+ @FloatRange(from = -90.0, to = 90.0) double upperRightLatitude,
+ @FloatRange(from = -180.0, to = 180.0) double upperRightLongitude,
+ @IntRange(from = 1) int maxResults,
+ @NonNull Locale locale,
+ int callingUid,
+ @NonNull String callingPackage) {
+ mLocationName = locationName;
+ mLowerLeftLatitude = lowerLeftLatitude;
+ mLowerLeftLongitude = lowerLeftLongitude;
+ mUpperRightLatitude = upperRightLatitude;
+ mUpperRightLongitude = upperRightLongitude;
+ mMaxResults = maxResults;
+ mLocale = locale;
+ mCallingUid = callingUid;
+ mCallingPackage = callingPackage;
+ mCallingAttributionTag = null;
+ }
+
+ /** Sets the attribution tag. */
+ @NonNull
+ public Builder setCallingAttributionTag(@NonNull String attributionTag) {
+ mCallingAttributionTag = attributionTag;
+ return this;
+ }
+
+ /** Builds a {@link ForwardGeocodeRequest}. */
+ @NonNull
+ public ForwardGeocodeRequest build() {
+ return new ForwardGeocodeRequest(
+ mLocationName,
+ mLowerLeftLatitude,
+ mLowerLeftLongitude,
+ mUpperRightLatitude,
+ mUpperRightLongitude,
+ mMaxResults,
+ mLocale,
+ mCallingUid,
+ mCallingPackage,
+ mCallingAttributionTag);
+ }
+ }
+}
diff --git a/location/java/android/location/provider/GeocodeProviderBase.java b/location/java/android/location/provider/GeocodeProviderBase.java
new file mode 100644
index 0000000..e2c48b9
--- /dev/null
+++ b/location/java/android/location/provider/GeocodeProviderBase.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Address;
+import android.location.flags.Flags;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.OutcomeReceiver;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Base class for geocode providers outside the system server.
+ *
+ * <p>Geocode providers should be wrapped in a non-exported service which returns the result of
+ * {@link #getBinder()} from the service's {@link android.app.Service#onBind(Intent)} method. The
+ * service should not be exported so that components other than the system server cannot bind to it.
+ * Alternatively, the service may be guarded by a permission that only system server can obtain. The
+ * service may specify metadata on its capabilities:
+ *
+ * <ul>
+ * <li>"serviceVersion": An integer version code to help tie break if multiple services are
+ * capable of implementing the geocode provider. All else equal, the service with the highest
+ * version code will be chosen. Assumed to be 0 if not specified.
+ * <li>"serviceIsMultiuser": A boolean property, indicating if the service wishes to take
+ * responsibility for handling changes to the current user on the device. If true, the service
+ * will always be bound from the system user. If false, the service will always be bound from
+ * the current user. If the current user changes, the old binding will be released, and a new
+ * binding established under the new user. Assumed to be false if not specified.
+ * </ul>
+ *
+ * <p>The service should have an intent filter in place for the geocode provider as specified by the
+ * constant in this class.
+ *
+ * <p>Geocode providers are identified by their UID / package name / attribution tag. Based on this
+ * identity, geocode providers may be given some special privileges.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public abstract class GeocodeProviderBase {
+
+ /**
+ * The action the wrapping service should have in its intent filter to implement the geocode
+ * provider.
+ */
+ @SuppressLint("ActionValue")
+ public static final String ACTION_GEOCODE_PROVIDER =
+ "com.android.location.service.GeocodeProvider";
+
+ final String mTag;
+ @Nullable final String mAttributionTag;
+ final IBinder mBinder;
+
+ /**
+ * Subclasses should pass in a context and an arbitrary tag that may be used for logcat logging
+ * of errors, and thus should uniquely identify the class.
+ */
+ public GeocodeProviderBase(@NonNull Context context, @NonNull String tag) {
+ mTag = tag;
+ mAttributionTag = context.getAttributionTag();
+ mBinder = new Service();
+ }
+
+ /**
+ * Returns the IBinder instance that should be returned from the {@link
+ * android.app.Service#onBind(Intent)} method of the wrapping service.
+ */
+ @NonNull
+ public final IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * Requests forward geocoding of the given arguments. The given callback must be invoked once.
+ */
+ public abstract void onForwardGeocode(
+ @NonNull ForwardGeocodeRequest request,
+ @NonNull OutcomeReceiver<List<Address>, Exception> callback);
+
+ /**
+ * Requests reverse geocoding of the given arguments. The given callback must be invoked once.
+ */
+ public abstract void onReverseGeocode(
+ @NonNull ReverseGeocodeRequest request,
+ @NonNull OutcomeReceiver<List<Address>, Exception> callback);
+
+ private class Service extends IGeocodeProvider.Stub {
+ @Override
+ public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+ try {
+ onForwardGeocode(request, new SingleUseCallback(callback));
+ } catch (RuntimeException e) {
+ // exceptions on one-way binder threads are dropped - move to a different thread
+ Log.w(mTag, e);
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
+ throw new AssertionError(e);
+ });
+ }
+ }
+
+ @Override
+ public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+ try {
+ onReverseGeocode(request, new SingleUseCallback(callback));
+ } catch (RuntimeException e) {
+ // exceptions on one-way binder threads are dropped - move to a different thread
+ Log.w(mTag, e);
+ new Handler(Looper.getMainLooper())
+ .post(
+ () -> {
+ throw new AssertionError(e);
+ });
+ }
+ }
+ }
+
+ private static class SingleUseCallback implements OutcomeReceiver<List<Address>, Exception> {
+
+ private final AtomicReference<IGeocodeCallback> mCallback;
+
+ SingleUseCallback(IGeocodeCallback callback) {
+ mCallback = new AtomicReference<>(callback);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ try {
+ Objects.requireNonNull(mCallback.getAndSet(null)).onError(e.toString());
+ } catch (RemoteException r) {
+ throw r.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void onResult(List<Address> results) {
+ try {
+ Objects.requireNonNull(mCallback.getAndSet(null)).onResults(results);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+}
diff --git a/location/java/android/location/IGeocodeListener.aidl b/location/java/android/location/provider/IGeocodeCallback.aidl
similarity index 76%
rename from location/java/android/location/IGeocodeListener.aidl
rename to location/java/android/location/provider/IGeocodeCallback.aidl
index 8e10411..cf52713 100644
--- a/location/java/android/location/IGeocodeListener.aidl
+++ b/location/java/android/location/provider/IGeocodeCallback.aidl
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-package android.location;
+package android.location.provider;
import android.location.Address;
/**
- * An interface for returning geocode results.
- *
- * {@hide}
+ * Binder interface for geocoding callbacks.
+ * @hide
*/
-interface IGeocodeListener {
-
- oneway void onResults(String error, in List<Address> results);
+oneway interface IGeocodeCallback {
+ void onError(String error);
+ void onResults(in List<Address> results);
}
diff --git a/location/java/android/location/provider/IGeocodeProvider.aidl b/location/java/android/location/provider/IGeocodeProvider.aidl
new file mode 100644
index 0000000..9217438
--- /dev/null
+++ b/location/java/android/location/provider/IGeocodeProvider.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.ReverseGeocodeRequest;
+
+/**
+ * Binder interface for services that implement geocode providers. Do not implement this directly,
+ * extend {@link GeocodeProviderBase} instead.
+ * @hide
+ */
+oneway interface IGeocodeProvider {
+ void forwardGeocode(in ForwardGeocodeRequest request, in IGeocodeCallback callback);
+ void reverseGeocode(in ReverseGeocodeRequest request, in IGeocodeCallback callback);
+}
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/provider/ReverseGeocodeRequest.aidl
similarity index 75%
rename from location/java/android/location/GeocoderParams.aidl
rename to location/java/android/location/provider/ReverseGeocodeRequest.aidl
index 2484e20..015757a 100644
--- a/location/java/android/location/GeocoderParams.aidl
+++ b/location/java/android/location/provider/ReverseGeocodeRequest.aidl
@@ -1,11 +1,10 @@
/*
- * Copyright (C) 2010, The Android Open Source Project
- *
+ * Copyright (C) 2024
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +13,6 @@
* limitations under the License.
*/
-package android.location;
+package android.location.provider;
-parcelable GeocoderParams;
+parcelable ReverseGeocodeRequest;
diff --git a/location/java/android/location/provider/ReverseGeocodeRequest.java b/location/java/android/location/provider/ReverseGeocodeRequest.java
new file mode 100644
index 0000000..57c9047
--- /dev/null
+++ b/location/java/android/location/provider/ReverseGeocodeRequest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location.provider;
+
+import static java.lang.Math.max;
+
+import android.annotation.FlaggedApi;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.location.flags.Flags;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Reverse geocode (ie from lat/lng to address) provider request.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NEW_GEOCODER)
+@SystemApi
+public final class ReverseGeocodeRequest implements Parcelable {
+
+ private final double mLatitude;
+ private final double mLongitude;
+ private final int mMaxResults;
+ private final Locale mLocale;
+
+ private final int mCallingUid;
+ private final String mCallingPackage;
+ @Nullable private final String mCallingAttributionTag;
+
+ private ReverseGeocodeRequest(
+ double latitude,
+ double longitude,
+ int maxResults,
+ Locale locale,
+ int callingUid,
+ String callingPackage,
+ @Nullable String callingAttributionTag) {
+ Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
+ Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
+
+ mLatitude = latitude;
+ mLongitude = longitude;
+ mMaxResults = max(maxResults, 1);
+ mLocale = Objects.requireNonNull(locale);
+
+ mCallingUid = callingUid;
+ mCallingPackage = Objects.requireNonNull(callingPackage);
+ mCallingAttributionTag = callingAttributionTag;
+ }
+
+ /** The latitude of the point to be reverse geocoded. */
+ @FloatRange(from = -90.0, to = 90.0)
+ public double getLatitude() {
+ return mLatitude;
+ }
+
+ /** The longitude of the point to be reverse geocoded. */
+ @FloatRange(from = -180.0, to = 180.0)
+ public double getLongitude() {
+ return mLongitude;
+ }
+
+ /** The maximum number of reverse geocoding results that should be returned. */
+ @IntRange(from = 1)
+ public int getMaxResults() {
+ return mMaxResults;
+ }
+
+ /** The locale that results should be localized to (best effort). */
+ @NonNull
+ public Locale getLocale() {
+ return mLocale;
+ }
+
+ /** The UID of the caller this geocoding request is happening on behalf of. */
+ public int getCallingUid() {
+ return mCallingUid;
+ }
+
+ /** The package of the caller this geocoding request is happening on behalf of. */
+ @NonNull
+ public String getCallingPackage() {
+ return mCallingPackage;
+ }
+
+ /** The attribution tag of the caller this geocoding request is happening on behalf of. */
+ @Nullable
+ public String getCallingAttributionTag() {
+ return mCallingAttributionTag;
+ }
+
+ public static final @NonNull Creator<ReverseGeocodeRequest> CREATOR =
+ new Creator<>() {
+ @Override
+ public ReverseGeocodeRequest createFromParcel(Parcel in) {
+ return new ReverseGeocodeRequest(
+ in.readDouble(),
+ in.readDouble(),
+ in.readInt(),
+ new Locale(in.readString8(), in.readString8(), in.readString8()),
+ in.readInt(),
+ Objects.requireNonNull(in.readString8()),
+ in.readString8());
+ }
+
+ @Override
+ public ReverseGeocodeRequest[] newArray(int size) {
+ return new ReverseGeocodeRequest[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeDouble(mLatitude);
+ parcel.writeDouble(mLongitude);
+ parcel.writeInt(mMaxResults);
+ parcel.writeString8(mLocale.getLanguage());
+ parcel.writeString8(mLocale.getCountry());
+ parcel.writeString8(mLocale.getVariant());
+ parcel.writeInt(mCallingUid);
+ parcel.writeString8(mCallingPackage);
+ parcel.writeString8(mCallingAttributionTag);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof ReverseGeocodeRequest that) {
+ return mLatitude == that.mLatitude
+ && mLongitude == that.mLongitude
+ && mMaxResults == that.mMaxResults
+ && mCallingUid == that.mCallingUid
+ && mLocale.equals(that.mLocale)
+ && mCallingPackage.equals(that.mCallingPackage)
+ && Objects.equals(mCallingAttributionTag, that.mCallingAttributionTag);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mLatitude,
+ mLongitude,
+ mMaxResults,
+ mLocale,
+ mCallingUid,
+ mCallingPackage,
+ mCallingAttributionTag);
+ }
+
+ /** A Builder for {@link ReverseGeocodeRequest}s. */
+ public static final class Builder {
+
+ private final double mLatitude;
+ private final double mLongitude;
+ private final int mMaxResults;
+ private final Locale mLocale;
+
+ private final int mCallingUid;
+ private final String mCallingPackage;
+ @Nullable private String mCallingAttributionTag;
+
+ /** Creates a new Builder instance with the given parameters. */
+ public Builder(
+ @FloatRange(from = -90.0, to = 90.0) double latitude,
+ @FloatRange(from = -180.0, to = 180.0) double longitude,
+ @IntRange(from = 0) int maxResults,
+ @NonNull Locale locale,
+ int callingUid,
+ @NonNull String callingPackage) {
+ mLatitude = latitude;
+ mLongitude = longitude;
+ mMaxResults = maxResults;
+ mLocale = locale;
+ mCallingUid = callingUid;
+ mCallingPackage = callingPackage;
+ mCallingAttributionTag = null;
+ }
+
+ /** Sets the attribution tag. */
+ @NonNull
+ public Builder setCallingAttributionTag(@NonNull String attributionTag) {
+ mCallingAttributionTag = attributionTag;
+ return this;
+ }
+
+ /** Builds a {@link ReverseGeocodeRequest}. */
+ @NonNull
+ public ReverseGeocodeRequest build() {
+ return new ReverseGeocodeRequest(
+ mLatitude,
+ mLongitude,
+ mMaxResults,
+ mLocale,
+ mCallingUid,
+ mCallingPackage,
+ mCallingAttributionTag);
+ }
+ }
+}
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index c9be579..b10019a 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -30,6 +30,7 @@
"androidx.annotation_annotation",
],
api_packages: [
+ "android.location",
"com.android.location.provider",
"com.android.location.timezone.provider",
],
diff --git a/location/lib/README.txt b/location/lib/README.txt
index 400a7dd..ae51872 100644
--- a/location/lib/README.txt
+++ b/location/lib/README.txt
@@ -1,30 +1,12 @@
This library (com.android.location.provider.jar) is a shared java library
-containing classes required by unbundled location providers.
+containing classes required by unbundled providers. The library was created
+as a way of exposing API classes outside of the public API before SystemApi
+was possible. Now that SystemApi exists, no new classes should ever be added
+to this library, and all classes in this library should eventually be
+deprecated and new SystemApi replacements offered.
---- Rules of this library ---
-o This library is effectively a PUBLIC API for unbundled location providers
- that may be distributed outside the system image. So it MUST BE API STABLE.
- You can add but not remove. The rules are the same as for the
- public platform SDK API.
-o This library can see and instantiate internal platform classes (such as
- ProviderRequest.java), but it must not expose them in any public method
- (or by extending them via inheritance). This would break clients of the
- library because they cannot see the internal platform classes.
-
-This library is distributed in the system image, and loaded as
-a shared library. So you can change the implementation, but not
-the interface. In this way it is like framework.jar.
-
---- Why does this library exists? ---
-
-Unbundled location providers (such as the NetworkLocationProvider)
-can not use internal platform classes.
-
-So ideally all of these classes would be part of the public platform SDK API,
-but that doesn't seem like a great idea when only applications with a special
-signature can implement this API.
-
-The compromise is this library.
-
-It wraps internal platform classes (like ProviderRequest) with a stable
-API that does not leak the internal classes.
+Whether or not classes in this library can ever be removed must be answered on
+a case by case basis. Most of the classes are usually referenced by Google Play
+services (in which case references can be removed from that code base), but
+these classes may also be referenced by OEM code, which must be considered
+before any removal.
diff --git a/location/lib/api/system-current.txt b/location/lib/api/system-current.txt
index 7046abd..75e6bb4 100644
--- a/location/lib/api/system-current.txt
+++ b/location/lib/api/system-current.txt
@@ -1,4 +1,21 @@
// Signature format: 2.0
+package android.location {
+
+ @Deprecated public class GeocoderParams implements android.os.Parcelable {
+ ctor @Deprecated public GeocoderParams(android.content.Context);
+ ctor @Deprecated public GeocoderParams(android.content.Context, java.util.Locale);
+ ctor @Deprecated public GeocoderParams(int, String, @Nullable String, java.util.Locale);
+ method @Deprecated public int describeContents();
+ method @Deprecated @Nullable public String getClientAttributionTag();
+ method @Deprecated @NonNull public String getClientPackage();
+ method @Deprecated public int getClientUid();
+ method @Deprecated @NonNull public java.util.Locale getLocale();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GeocoderParams> CREATOR;
+ }
+
+}
+
package com.android.location.provider {
@Deprecated public final class FusedLocationHardware {
@@ -25,6 +42,13 @@
method @Deprecated public void onStatusChanged(int);
}
+ @Deprecated public abstract class GeocodeProvider {
+ ctor @Deprecated public GeocodeProvider();
+ method @Deprecated public android.os.IBinder getBinder();
+ method @Deprecated public abstract String onGetFromLocation(double, double, int, android.location.GeocoderParams, java.util.List<android.location.Address>);
+ method @Deprecated public abstract String onGetFromLocationName(String, double, double, double, double, int, android.location.GeocoderParams, java.util.List<android.location.Address>);
+ }
+
@Deprecated public class GmsFusedBatchOptions {
ctor @Deprecated public GmsFusedBatchOptions();
method @Deprecated public int getFlags();
diff --git a/core/java/android/location/GeocoderParams.java b/location/lib/java/android/location/GeocoderParams.java
similarity index 65%
rename from core/java/android/location/GeocoderParams.java
rename to location/lib/java/android/location/GeocoderParams.java
index 3ea6364..780ccf4 100644
--- a/core/java/android/location/GeocoderParams.java
+++ b/location/lib/java/android/location/GeocoderParams.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
+import android.annotation.SystemApi;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,15 +28,15 @@
import java.util.Objects;
/**
- * This class contains extra parameters to pass to an IGeocodeProvider
- * implementation from the Geocoder class. Currently this contains the
- * language, country and variant information from the Geocoder's locale
- * as well as the Geocoder client's package name for geocoder server
- * logging. This information is kept in a separate class to allow for
- * future expansion of the IGeocodeProvider interface.
+ * This class was originally shipped out-of-band from the normal API processes as a separate drop
+ * before SystemApi existed. Now that SystemApi does exist, this class has been retroactively
+ * published through SystemApi.
*
+ * @deprecated Do not use.
* @hide
*/
+@Deprecated
+@SystemApi
public class GeocoderParams implements Parcelable {
private final int mUid;
@@ -52,7 +52,8 @@
this(Process.myUid(), context.getPackageName(), context.getAttributionTag(), locale);
}
- private GeocoderParams(int uid, String packageName, String attributionTag, Locale locale) {
+ public GeocoderParams(
+ int uid, String packageName, @Nullable String attributionTag, Locale locale) {
mUid = uid;
mPackageName = Objects.requireNonNull(packageName);
mAttributionTag = attributionTag;
@@ -62,7 +63,6 @@
/**
* Returns the client UID.
*/
- @UnsupportedAppUsage
public int getClientUid() {
return mUid;
}
@@ -70,7 +70,6 @@
/**
* Returns the client package name.
*/
- @UnsupportedAppUsage
public @NonNull String getClientPackage() {
return mPackageName;
}
@@ -78,7 +77,6 @@
/**
* Returns the client attribution tag.
*/
- @UnsupportedAppUsage
public @Nullable String getClientAttributionTag() {
return mAttributionTag;
}
@@ -86,34 +84,38 @@
/**
* Returns the locale.
*/
- @UnsupportedAppUsage
public @NonNull Locale getLocale() {
return mLocale;
}
public static final @NonNull Parcelable.Creator<GeocoderParams> CREATOR =
- new Parcelable.Creator<GeocoderParams>() {
- public GeocoderParams createFromParcel(Parcel in) {
- int uid = in.readInt();
- String packageName = in.readString8();
- String attributionTag = in.readString8();
- String language = in.readString8();
- String country = in.readString8();
- String variant = in.readString8();
+ new Parcelable.Creator<>() {
+ public GeocoderParams createFromParcel(Parcel in) {
+ int uid = in.readInt();
+ 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));
- }
+ return new GeocoderParams(
+ uid,
+ packageName,
+ attributionTag,
+ new Locale(language, country, variant));
+ }
- public GeocoderParams[] newArray(int size) {
- return new GeocoderParams[size];
- }
- };
+ public GeocoderParams[] newArray(int size) {
+ return new GeocoderParams[size];
+ }
+ };
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mUid);
parcel.writeString8(mPackageName);
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
index 05d7935..45077ba 100644
--- a/location/lib/java/com/android/location/provider/GeocodeProvider.java
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -16,10 +16,13 @@
package com.android.location.provider;
+import android.annotation.SystemApi;
import android.location.Address;
import android.location.GeocoderParams;
-import android.location.IGeocodeListener;
-import android.location.IGeocodeProvider;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.IGeocodeProvider;
+import android.location.provider.ReverseGeocodeRequest;
import android.os.IBinder;
import android.os.RemoteException;
@@ -27,47 +30,74 @@
import java.util.List;
/**
- * Base class for geocode providers implemented as unbundled services.
+ * This class was originally shipped out-of-band from the normal API processes as a separate drop
+ * before SystemApi existed. Now that SystemApi does exist, this class has been retroactively
+ * published through SystemApi.
*
- * <p>Geocode providers can be implemented as services and return the result of
- * {@link GeocodeProvider#getBinder()} in its getBinder() method.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled
- * applications, and must remain API stable. See README.txt in the root
- * of this package for more information.
+ * @deprecated Use {@link android.location.provider.GeocodeProviderBase} instead.
* @hide
*/
+@Deprecated
+@SystemApi
public abstract class GeocodeProvider {
- private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
- @Override
- public void getFromLocation(double latitude, double longitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- List<Address> results = new ArrayList<>();
- String error = onGetFromLocation(latitude, longitude, maxResults, params, results);
- try {
- listener.onResults(error, results);
- } catch (RemoteException e) {
- // ignore
- }
- }
+ private final IGeocodeProvider.Stub mProvider =
+ new IGeocodeProvider.Stub() {
+ @Override
+ public void reverseGeocode(
+ ReverseGeocodeRequest request, IGeocodeCallback callback) {
+ List<Address> results = new ArrayList<>();
+ String error =
+ onGetFromLocation(
+ request.getLatitude(),
+ request.getLongitude(),
+ request.getMaxResults(),
+ new GeocoderParams(
+ request.getCallingUid(),
+ request.getCallingPackage(),
+ request.getCallingAttributionTag(),
+ request.getLocale()),
+ results);
+ try {
+ if (error != null) {
+ callback.onError(error);
+ } else {
+ callback.onResults(results);
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
- @Override
- public void getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- List<Address> results = new ArrayList<>();
- String error = onGetFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, results);
- try {
- listener.onResults(error, results);
- } catch (RemoteException e) {
- // ignore
- }
- }
- };
+ @Override
+ public void forwardGeocode(
+ ForwardGeocodeRequest request, IGeocodeCallback callback) {
+ List<Address> results = new ArrayList<>();
+ String error =
+ onGetFromLocationName(
+ request.getLocationName(),
+ request.getLowerLeftLatitude(),
+ request.getLowerLeftLongitude(),
+ request.getUpperRightLatitude(),
+ request.getUpperRightLongitude(),
+ request.getMaxResults(),
+ new GeocoderParams(
+ request.getCallingUid(),
+ request.getCallingPackage(),
+ request.getCallingAttributionTag(),
+ request.getLocale()),
+ results);
+ try {
+ if (error != null) {
+ callback.onError(error);
+ } else {
+ callback.onResults(results);
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ };
/**
* This method is overridden to implement the
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
deleted file mode 100644
index ac42646..0000000
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.location.GeocoderParams;
-import android.location.IGeocodeListener;
-import android.location.IGeocodeProvider;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import com.android.server.servicewatcher.CurrentUserServiceSupplier;
-import com.android.server.servicewatcher.ServiceWatcher;
-
-import java.util.Collections;
-
-/**
- * Proxy for IGeocodeProvider implementations.
- *
- * @hide
- */
-public class GeocoderProxy {
-
- private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
-
- /**
- * Creates and registers this proxy. If no suitable service is available for the proxy, returns
- * null.
- */
- @Nullable
- public static GeocoderProxy createAndRegister(Context context) {
- GeocoderProxy proxy = new GeocoderProxy(context);
- if (proxy.register()) {
- return proxy;
- } else {
- return null;
- }
- }
-
- private final ServiceWatcher mServiceWatcher;
-
- private GeocoderProxy(Context context) {
- mServiceWatcher = ServiceWatcher.create(context, "GeocoderProxy",
- CurrentUserServiceSupplier.createFromConfig(context, SERVICE_ACTION,
- com.android.internal.R.bool.config_enableGeocoderOverlay,
- com.android.internal.R.string.config_geocoderProviderPackageName),
- null);
- }
-
- private boolean register() {
- boolean resolves = mServiceWatcher.checkServiceResolves();
- if (resolves) {
- mServiceWatcher.register();
- }
- return resolves;
- }
-
- /**
- * Geocodes stuff.
- */
- public void getFromLocation(double latitude, double longitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderOperation() {
- @Override
- public void run(IBinder binder) throws RemoteException {
- IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- provider.getFromLocation(latitude, longitude, maxResults, params, listener);
- }
-
- @Override
- public void onError(Throwable t) {
- try {
- listener.onResults(t.toString(), Collections.emptyList());
- } catch (RemoteException e) {
- // ignore
- }
- }
- });
- }
-
- /**
- * Geocodes stuff.
- */
- public void getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- mServiceWatcher.runOnBinder(new ServiceWatcher.BinderOperation() {
- @Override
- public void run(IBinder binder) throws RemoteException {
- IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- provider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, listener);
- }
-
- @Override
- public void onError(Throwable t) {
- try {
- listener.onResults(t.toString(), Collections.emptyList());
- } catch (RemoteException e) {
- // ignore
- }
- }
- });
- }
-}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 323cdc5..c5f3855 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -52,13 +52,11 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
-import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssAntennaInfo;
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
-import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
@@ -75,8 +73,11 @@
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.IGeocodeCallback;
import android.location.provider.IProviderRequestListener;
import android.location.provider.ProviderProperties;
+import android.location.provider.ReverseGeocodeRequest;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Build;
@@ -141,6 +142,7 @@
import com.android.server.location.provider.PassiveLocationProvider;
import com.android.server.location.provider.PassiveLocationProviderManager;
import com.android.server.location.provider.StationaryThrottlingLocationProvider;
+import com.android.server.location.provider.proxy.ProxyGeocodeProvider;
import com.android.server.location.provider.proxy.ProxyLocationProvider;
import com.android.server.location.settings.LocationSettings;
import com.android.server.location.settings.LocationUserSettings;
@@ -253,7 +255,7 @@
private final GeofenceManager mGeofenceManager;
private volatile @Nullable GnssManagerService mGnssManagerService = null;
- private GeocoderProxy mGeocodeProvider;
+ private ProxyGeocodeProvider mGeocodeProvider;
private final Object mDeprecatedGnssBatchingLock = new Object();
@GuardedBy("mDeprecatedGnssBatchingLock")
@@ -493,7 +495,7 @@
}
// bind to geocoder provider
- mGeocodeProvider = GeocoderProxy.createAndRegister(mContext);
+ mGeocodeProvider = ProxyGeocodeProvider.createAndRegister(mContext);
if (mGeocodeProvider == null) {
Log.e(TAG, "no geocoder provider found");
}
@@ -1363,23 +1365,22 @@
}
@Override
- public boolean geocoderIsPresent() {
+ public boolean isGeocodeAvailable() {
return mGeocodeProvider != null;
}
@Override
- public void getFromLocation(double latitude, double longitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- // validate identity
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
- params.getClientAttributionTag());
- Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+ public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+ CallerIdentity identity =
+ CallerIdentity.fromBinder(
+ mContext, request.getCallingPackage(), request.getCallingAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == request.getCallingUid());
if (mGeocodeProvider != null) {
- mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, params, listener);
+ mGeocodeProvider.reverseGeocode(request, callback);
} else {
try {
- listener.onResults(null, Collections.emptyList());
+ callback.onError(null);
} catch (RemoteException e) {
// ignore
}
@@ -1387,22 +1388,17 @@
}
@Override
- public void getFromLocationName(String locationName,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults,
- GeocoderParams params, IGeocodeListener listener) {
- // validate identity
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
- params.getClientAttributionTag());
- Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+ public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+ CallerIdentity identity =
+ CallerIdentity.fromBinder(
+ mContext, request.getCallingPackage(), request.getCallingAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == request.getCallingUid());
if (mGeocodeProvider != null) {
- mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, listener);
+ mGeocodeProvider.forwardGeocode(request, callback);
} else {
try {
- listener.onResults(null, Collections.emptyList());
+ callback.onError(null);
} catch (RemoteException e) {
// ignore
}
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java
new file mode 100644
index 0000000..ac945f1
--- /dev/null
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyGeocodeProvider.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.provider.proxy;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.provider.ForwardGeocodeRequest;
+import android.location.provider.GeocodeProviderBase;
+import android.location.provider.IGeocodeCallback;
+import android.location.provider.IGeocodeProvider;
+import android.location.provider.ReverseGeocodeRequest;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.server.servicewatcher.CurrentUserServiceSupplier;
+import com.android.server.servicewatcher.ServiceWatcher;
+
+/** Proxy for IGeocodeProvider implementations. */
+public class ProxyGeocodeProvider {
+
+ /**
+ * Creates and registers this proxy. If no suitable service is available for the proxy, returns
+ * null.
+ */
+ @Nullable
+ public static ProxyGeocodeProvider createAndRegister(Context context) {
+ ProxyGeocodeProvider proxy = new ProxyGeocodeProvider(context);
+ if (proxy.register()) {
+ return proxy;
+ } else {
+ return null;
+ }
+ }
+
+ private final ServiceWatcher mServiceWatcher;
+
+ private ProxyGeocodeProvider(Context context) {
+ mServiceWatcher =
+ ServiceWatcher.create(
+ context,
+ "GeocoderProxy",
+ CurrentUserServiceSupplier.createFromConfig(
+ context,
+ GeocodeProviderBase.ACTION_GEOCODE_PROVIDER,
+ com.android.internal.R.bool.config_enableGeocoderOverlay,
+ com.android.internal.R.string.config_geocoderProviderPackageName),
+ null);
+ }
+
+ private boolean register() {
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
+ }
+ return resolves;
+ }
+
+ /** Reverse geocodes. */
+ public void reverseGeocode(ReverseGeocodeRequest request, IGeocodeCallback callback) {
+ mServiceWatcher.runOnBinder(
+ new ServiceWatcher.BinderOperation() {
+ @Override
+ public void run(IBinder binder) throws RemoteException {
+ IGeocodeProvider.Stub.asInterface(binder).reverseGeocode(request, callback);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ try {
+ callback.onError(t.toString());
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ });
+ }
+
+ /** Forward geocodes. */
+ public void forwardGeocode(ForwardGeocodeRequest request, IGeocodeCallback callback) {
+ mServiceWatcher.runOnBinder(
+ new ServiceWatcher.BinderOperation() {
+ @Override
+ public void run(IBinder binder) throws RemoteException {
+ IGeocodeProvider.Stub.asInterface(binder).forwardGeocode(request, callback);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ try {
+ callback.onError(t.toString());
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ });
+ }
+}