From e655f11ca5b16d05734cb0bd1b94504c181a483e Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Wed, 9 Nov 2022 13:12:11 +0000 Subject: [PATCH 1/2] Revert CountryDetector changes -Revert detectCountry() to UnsupportedAppUsage -Revert addCountryListener & removeCountryListener to UnsupportedAppUsage -Revert countryListener to UnsupportedAppUsage -Revert getCountryIso() to UnsupportedAppUsage to support api with new naming convention Bug: 252989268 Test: manual test && make update-api Change-Id: I5c5978f4460eb6bce8d3ed97458b5cc6ac6d788d --- core/api/system-current.txt | 11 --- core/api/system-lint-baseline.txt | 6 -- location/java/android/location/Country.java | 99 +++++++++---------- .../android/location/CountryDetector.java | 82 +++++++-------- .../android/location/CountryListener.java | 8 +- 5 files changed, 85 insertions(+), 121 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 014c4eee39248..3a98dfa1000db 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5609,7 +5609,6 @@ package android.location { public final class Country implements android.os.Parcelable { method public int describeContents(); - method @NonNull public String getCountryIso(); method public int getSource(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3 @@ -5619,16 +5618,6 @@ package android.location { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } - public class CountryDetector { - method public void addCountryListener(@NonNull android.location.CountryListener, @Nullable android.os.Looper); - method @Nullable public android.location.Country detectCountry(); - method public void removeCountryListener(@NonNull android.location.CountryListener); - } - - public interface CountryListener { - method public void onCountryDetected(@NonNull android.location.Country); - } - public final class GnssCapabilities implements android.os.Parcelable { method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); method @Deprecated public boolean hasNavMessages(); diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 47588d97fdbf3..025e8629fc207 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -3,10 +3,6 @@ ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions(): Method should return Collection (or subclass) instead of raw array; was `java.lang.CharSequence[]` -ExecutorRegistration: android.location.CountryDetector#addCountryListener(android.location.CountryListener, android.os.Looper): - Registration methods should have overload that accepts delivery Executor: `addCountryListener` - - GenericException: android.app.prediction.AppPredictor#finalize(): Methods must not throw generic exceptions (`java.lang.Throwable`) GenericException: android.hardware.location.ContextHubClient#finalize(): @@ -131,8 +127,6 @@ SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Print SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.content.pm.ResolveInfo#dump(android.util.Printer, String): SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ResolveInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.location.CountryDetector#addCountryListener(android.location.CountryListener, android.os.Looper): - SAM-compatible parameters (such as parameter 1, "listener", in android.location.CountryDetector.addCountryListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.location.Location#dump(android.util.Printer, String): SAM-compatible parameters (such as parameter 1, "pw", in android.location.Location.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler): diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java index 8e1bb1f0a9b33..62f48917f4dc5 100644 --- a/location/java/android/location/Country.java +++ b/location/java/android/location/Country.java @@ -33,34 +33,22 @@ import java.util.Locale; */ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) public final class Country implements Parcelable { - /** - * The country code came from the mobile network - */ + /** The country code came from the mobile network */ public static final int COUNTRY_SOURCE_NETWORK = 0; - /** - * The country code came from the location service - */ + /** The country code came from the location service */ public static final int COUNTRY_SOURCE_LOCATION = 1; - /** - * The country code was read from the SIM card - */ + /** The country code was read from the SIM card */ public static final int COUNTRY_SOURCE_SIM = 2; - /** - * The country code came from the system locale setting - */ + /** The country code came from the system locale setting */ public static final int COUNTRY_SOURCE_LOCALE = 3; - /** - * The ISO 3166-1 two letters country code. - */ + /** The ISO 3166-1 two letters country code. */ private final String mCountryIso; - /** - * Where the country code came from. - */ + /** Where the country code came from. */ private final int mSource; private int mHashCode; @@ -73,21 +61,21 @@ public final class Country implements Parcelable { /** * @param countryIso the ISO 3166-1 two letters country code. - * @param source where the countryIso came from, could be one of below - * values - *

- *

    - *
  • {@link #COUNTRY_SOURCE_NETWORK}
  • - *
  • {@link #COUNTRY_SOURCE_LOCATION}
  • - *
  • {@link #COUNTRY_SOURCE_SIM}
  • - *
  • {@link #COUNTRY_SOURCE_LOCALE}
  • - *
+ * @param source where the countryIso came from, could be one of below values + *

+ *

    + *
  • {@link #COUNTRY_SOURCE_NETWORK} + *
  • {@link #COUNTRY_SOURCE_LOCATION} + *
  • {@link #COUNTRY_SOURCE_SIM} + *
  • {@link #COUNTRY_SOURCE_LOCALE} + *
* * @hide */ @UnsupportedAppUsage - public Country(final String countryIso, final int source) { - if (countryIso == null || source < COUNTRY_SOURCE_NETWORK + public Country(@NonNull final String countryIso, final int source) { + if (countryIso == null + || source < COUNTRY_SOURCE_NETWORK || source > COUNTRY_SOURCE_LOCALE) { throw new IllegalArgumentException(); } @@ -97,7 +85,8 @@ public final class Country implements Parcelable { } private Country(final String countryIso, final int source, long timestamp) { - if (countryIso == null || source < COUNTRY_SOURCE_NETWORK + if (countryIso == null + || source < COUNTRY_SOURCE_NETWORK || source > COUNTRY_SOURCE_LOCALE) { throw new IllegalArgumentException(); } @@ -115,21 +104,22 @@ public final class Country implements Parcelable { /** * @return the ISO 3166-1 two letters country code + * @hide */ - @NonNull + @UnsupportedAppUsage public String getCountryIso() { return mCountryIso; } /** * @return where the country code came from, could be one of below values - *

- *

    - *
  • {@link #COUNTRY_SOURCE_NETWORK}
  • - *
  • {@link #COUNTRY_SOURCE_LOCATION}
  • - *
  • {@link #COUNTRY_SOURCE_SIM}
  • - *
  • {@link #COUNTRY_SOURCE_LOCALE}
  • - *
+ *

+ *

    + *
  • {@link #COUNTRY_SOURCE_NETWORK} + *
  • {@link #COUNTRY_SOURCE_LOCATION} + *
  • {@link #COUNTRY_SOURCE_SIM} + *
  • {@link #COUNTRY_SOURCE_LOCALE} + *
*/ public int getSource() { return mSource; @@ -146,15 +136,16 @@ public final class Country implements Parcelable { } @android.annotation.NonNull - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public Country createFromParcel(Parcel in) { - return new Country(in.readString(), in.readInt(), in.readLong()); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Country createFromParcel(Parcel in) { + return new Country(in.readString(), in.readInt(), in.readLong()); + } - public Country[] newArray(int size) { - return new Country[size]; - } - }; + public Country[] newArray(int size) { + return new Country[size]; + } + }; @Override public int describeContents() { @@ -169,10 +160,9 @@ public final class Country implements Parcelable { } /** - * Returns true if this {@link Country} is equivalent to the given object. This ignores - * the timestamp value and just checks for equivalence of countryIso and source values. - * Returns false otherwise. - * + * Returns true if this {@link Country} is equivalent to the given object. This ignores the + * timestamp value and just checks for equivalence of countryIso and source values. Returns + * false otherwise. */ @Override public boolean equals(@Nullable Object object) { @@ -200,13 +190,12 @@ public final class Country implements Parcelable { } /** - * Compare the specified country to this country object ignoring the source - * and timestamp fields, return true if the countryIso fields are equal + * Compare the specified country to this country object ignoring the source and timestamp + * fields, return true if the countryIso fields are equal * * @param country the country to compare - * @return true if the specified country's countryIso field is equal to this - * country's, false otherwise. - * + * @return true if the specified country's countryIso field is equal to this country's, false + * otherwise. * @hide */ public boolean equalsIgnoreSource(Country country) { diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index 3a0edfc571938..2592a280af8fe 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -16,9 +16,6 @@ package android.location; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -31,35 +28,35 @@ import android.util.Log; import java.util.HashMap; /** - * This class provides access to the system country detector service. This - * service allows applications to obtain the country that the user is in. - *

- * The country will be detected in order of reliability, like + * This class provides access to the system country detector service. This service allows + * applications to obtain the country that the user is in. + * + *

The country will be detected in order of reliability, like + * *

    - *
  • Mobile network
  • - *
  • Location
  • - *
  • SIM's country
  • - *
  • Phone's locale
  • + *
  • Mobile network + *
  • Location + *
  • SIM's country + *
  • Phone's locale *
- *

- * Call the {@link #detectCountry()} to get the available country immediately. - *

- * To be notified of the future country change, use the - * {@link #addCountryListener} + * + *

Call the {@link #detectCountry()} to get the available country immediately. + * + *

To be notified of the future country change, use the {@link #addCountryListener} + * *

* * @hide */ -@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) @SystemService(Context.COUNTRY_DETECTOR) public class CountryDetector { /** - * The class to wrap the ICountryListener.Stub and CountryListener objects - * together. The CountryListener will be notified through the specific - * looper once the country changed and detected. + * The class to wrap the ICountryListener.Stub and CountryListener objects together. The + * CountryListener will be notified through the specific looper once the country changed and + * detected. */ - private final static class ListenerTransport extends ICountryListener.Stub { + private static final class ListenerTransport extends ICountryListener.Stub { private final CountryListener mListener; @@ -75,23 +72,23 @@ public class CountryDetector { } public void onCountryDetected(final Country country) { - mHandler.post(new Runnable() { - public void run() { - mListener.onCountryDetected(country); - } - }); + mHandler.post( + new Runnable() { + public void run() { + mListener.onCountryDetected(country); + } + }); } } - private final static String TAG = "CountryDetector"; + private static final String TAG = "CountryDetector"; private final ICountryDetector mService; private final HashMap mListeners; /** - * @hide - hide this constructor because it has a parameter of type - * ICountryDetector, which is a system private class. The right way to - * create an instance of this class is using the factory - * Context.getSystemService. + * @hide - hide this constructor because it has a parameter of type ICountryDetector, which is a + * system private class. The right way to create an instance of this class is using the + * factory Context.getSystemService. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public CountryDetector(ICountryDetector service) { @@ -102,10 +99,9 @@ public class CountryDetector { /** * Start detecting the country that the user is in. * - * @return the country if it is available immediately, otherwise null will - * be returned. + * @return the country if it is available immediately, otherwise null will be returned. */ - @Nullable + @UnsupportedAppUsage public Country detectCountry() { try { return mService.detectCountry(); @@ -116,15 +112,14 @@ public class CountryDetector { } /** - * Add a listener to receive the notification when the country is detected - * or changed. + * Add a listener to receive the notification when the country is detected or changed. * * @param listener will be called when the country is detected or changed. - * @param looper a Looper object whose message queue will be used to - * implement the callback mechanism. If looper is null then the - * callbacks will be called on the main thread. + * @param looper a Looper object whose message queue will be used to implement the callback + * mechanism. If looper is null then the callbacks will be called on the main thread. */ - public void addCountryListener(@NonNull CountryListener listener, @Nullable Looper looper) { + @UnsupportedAppUsage + public void addCountryListener(CountryListener listener, Looper looper) { synchronized (mListeners) { if (!mListeners.containsKey(listener)) { ListenerTransport transport = new ListenerTransport(listener, looper); @@ -138,10 +133,9 @@ public class CountryDetector { } } - /** - * Remove the listener - */ - public void removeCountryListener(@NonNull CountryListener listener) { + /** Remove the listener */ + @UnsupportedAppUsage + public void removeCountryListener(CountryListener listener) { synchronized (mListeners) { ListenerTransport transport = mListeners.get(listener); if (transport != null) { diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java index 5c06d8239c236..eb67205f4de98 100644 --- a/location/java/android/location/CountryListener.java +++ b/location/java/android/location/CountryListener.java @@ -16,8 +16,7 @@ package android.location; -import android.annotation.NonNull; -import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; /** * The listener for receiving the notification when the country is detected or @@ -25,11 +24,10 @@ import android.annotation.SystemApi; * * @hide */ -@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) public interface CountryListener { /** * @param country the changed or detected country. - * */ - void onCountryDetected(@NonNull Country country); + @UnsupportedAppUsage + void onCountryDetected(Country country); } From 576862f57914537a755b11b0235609d6f9698c73 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Tue, 15 Nov 2022 03:49:59 +0000 Subject: [PATCH 2/2] API Enhancement CountryDetector -Replace CountryListener with a Consumer -Add registerCountryDetectorCallback to take an Executor Vs addCountryListener taking Looper -Add unregisterCountryDetectorCallback to remove Consumer callback interface -Adding getSource to return an IntDef -Expose Country constructor -Adding alternative API with new naming for getCountryIso -Refactoring addCountryListener() & removeCountryListener API's Bug: 252989268, 258197470 CTS-Coverage-Bug: 255511190 Test: manual test && make update-api Change-Id: I5a2f253a87d1037837bc161a80cb873a6471c229 --- core/api/system-current.txt | 7 ++ location/java/android/location/Country.java | 111 ++++++++++++------ .../android/location/CountryDetector.java | 101 ++++++++++------ .../android/location/CountryListener.java | 11 +- .../server/CountryDetectorService.java | 4 + 5 files changed, 162 insertions(+), 72 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 3a98dfa1000db..132ea32f0f7b1 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5608,7 +5608,9 @@ package android.location { } public final class Country implements android.os.Parcelable { + ctor public Country(@NonNull String, int); method public int describeContents(); + method @NonNull public String getCountryCode(); method public int getSource(); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3 @@ -5618,6 +5620,11 @@ package android.location { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public class CountryDetector { + method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer); + } + public final class GnssCapabilities implements android.os.Parcelable { method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); method @Deprecated public boolean hasNavMessages(); diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java index 62f48917f4dc5..53cc943a7237e 100644 --- a/location/java/android/location/Country.java +++ b/location/java/android/location/Country.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -24,6 +25,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Locale; /** @@ -33,22 +36,48 @@ import java.util.Locale; */ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) public final class Country implements Parcelable { - /** The country code came from the mobile network */ + /** + * The country code came from the mobile network + */ public static final int COUNTRY_SOURCE_NETWORK = 0; - /** The country code came from the location service */ + /** + * The country code came from the location service + */ public static final int COUNTRY_SOURCE_LOCATION = 1; - /** The country code was read from the SIM card */ + /** + * The country code was read from the SIM card + */ public static final int COUNTRY_SOURCE_SIM = 2; - /** The country code came from the system locale setting */ + /** + * The country code came from the system locale setting + */ public static final int COUNTRY_SOURCE_LOCALE = 3; + /** + * Country source type + * + * @hide + */ + @IntDef( + prefix = {"COUNTRY_SOURCE_"}, + value = { + COUNTRY_SOURCE_NETWORK, + COUNTRY_SOURCE_LOCATION, + COUNTRY_SOURCE_SIM, + COUNTRY_SOURCE_LOCALE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CountrySource {} + /** The ISO 3166-1 two letters country code. */ private final String mCountryIso; - /** Where the country code came from. */ + /** + * Where the country code came from. + */ private final int mSource; private int mHashCode; @@ -69,11 +98,8 @@ public final class Country implements Parcelable { *

  • {@link #COUNTRY_SOURCE_SIM} *
  • {@link #COUNTRY_SOURCE_LOCALE} * - * - * @hide */ - @UnsupportedAppUsage - public Country(@NonNull final String countryIso, final int source) { + public Country(@NonNull final String countryIso, @CountrySource final int source) { if (countryIso == null || source < COUNTRY_SOURCE_NETWORK || source > COUNTRY_SOURCE_LOCALE) { @@ -85,8 +111,7 @@ public final class Country implements Parcelable { } private Country(final String countryIso, final int source, long timestamp) { - if (countryIso == null - || source < COUNTRY_SOURCE_NETWORK + if (countryIso == null || source < COUNTRY_SOURCE_NETWORK || source > COUNTRY_SOURCE_LOCALE) { throw new IllegalArgumentException(); } @@ -104,23 +129,38 @@ public final class Country implements Parcelable { /** * @return the ISO 3166-1 two letters country code + * * @hide + * + * @deprecated clients using getCountryIso should use the {@link #getCountryCode()} API instead. */ @UnsupportedAppUsage + @Deprecated public String getCountryIso() { return mCountryIso; } /** - * @return where the country code came from, could be one of below values - *

    - *

      - *
    • {@link #COUNTRY_SOURCE_NETWORK} - *
    • {@link #COUNTRY_SOURCE_LOCATION} - *
    • {@link #COUNTRY_SOURCE_SIM} - *
    • {@link #COUNTRY_SOURCE_LOCALE} - *
    + * Retrieves country code. + * + * @return country code in ISO 3166-1:alpha2 */ + @NonNull + public String getCountryCode() { + return mCountryIso; + } + + /** + * @return where the country code came from, could be one of below values + *

    + *

      + *
    • {@link #COUNTRY_SOURCE_NETWORK}
    • + *
    • {@link #COUNTRY_SOURCE_LOCATION}
    • + *
    • {@link #COUNTRY_SOURCE_SIM}
    • + *
    • {@link #COUNTRY_SOURCE_LOCALE}
    • + *
    + */ + @CountrySource public int getSource() { return mSource; } @@ -136,16 +176,15 @@ public final class Country implements Parcelable { } @android.annotation.NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public Country createFromParcel(Parcel in) { - return new Country(in.readString(), in.readInt(), in.readLong()); - } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public Country createFromParcel(Parcel in) { + return new Country(in.readString(), in.readInt(), in.readLong()); + } - public Country[] newArray(int size) { - return new Country[size]; - } - }; + public Country[] newArray(int size) { + return new Country[size]; + } + }; @Override public int describeContents() { @@ -160,9 +199,10 @@ public final class Country implements Parcelable { } /** - * Returns true if this {@link Country} is equivalent to the given object. This ignores the - * timestamp value and just checks for equivalence of countryIso and source values. Returns - * false otherwise. + * Returns true if this {@link Country} is equivalent to the given object. This ignores + * the timestamp value and just checks for equivalence of countryIso and source values. + * Returns false otherwise. + * */ @Override public boolean equals(@Nullable Object object) { @@ -190,12 +230,13 @@ public final class Country implements Parcelable { } /** - * Compare the specified country to this country object ignoring the source and timestamp - * fields, return true if the countryIso fields are equal + * Compare the specified country to this country object ignoring the source + * and timestamp fields, return true if the countryIso fields are equal * * @param country the country to compare - * @return true if the specified country's countryIso field is equal to this country's, false - * otherwise. + * @return true if the specified country's countryIso field is equal to this + * country's, false otherwise. + * * @hide */ public boolean equalsIgnoreSource(Country country) { diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java index 2592a280af8fe..6abb35020a359 100644 --- a/location/java/android/location/CountryDetector.java +++ b/location/java/android/location/CountryDetector.java @@ -16,16 +16,22 @@ package android.location; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import java.util.HashMap; +import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * This class provides access to the system country detector service. This service allows @@ -48,42 +54,38 @@ import java.util.HashMap; * * @hide */ +@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS) @SystemService(Context.COUNTRY_DETECTOR) public class CountryDetector { /** - * The class to wrap the ICountryListener.Stub and CountryListener objects together. The - * CountryListener will be notified through the specific looper once the country changed and - * detected. + * The class to wrap the ICountryListener.Stub , CountryListener & {@code Consumer} + * objects together. + * + *

    The CountryListener will be notified through the Handler Executor once the country changed + * and detected. + * + *

    {@code Consumer} callback interface is notified through the specific executor + * once the country changed and detected. */ private static final class ListenerTransport extends ICountryListener.Stub { - private final CountryListener mListener; + private final Consumer mListener; + private final Executor mExecutor; - private final Handler mHandler; - - public ListenerTransport(CountryListener listener, Looper looper) { - mListener = listener; - if (looper != null) { - mHandler = new Handler(looper); - } else { - mHandler = new Handler(); - } + ListenerTransport(Consumer consumer, Executor executor) { + mListener = consumer; + mExecutor = executor; } public void onCountryDetected(final Country country) { - mHandler.post( - new Runnable() { - public void run() { - mListener.onCountryDetected(country); - } - }); + mExecutor.execute(() -> mListener.accept(country)); } } private static final String TAG = "CountryDetector"; private final ICountryDetector mService; - private final HashMap mListeners; + private final HashMap, ListenerTransport> mListeners; /** * @hide - hide this constructor because it has a parameter of type ICountryDetector, which is a @@ -93,13 +95,14 @@ public class CountryDetector { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public CountryDetector(ICountryDetector service) { mService = service; - mListeners = new HashMap(); + mListeners = new HashMap<>(); } /** * Start detecting the country that the user is in. * * @return the country if it is available immediately, otherwise null will be returned. + * @hide */ @UnsupportedAppUsage public Country detectCountry() { @@ -117,33 +120,59 @@ public class CountryDetector { * @param listener will be called when the country is detected or changed. * @param looper a Looper object whose message queue will be used to implement the callback * mechanism. If looper is null then the callbacks will be called on the main thread. + * @hide + * @deprecated client using this api should use {@link + * #registerCountryDetectorCallback(Executor, Consumer)} } */ @UnsupportedAppUsage - public void addCountryListener(CountryListener listener, Looper looper) { + @Deprecated + public void addCountryListener(@NonNull CountryListener listener, @Nullable Looper looper) { + Handler handler = looper != null ? new Handler(looper) : new Handler(); + registerCountryDetectorCallback(new HandlerExecutor(handler), listener); + } + + /** + * Remove the listener + * + * @hide + * @deprecated client using this api should use {@link + * #unregisterCountryDetectorCallback(Consumer)} + */ + @UnsupportedAppUsage + @Deprecated + public void removeCountryListener(CountryListener listener) { + unregisterCountryDetectorCallback(listener); + } + + /** + * Add a callback interface, to be notified when country code is added or changes. + * + * @param executor The callback executor for the response. + * @param consumer {@link Consumer} callback to receive the country code when changed/detected + */ + public void registerCountryDetectorCallback( + @NonNull Executor executor, @NonNull Consumer consumer) { synchronized (mListeners) { - if (!mListeners.containsKey(listener)) { - ListenerTransport transport = new ListenerTransport(listener, looper); - try { - mService.addCountryListener(transport); - mListeners.put(listener, transport); - } catch (RemoteException e) { - Log.e(TAG, "addCountryListener: RemoteException", e); - } + unregisterCountryDetectorCallback(consumer); + ListenerTransport transport = new ListenerTransport(consumer, executor); + try { + mService.addCountryListener(transport); + mListeners.put(consumer, transport); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } } - /** Remove the listener */ - @UnsupportedAppUsage - public void removeCountryListener(CountryListener listener) { + /** Remove the callback subscribed to Update country code */ + public void unregisterCountryDetectorCallback(@NonNull Consumer consumer) { synchronized (mListeners) { - ListenerTransport transport = mListeners.get(listener); + ListenerTransport transport = mListeners.remove(consumer); if (transport != null) { try { - mListeners.remove(listener); mService.removeCountryListener(transport); } catch (RemoteException e) { - Log.e(TAG, "removeCountryListener: RemoteException", e); + throw e.rethrowFromSystemServer(); } } } diff --git a/location/java/android/location/CountryListener.java b/location/java/android/location/CountryListener.java index eb67205f4de98..0ca6962460f86 100644 --- a/location/java/android/location/CountryListener.java +++ b/location/java/android/location/CountryListener.java @@ -18,16 +18,25 @@ package android.location; import android.compat.annotation.UnsupportedAppUsage; +import java.util.function.Consumer; + /** * The listener for receiving the notification when the country is detected or * changed * * @hide */ -public interface CountryListener { +public interface CountryListener extends Consumer { /** * @param country the changed or detected country. */ @UnsupportedAppUsage void onCountryDetected(Country country); + + /** + * @param country the changed or detected country. + */ + default void accept(Country country) { + onCountryDetected(country); + } } diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index a2a7dd35371fc..a6549253dcab3 100644 --- a/services/core/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java @@ -148,6 +148,10 @@ public class CountryDetectorService extends ICountryDetector.Stub { Receiver r = new Receiver(listener); try { listener.asBinder().linkToDeath(r, 0); + final Country country = detectCountry(); + if (country != null) { + listener.onCountryDetected(country); + } mReceivers.put(listener.asBinder(), r); if (mReceivers.size() == 1) { Slog.d(TAG, "The first listener is added");