From 7a46eda83ee043d516467182bf49a3d55106e58f Mon Sep 17 00:00:00 2001 From: Soonil Nagarkar Date: Tue, 5 Jan 2021 13:12:14 -0800 Subject: Add GNSS capabilities and antenna broadcasts Provide a system wide broadcast when GNSS capabilities change and when GNSS antenna infos change so that clients have some way to detect this. Antenna info was previously implemented as a listener, but after evaluating the information, it is not protected, changes infrequently with device configuration (if a foldable is unfolded for instance), and clients need to see every change (not the previous model of only sending changes while the client is foreground and GPS is enabled). As a corollary, deprecate GNSS status events. These status messages contain duplicate, inconsistent information, and do not scale for new APIs. In addition, we don't have any clients that use these status messages for any real purpose. Bug: 153129152 Test: atest CtsLocationFineTestCases Change-Id: Icc5bed8e37c7e8f168de57d2a019e94d96c0d3f2 --- .../java/android/location/GnssAntennaInfo.java | 223 ++++++++++++++------- .../android/location/GnssMeasurementsEvent.java | 22 +- .../android/location/GnssNavigationMessage.java | 16 ++ location/java/android/location/GnssStatus.java | 20 -- .../android/location/IGnssAntennaInfoListener.aidl | 26 --- .../java/android/location/ILocationManager.aidl | 7 +- .../java/android/location/LocationManager.java | 108 ++++++++-- 7 files changed, 277 insertions(+), 145 deletions(-) delete mode 100644 location/java/android/location/IGnssAntennaInfoListener.aidl (limited to 'location/java') diff --git a/location/java/android/location/GnssAntennaInfo.java b/location/java/android/location/GnssAntennaInfo.java index 23977f18f749..f1eb8fccdd3c 100644 --- a/location/java/android/location/GnssAntennaInfo.java +++ b/location/java/android/location/GnssAntennaInfo.java @@ -34,17 +34,19 @@ import java.util.Objects; public final class GnssAntennaInfo implements Parcelable { private final double mCarrierFrequencyMHz; private final PhaseCenterOffset mPhaseCenterOffset; - private final SphericalCorrections mPhaseCenterVariationCorrections; - private final SphericalCorrections mSignalGainCorrections; + private final @Nullable SphericalCorrections mPhaseCenterVariationCorrections; + private final @Nullable SphericalCorrections mSignalGainCorrections; /** - * Used for receiving GNSS antenna info from the GNSS engine. You can implement this interface - * and call {@link LocationManager#registerAntennaInfoListener}; + * Used for receiving GNSS antenna info from the GNSS engine. + * + * @deprecated Prefer to use a broadcast receiver for + * {@link LocationManager#ACTION_GNSS_ANTENNA_INFOS_CHANGED}. */ + @Deprecated public interface Listener { /** - * Returns the latest GNSS antenna info. This event is triggered when a listener is - * registered, and whenever the antenna info changes (due to a device configuration change). + * Invoked on a change to GNSS antenna info. */ void onGnssAntennaInfoReceived(@NonNull List gnssAntennaInfos); } @@ -172,6 +174,28 @@ public final class GnssAntennaInfo implements Parcelable { + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm + '}'; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PhaseCenterOffset)) { + return false; + } + PhaseCenterOffset that = (PhaseCenterOffset) o; + return Double.compare(that.mOffsetXMm, mOffsetXMm) == 0 + && Double.compare(that.mOffsetXUncertaintyMm, mOffsetXUncertaintyMm) == 0 + && Double.compare(that.mOffsetYMm, mOffsetYMm) == 0 + && Double.compare(that.mOffsetYUncertaintyMm, mOffsetYUncertaintyMm) == 0 + && Double.compare(that.mOffsetZMm, mOffsetZMm) == 0 + && Double.compare(that.mOffsetZUncertaintyMm, mOffsetZUncertaintyMm) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(mOffsetXMm, mOffsetYMm, mOffsetZMm); + } } /** @@ -190,38 +214,34 @@ public final class GnssAntennaInfo implements Parcelable { * i.e., deltaPhi = 180 / (number of columns - 1). */ public static final class SphericalCorrections implements Parcelable { - private final double[][] mCorrections; - private final double[][] mCorrectionUncertainties; - private final double mDeltaTheta; - private final double mDeltaPhi; + private final int mNumRows; private final int mNumColumns; + private final double[][] mCorrections; + private final double[][] mCorrectionUncertainties; public SphericalCorrections(@NonNull double[][] corrections, @NonNull double[][] correctionUncertainties) { - if (corrections.length != correctionUncertainties.length - || corrections[0].length != correctionUncertainties[0].length) { - throw new IllegalArgumentException("Correction and correction uncertainty arrays " - + "must have the same dimensions."); + if (corrections.length != correctionUncertainties.length || corrections.length < 1) { + throw new IllegalArgumentException("correction and uncertainty arrays must have " + + "the same (non-zero) dimensions"); } mNumRows = corrections.length; - if (mNumRows < 1) { - throw new IllegalArgumentException("Arrays must have at least one row."); - } - mNumColumns = corrections[0].length; - if (mNumColumns < 2) { - throw new IllegalArgumentException("Arrays must have at least two columns."); + for (int i = 0; i < corrections.length; i++) { + if (corrections[i].length != mNumColumns + || correctionUncertainties[i].length != mNumColumns || mNumColumns < 2) { + throw new IllegalArgumentException("correction and uncertainty arrays must all " + + " have the same (greater than 2) number of columns"); + } } mCorrections = corrections; mCorrectionUncertainties = correctionUncertainties; - mDeltaTheta = 360.0d / mNumRows; - mDeltaPhi = 180.0d / (mNumColumns - 1); } - SphericalCorrections(Parcel in) { + private SphericalCorrections(Parcel in) { int numRows = in.readInt(); int numColumns = in.readInt(); @@ -231,19 +251,16 @@ public final class GnssAntennaInfo implements Parcelable { new double[numRows][numColumns]; for (int row = 0; row < numRows; row++) { - in.readDoubleArray(corrections[row]); - } - - for (int row = 0; row < numRows; row++) { - in.readDoubleArray(correctionUncertainties[row]); + for (int col = 0; col < numColumns; col++) { + corrections[row][col] = in.readDouble(); + correctionUncertainties[row][col] = in.readDouble(); + } } mNumRows = numRows; mNumColumns = numColumns; mCorrections = corrections; mCorrectionUncertainties = correctionUncertainties; - mDeltaTheta = 360.0d / mNumRows; - mDeltaPhi = 180.0d / (mNumColumns - 1); } /** @@ -286,7 +303,7 @@ public final class GnssAntennaInfo implements Parcelable { */ @FloatRange(from = 0.0f, to = 360.0f) public double getDeltaTheta() { - return mDeltaTheta; + return 360.0D / mNumRows; } /** @@ -294,7 +311,7 @@ public final class GnssAntennaInfo implements Parcelable { */ @FloatRange(from = 0.0f, to = 180.0f) public double getDeltaPhi() { - return mDeltaPhi; + return 180.0D / (mNumColumns - 1); } @@ -320,11 +337,11 @@ public final class GnssAntennaInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mNumRows); dest.writeInt(mNumColumns); - for (double[] row : mCorrections) { - dest.writeDoubleArray(row); - } - for (double[] row : mCorrectionUncertainties) { - dest.writeDoubleArray(row); + for (int row = 0; row < mNumRows; row++) { + for (int col = 0; col < mNumColumns; col++) { + dest.writeDouble(mCorrections[row][col]); + dest.writeDouble(mCorrectionUncertainties[row][col]); + } } } @@ -333,22 +350,41 @@ public final class GnssAntennaInfo implements Parcelable { return "SphericalCorrections{" + "Corrections=" + Arrays.toString(mCorrections) + ", CorrectionUncertainties=" + Arrays.toString(mCorrectionUncertainties) - + ", DeltaTheta=" + mDeltaTheta - + ", DeltaPhi=" + mDeltaPhi + + ", DeltaTheta=" + getDeltaTheta() + + ", DeltaPhi=" + getDeltaPhi() + '}'; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SphericalCorrections)) { + return false; + } + SphericalCorrections that = (SphericalCorrections) o; + return mNumRows == that.mNumRows + && mNumColumns == that.mNumColumns + && Arrays.deepEquals(mCorrections, that.mCorrections) + && Arrays.deepEquals(mCorrectionUncertainties, that.mCorrectionUncertainties); + } + + @Override + public int hashCode() { + int result = Arrays.deepHashCode(mCorrections); + result = 31 * result + Arrays.deepHashCode(mCorrectionUncertainties); + return result; + } } private GnssAntennaInfo( double carrierFrequencyMHz, - @NonNull PhaseCenterOffset phaseCenterOffset, + PhaseCenterOffset phaseCenterOffset, @Nullable SphericalCorrections phaseCenterVariationCorrections, @Nullable SphericalCorrections signalGainCorrectionDbi) { - if (phaseCenterOffset == null) { - throw new IllegalArgumentException("Phase Center Offset Coordinates cannot be null."); - } mCarrierFrequencyMHz = carrierFrequencyMHz; - mPhaseCenterOffset = phaseCenterOffset; + mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset); mPhaseCenterVariationCorrections = phaseCenterVariationCorrections; mSignalGainCorrections = signalGainCorrectionDbi; } @@ -359,8 +395,28 @@ public final class GnssAntennaInfo implements Parcelable { public static class Builder { private double mCarrierFrequencyMHz; private PhaseCenterOffset mPhaseCenterOffset; - private SphericalCorrections mPhaseCenterVariationCorrections; - private SphericalCorrections mSignalGainCorrections; + private @Nullable SphericalCorrections mPhaseCenterVariationCorrections; + private @Nullable SphericalCorrections mSignalGainCorrections; + + /** + * @deprecated Prefer {@link #Builder(double, PhaseCenterOffset)}. + */ + @Deprecated + public Builder() { + this(0, new PhaseCenterOffset(0, 0, 0, 0, 0, 0)); + } + + public Builder(double carrierFrequencyMHz, @NonNull PhaseCenterOffset phaseCenterOffset) { + mCarrierFrequencyMHz = carrierFrequencyMHz; + mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset); + } + + public Builder(@NonNull GnssAntennaInfo antennaInfo) { + mCarrierFrequencyMHz = antennaInfo.mCarrierFrequencyMHz; + mPhaseCenterOffset = antennaInfo.mPhaseCenterOffset; + mPhaseCenterVariationCorrections = antennaInfo.mPhaseCenterVariationCorrections; + mSignalGainCorrections = antennaInfo.mSignalGainCorrections; + } /** * Set antenna carrier frequency (MHz). @@ -462,32 +518,29 @@ public final class GnssAntennaInfo implements Parcelable { return mSignalGainCorrections; } - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - @Override - public GnssAntennaInfo createFromParcel(Parcel in) { - double carrierFrequencyMHz = in.readDouble(); - - ClassLoader classLoader = getClass().getClassLoader(); - PhaseCenterOffset phaseCenterOffset = - in.readParcelable(classLoader); - SphericalCorrections phaseCenterVariationCorrections = - in.readParcelable(classLoader); - SphericalCorrections signalGainCorrections = - in.readParcelable(classLoader); - - return new GnssAntennaInfo( - carrierFrequencyMHz, - phaseCenterOffset, - phaseCenterVariationCorrections, - signalGainCorrections); - } + public static final @NonNull Creator CREATOR = new Creator() { + @Override + public GnssAntennaInfo createFromParcel(Parcel in) { + double carrierFrequencyMHz = in.readDouble(); + PhaseCenterOffset phaseCenterOffset = + in.readTypedObject(PhaseCenterOffset.CREATOR); + SphericalCorrections phaseCenterVariationCorrections = + in.readTypedObject(SphericalCorrections.CREATOR); + SphericalCorrections signalGainCorrections = + in.readTypedObject(SphericalCorrections.CREATOR); + + return new GnssAntennaInfo( + carrierFrequencyMHz, + phaseCenterOffset, + phaseCenterVariationCorrections, + signalGainCorrections); + } - @Override - public GnssAntennaInfo[] newArray(int size) { - return new GnssAntennaInfo[size]; - } - }; + @Override + public GnssAntennaInfo[] newArray(int size) { + return new GnssAntennaInfo[size]; + } + }; @Override public int describeContents() { @@ -497,9 +550,9 @@ public final class GnssAntennaInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeDouble(mCarrierFrequencyMHz); - parcel.writeParcelable(mPhaseCenterOffset, flags); - parcel.writeParcelable(mPhaseCenterVariationCorrections, flags); - parcel.writeParcelable(mSignalGainCorrections, flags); + parcel.writeTypedObject(mPhaseCenterOffset, flags); + parcel.writeTypedObject(mPhaseCenterVariationCorrections, flags); + parcel.writeTypedObject(mSignalGainCorrections, flags); } @Override @@ -511,4 +564,26 @@ public final class GnssAntennaInfo implements Parcelable { + ", SignalGainCorrections=" + mSignalGainCorrections + '}'; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof GnssAntennaInfo)) { + return false; + } + GnssAntennaInfo that = (GnssAntennaInfo) o; + return Double.compare(that.mCarrierFrequencyMHz, mCarrierFrequencyMHz) == 0 + && mPhaseCenterOffset.equals(that.mPhaseCenterOffset) + && Objects.equals(mPhaseCenterVariationCorrections, + that.mPhaseCenterVariationCorrections) + && Objects.equals(mSignalGainCorrections, that.mSignalGainCorrections); + } + + @Override + public int hashCode() { + return Objects.hash(mCarrierFrequencyMHz, mPhaseCenterOffset, + mPhaseCenterVariationCorrections, mSignalGainCorrections); + } } diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java index 98ef2d4a6c9f..a07a64acb6e6 100644 --- a/location/java/android/location/GnssMeasurementsEvent.java +++ b/location/java/android/location/GnssMeasurementsEvent.java @@ -16,9 +16,9 @@ package android.location; -import android.annotation.TestApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; @@ -46,8 +46,10 @@ public final class GnssMeasurementsEvent implements Parcelable { public static abstract class Callback { /** * The status of the GNSS measurements event. + * @deprecated Do not use. * @hide */ + @Deprecated @Retention(RetentionPolicy.SOURCE) @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED, STATUS_NOT_ALLOWED}) public @interface GnssMeasurementsStatus {} @@ -56,19 +58,28 @@ public final class GnssMeasurementsEvent implements Parcelable { * The system does not support tracking of GNSS Measurements. * *

