Skip to content
Snippets Groups Projects
Commit 576862f5 authored by Nagendra Prasad Nagarle Basavaraju's avatar Nagendra Prasad Nagarle Basavaraju
Browse files

API Enhancement CountryDetector

-Replace CountryListener with a Consumer<Country>
-Add registerCountryDetectorCallback to take an Executor Vs addCountryListener taking Looper
-Add unregisterCountryDetectorCallback to remove Consumer<Country> 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
parent e655f11c
No related branches found
No related tags found
No related merge requests found
......@@ -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<android.location.Country> CREATOR;
}
 
public class CountryDetector {
method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Country>);
method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>);
}
public final class GnssCapabilities implements android.os.Parcelable {
method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
method @Deprecated public boolean hasNavMessages();
......@@ -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 {
* <li>{@link #COUNTRY_SOURCE_SIM}
* <li>{@link #COUNTRY_SOURCE_LOCALE}
* </ul>
*
* @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;
}
/**
* 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
* <p>
* <ul>
* <li>{@link #COUNTRY_SOURCE_NETWORK}
* <li>{@link #COUNTRY_SOURCE_LOCATION}
* <li>{@link #COUNTRY_SOURCE_SIM}
* <li>{@link #COUNTRY_SOURCE_LOCALE}
* </ul>
* <p>
* <ul>
* <li>{@link #COUNTRY_SOURCE_NETWORK}</li>
* <li>{@link #COUNTRY_SOURCE_LOCATION}</li>
* <li>{@link #COUNTRY_SOURCE_SIM}</li>
* <li>{@link #COUNTRY_SOURCE_LOCALE}</li>
* </ul>
*/
@CountrySource
public int getSource() {
return mSource;
}
......@@ -136,16 +176,15 @@ public final class Country implements Parcelable {
}
@android.annotation.NonNull
public static final Parcelable.Creator<Country> CREATOR =
new Parcelable.Creator<Country>() {
public Country createFromParcel(Parcel in) {
return new Country(in.readString(), in.readInt(), in.readLong());
}
public static final Parcelable.Creator<Country> CREATOR = new Parcelable.Creator<Country>() {
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) {
......
......@@ -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<Country>}
* objects together.
*
* <p>The CountryListener will be notified through the Handler Executor once the country changed
* and detected.
*
* <p>{@code Consumer<Country>} 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 Handler mHandler;
private final Consumer<Country> mListener;
private final Executor mExecutor;
public ListenerTransport(CountryListener listener, Looper looper) {
mListener = listener;
if (looper != null) {
mHandler = new Handler(looper);
} else {
mHandler = new Handler();
}
ListenerTransport(Consumer<Country> 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<CountryListener, ListenerTransport> mListeners;
private final HashMap<Consumer<Country>, 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<CountryListener, ListenerTransport>();
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<Country> 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<Country> 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();
}
}
}
......
......@@ -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<Country> {
/**
* @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);
}
}
......@@ -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");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment