Refactor Geocoder Provider System APIs

1) Deprecate old GeocoderProvider API which is not part of any published
   API surface.
2) Create new GeocoderProviderBase API which lives in normal SystemApi
   surface.
3) Cleanup various callback APIs and geocoding POJOs used internally.

Bug: 279319276
Bug: 229872126
Test: CTS
Change-Id: I1da453ba5f9fd98b08ecdbbbacf640497ed6cd42
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/location/lib/java/android/location/GeocoderParams.java b/location/lib/java/android/location/GeocoderParams.java
new file mode 100644
index 0000000..780ccf4
--- /dev/null
+++ b/location/lib/java/android/location/GeocoderParams.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.Process;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * 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;
+    private final String mPackageName;
+    private final @Nullable String mAttributionTag;
+    private final Locale mLocale;
+
+    public GeocoderParams(Context context) {
+        this(context, Locale.getDefault());
+    }
+
+    public GeocoderParams(Context context, Locale locale) {
+        this(Process.myUid(), context.getPackageName(), context.getAttributionTag(), locale);
+    }
+
+    public GeocoderParams(
+            int uid, String packageName, @Nullable String attributionTag, Locale locale) {
+        mUid = uid;
+        mPackageName = Objects.requireNonNull(packageName);
+        mAttributionTag = attributionTag;
+        mLocale = Objects.requireNonNull(locale);
+    }
+
+    /**
+     * Returns the client UID.
+     */
+    public int getClientUid() {
+        return mUid;
+    }
+
+    /**
+     * Returns the client package name.
+     */
+    public @NonNull String getClientPackage() {
+        return mPackageName;
+    }
+
+    /**
+     * Returns the client attribution tag.
+     */
+    public @Nullable String getClientAttributionTag() {
+        return mAttributionTag;
+    }
+
+    /**
+     * Returns the locale.
+     */
+    public @NonNull Locale getLocale() {
+        return mLocale;
+    }
+
+    public static final @NonNull Parcelable.Creator<GeocoderParams> CREATOR =
+            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));
+                }
+
+                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);
+        parcel.writeString8(mAttributionTag);
+        parcel.writeString8(mLocale.getLanguage());
+        parcel.writeString8(mLocale.getCountry());
+        parcel.writeString8(mLocale.getVariant());
+    }
+}
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