This status will not change in the future. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; /** * GNSS Measurements are successfully being tracked, it will receive updates once they are * available. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_READY = 1; /** * GPS provider or Location is disabled, updates will not be received until they are * enabled. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; /** @@ -81,7 +92,10 @@ public final class GnssMeasurementsEvent implements Parcelable { * *

If such a status is received, one would try again at a later time point where no * other client is having a conflicting request. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_NOT_ALLOWED = 3; /** @@ -91,7 +105,13 @@ public final class GnssMeasurementsEvent implements Parcelable { /** * Reports the latest status of the GNSS Measurements sub-system. + * + * @deprecated Do not rely on this callback. From Android S onwards this callback will be + * invoked once with {@link #STATUS_READY} in all cases for backwards compatibility, and + * then never invoked again. Use LocationManager APIs if you need to determine if + * GNSS measurements are supported or if location is off, etc... */ + @Deprecated public void onStatusChanged(@GnssMeasurementsStatus int status) {} } diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java index aade5ac63317..84a363d25c63 100644 --- a/location/java/android/location/GnssNavigationMessage.java +++ b/location/java/android/location/GnssNavigationMessage.java @@ -110,6 +110,7 @@ public final class GnssNavigationMessage implements Parcelable { public static abstract class Callback { /** * The status of GNSS Navigation Message event. + * @deprecated Do not use. * @hide */ @Retention(RetentionPolicy.SOURCE) @@ -120,19 +121,28 @@ public final class GnssNavigationMessage implements Parcelable { * The system does not support tracking of GNSS Navigation Messages. * * This status will not change in the future. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; /** * GNSS Navigation Messages are successfully being tracked, it will receive updates once * they are available. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_READY = 1; /** * GNSS provider or Location is disabled, updated will not be received until they are * enabled. + * + * @deprecated Do not use. */ + @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; /** @@ -142,7 +152,13 @@ public final class GnssNavigationMessage implements Parcelable { /** * Returns the latest status of the GNSS Navigation Messages sub-system. + * + * @deprecated Do not rely on this callback. From Android S onwards this callback will be + * invoked once with {@link #STATUS_READY} in all cases for backwards compatibility, and + * then never invoked again. Use LocationManager APIs if you need to determine if + * GNSS navigation messages are supported or if location is off, etc... */ + @Deprecated public void onStatusChanged(@GnssNavigationMessageStatus int status) {} } diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java index c5b4c1667831..b46e8ce2f605 100644 --- a/location/java/android/location/GnssStatus.java +++ b/location/java/android/location/GnssStatus.java @@ -391,20 +391,10 @@ public final class GnssStatus implements Parcelable { float[] basebandCn0DbHzs = new float[svCount]; for (int i = 0; i < svCount; i++) { svidWithFlags[i] = in.readInt(); - } - for (int i = 0; i < svCount; i++) { cn0DbHzs[i] = in.readFloat(); - } - for (int i = 0; i < svCount; i++) { elevations[i] = in.readFloat(); - } - for (int i = 0; i < svCount; i++) { azimuths[i] = in.readFloat(); - } - for (int i = 0; i < svCount; i++) { carrierFrequencies[i] = in.readFloat(); - } - for (int i = 0; i < svCount; i++) { basebandCn0DbHzs[i] = in.readFloat(); } @@ -428,20 +418,10 @@ public final class GnssStatus implements Parcelable { parcel.writeInt(mSvCount); for (int i = 0; i < mSvCount; i++) { parcel.writeInt(mSvidWithFlags[i]); - } - for (int i = 0; i < mSvCount; i++) { parcel.writeFloat(mCn0DbHzs[i]); - } - for (int i = 0; i < mSvCount; i++) { parcel.writeFloat(mElevations[i]); - } - for (int i = 0; i < mSvCount; i++) { parcel.writeFloat(mAzimuths[i]); - } - for (int i = 0; i < mSvCount; i++) { parcel.writeFloat(mCarrierFrequencies[i]); - } - for (int i = 0; i < mSvCount; i++) { parcel.writeFloat(mBasebandCn0DbHzs[i]); } } diff --git a/location/java/android/location/IGnssAntennaInfoListener.aidl b/location/java/android/location/IGnssAntennaInfoListener.aidl deleted file mode 100644 index 603ed6a2614e..000000000000 --- a/location/java/android/location/IGnssAntennaInfoListener.aidl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020, 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.GnssAntennaInfo; - -/** - * {@hide} - */ -oneway interface IGnssAntennaInfoListener { - void onGnssAntennaInfoReceived(in List gnssAntennaInfo); -} \ No newline at end of file diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 621fe1ba1432..c50904cad4e2 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -21,11 +21,11 @@ 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; import android.location.IGnssNavigationMessageListener; @@ -76,6 +76,8 @@ interface ILocationManager int getGnssYearOfHardware(); String getGnssHardwareModelName(); + @nullable List getGnssAntennaInfos(); + void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag); void unregisterGnssStatusCallback(in IGnssStatusListener callback); @@ -86,9 +88,6 @@ interface ILocationManager void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener); void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections); - void addGnssAntennaInfoListener(in IGnssAntennaInfoListener listener, String packageName, String attributionTag); - void removeGnssAntennaInfoListener(in IGnssAntennaInfoListener listener); - void addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener, String packageName, String attributionTag); void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 00381a68a2a2..1d3e8ebaa0ab 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -44,7 +44,10 @@ import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; @@ -64,6 +67,7 @@ import com.android.internal.listeners.ListenerTransportMultiplexer; import com.android.internal.util.Preconditions; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -311,6 +315,48 @@ public class LocationManager { public static final String HIGH_POWER_REQUEST_CHANGE_ACTION = "android.location.HIGH_POWER_REQUEST_CHANGE"; + /** + * Broadcast intent action when GNSS capabilities change. This is most common at boot time as + * GNSS capabilities are queried from the chipset. Includes an intent extra, + * {@link #EXTRA_GNSS_CAPABILITIES}, with the new {@link GnssCapabilities}. + * + * @see #EXTRA_GNSS_CAPABILITIES + * @see #getGnssCapabilities() + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_GNSS_CAPABILITIES_CHANGED = + "android.location.action.GNSS_CAPABILITIES_CHANGED"; + + /** + * Intent extra included with {@link #ACTION_GNSS_CAPABILITIES_CHANGED} broadcasts, containing + * the new {@link GnssCapabilities}. + * + * @see #ACTION_GNSS_CAPABILITIES_CHANGED + */ + public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES"; + + /** + * Broadcast intent action when GNSS antenna infos change. Includes an intent extra, + * {@link #EXTRA_GNSS_ANTENNA_INFOS}, with an ArrayList of the new {@link GnssAntennaInfo}. This + * may be read via {@link android.content.Intent#getParcelableArrayListExtra(String)}. + * + * @see #EXTRA_GNSS_ANTENNA_INFOS + * @see #getGnssAntennaInfos() + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_GNSS_ANTENNA_INFOS_CHANGED = + "android.location.action.GNSS_ANTENNA_INFOS_CHANGED"; + + /** + * Intent extra included with {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED} broadcasts, containing + * the new ArrayList of {@link GnssAntennaInfo}. This may be read via + * {@link android.content.Intent#getParcelableArrayListExtra(String)}. + * + * @see #ACTION_GNSS_ANTENNA_INFOS_CHANGED + */ + public static final String EXTRA_GNSS_ANTENNA_INFOS = + "android.location.extra.GNSS_ANTENNA_INFOS"; + /** * Broadcast intent action for Settings app to inject a footer at the bottom of location * settings. This is for use only by apps that are included in the system image. @@ -2136,6 +2182,20 @@ public class LocationManager { } } + /** + * Returns the current list of GNSS antenna infos, or null if unknown or unsupported. + * + * @see #getGnssCapabilities() + */ + @Nullable + public List getGnssAntennaInfos() { + try { + return mService.getGnssAntennaInfos(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Retrieves information about the current status of the GPS engine. This should only be called * from within the {@link GpsStatus.Listener#onGpsStatusChanged} callback to ensure that the @@ -2559,15 +2619,19 @@ public class LocationManager { * *

Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}. * + *

Prior to Android S, this requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} + * permission. + * * @param executor the executor that the listener runs on * @param listener the listener to register * @return {@code true} always * * @throws IllegalArgumentException if executor is null * @throws IllegalArgumentException if listener is null - * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + * + * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}. */ - @RequiresPermission(ACCESS_FINE_LOCATION) + @Deprecated public boolean registerAntennaInfoListener( @NonNull @CallbackExecutor Executor executor, @NonNull GnssAntennaInfo.Listener listener) { @@ -2579,7 +2643,10 @@ public class LocationManager { * Unregisters a GNSS Antenna Info listener. * * @param listener a {@link GnssAntennaInfo.Listener} object to remove + * + * @deprecated Prefer to use a receiver for {@link #ACTION_GNSS_ANTENNA_INFOS_CHANGED}. */ + @Deprecated public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) { getGnssAntennaInfoTransportMultiplexer().removeListener(listener); } @@ -3153,40 +3220,41 @@ public class LocationManager { private class GnssAntennaInfoTransportMultiplexer extends ListenerTransportMultiplexer { - private @Nullable IGnssAntennaInfoListener mListenerTransport; + private @Nullable BroadcastReceiver mListenerTransport; GnssAntennaInfoTransportMultiplexer() {} @Override - protected void registerWithServer(Void ignored) throws RemoteException { - IGnssAntennaInfoListener transport = mListenerTransport; - if (transport == null) { - transport = new GnssAntennaInfoListener(); + protected void registerWithServer(Void ignored) { + if (mListenerTransport == null) { + // if an exception is thrown the transport should not be set + BroadcastReceiver transport = new GnssAntennaInfoReceiver(); + mContext.registerReceiver(transport, + new IntentFilter(ACTION_GNSS_ANTENNA_INFOS_CHANGED)); + mListenerTransport = transport; } - - // if a remote exception is thrown the transport should not be set - mListenerTransport = null; - mService.addGnssAntennaInfoListener(transport, mContext.getPackageName(), - mContext.getAttributionTag()); - mListenerTransport = transport; } @Override - protected void unregisterWithServer() throws RemoteException { + protected void unregisterWithServer() { if (mListenerTransport != null) { - IGnssAntennaInfoListener transport = mListenerTransport; + BroadcastReceiver transport = mListenerTransport; mListenerTransport = null; - mService.removeGnssAntennaInfoListener(transport); + mContext.unregisterReceiver(transport); } } - private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub { + private class GnssAntennaInfoReceiver extends BroadcastReceiver { - GnssAntennaInfoListener() {} + GnssAntennaInfoReceiver() {} @Override - public void onGnssAntennaInfoReceived(List infos) { - deliverToListeners(callback -> callback.onGnssAntennaInfoReceived(infos)); + public void onReceive(Context context, Intent intent) { + ArrayList infos = intent.getParcelableArrayListExtra( + EXTRA_GNSS_ANTENNA_INFOS); + if (infos != null) { + deliverToListeners(callback -> callback.onGnssAntennaInfoReceived(infos)); + } } } } -- cgit v1.2.3-59-g8ed1b