From af90af79315d30ce62131bc43a828b57bade78ba Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Wed, 29 Dec 2021 15:58:42 -0800 Subject: Add GnssAutomaticGainControl to GnssMeasurementsEvent (frameworks/base) AgcLevelDb has been a subfield of GnssMeasurement. However, GnssMeasurement is only reported by the chipset when there is GNSS signal. For example, in deep indoor, or when there is strong jamming signal, no GnssMeasurement can be reported, and thus no AGC value can be reported. To resolve that, we are adding this GnssAgc to GnssMeasurementsEvent directly, so that the client can get AGC values even without GNSS signal (i.e., without GnssMeasurement). Bug: 206670536 Test: atest GnssAutomaticGainControlTest atest GnssMeasurementsEventTest Change-Id: I97c7ec98b6e8cc977c6e879b52a8cf75c355ae33 --- .../android/location/GnssAutomaticGainControl.aidl | 19 ++ .../android/location/GnssAutomaticGainControl.java | 215 +++++++++++++++++++++ .../java/android/location/GnssMeasurement.java | 8 + .../android/location/GnssMeasurementsEvent.java | 161 +++++++++++---- 4 files changed, 362 insertions(+), 41 deletions(-) create mode 100644 location/java/android/location/GnssAutomaticGainControl.aidl create mode 100644 location/java/android/location/GnssAutomaticGainControl.java (limited to 'location/java/android') diff --git a/location/java/android/location/GnssAutomaticGainControl.aidl b/location/java/android/location/GnssAutomaticGainControl.aidl new file mode 100644 index 000000000000..8298cb711064 --- /dev/null +++ b/location/java/android/location/GnssAutomaticGainControl.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 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; + +parcelable GnssAutomaticGainControl; diff --git a/location/java/android/location/GnssAutomaticGainControl.java b/location/java/android/location/GnssAutomaticGainControl.java new file mode 100644 index 000000000000..e4f7304a8c9d --- /dev/null +++ b/location/java/android/location/GnssAutomaticGainControl.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 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.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.Objects; + +/** + * A class that contains GNSS Automatic Gain Control (AGC) information. + * + *

AGC acts as a variable gain amplifier adjusting the power of the incoming signal. The AGC + * level may be used to indicate potential interference. Higher gain (and/or lower input power) + * shall be output as a positive number. Hence in cases of strong jamming, in the band of this + * signal, this value will go more negative. This value must be consistent given the same level + * of the incoming signal power. + * + *

Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW + * components) may also affect the typical output of this value on any given hardware design + * in an open sky test - the important aspect of this output is that changes in this value are + * indicative of changes on input signal power in the frequency band for this measurement. + */ +public final class GnssAutomaticGainControl implements Parcelable { + private final double mLevelDb; + private final int mConstellationType; + private final long mCarrierFrequencyHz; + + /** + * Creates a {@link GnssAutomaticGainControl} with a full list of parameters. + */ + private GnssAutomaticGainControl(double levelDb, int constellationType, + long carrierFrequencyHz) { + mLevelDb = levelDb; + mConstellationType = constellationType; + mCarrierFrequencyHz = carrierFrequencyHz; + } + + /** + * Gets the Automatic Gain Control level in dB. + */ + @FloatRange(from = -10000, to = 10000) + public double getLevelDb() { + return mLevelDb; + } + + /** + * Gets the constellation type. + * + *

The return value is one of those constants with {@code CONSTELLATION_} prefix in + * {@link GnssStatus}. + */ + @GnssStatus.ConstellationType + public int getConstellationType() { + return mConstellationType; + } + + /** + * Gets the carrier frequency of the tracked signal. + * + *

For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, + * L5 = 1176.45 MHz, varying GLO channels, etc. + * + * @return the carrier frequency of the signal tracked in Hz. + */ + @IntRange(from = 0) + public long getCarrierFrequencyHz() { + return mCarrierFrequencyHz; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flag) { + parcel.writeDouble(mLevelDb); + parcel.writeInt(mConstellationType); + parcel.writeLong(mCarrierFrequencyHz); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + @NonNull + public GnssAutomaticGainControl createFromParcel(@NonNull Parcel parcel) { + return new GnssAutomaticGainControl(parcel.readDouble(), parcel.readInt(), + parcel.readLong()); + } + + @Override + public GnssAutomaticGainControl[] newArray(int i) { + return new GnssAutomaticGainControl[i]; + } + }; + + @NonNull + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("GnssAutomaticGainControl["); + s.append("Level=").append(mLevelDb).append(" dB"); + s.append(" Constellation=").append( + GnssStatus.constellationTypeToString(mConstellationType)); + s.append(" CarrierFrequency=").append(mCarrierFrequencyHz).append(" Hz"); + s.append(']'); + return s.toString(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof GnssAutomaticGainControl)) { + return false; + } + + GnssAutomaticGainControl other = (GnssAutomaticGainControl) obj; + if (Double.compare(mLevelDb, other.mLevelDb) + != 0) { + return false; + } + if (mConstellationType != other.mConstellationType) { + return false; + } + if (mCarrierFrequencyHz != other.mCarrierFrequencyHz) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(mLevelDb, mConstellationType, mCarrierFrequencyHz); + } + + /** Builder for {@link GnssAutomaticGainControl} */ + public static final class Builder { + private double mLevelDb; + private int mConstellationType; + private long mCarrierFrequencyHz; + + /** + * Constructs a {@link GnssAutomaticGainControl.Builder} instance. + */ + public Builder() { + } + + /** + * Constructs a {@link GnssAutomaticGainControl.Builder} instance by copying a + * {@link GnssAutomaticGainControl}. + */ + public Builder(@NonNull GnssAutomaticGainControl agc) { + mLevelDb = agc.getLevelDb(); + mConstellationType = agc.getConstellationType(); + mCarrierFrequencyHz = agc.getCarrierFrequencyHz(); + } + + /** + * Sets the Automatic Gain Control level in dB. + */ + @NonNull + public Builder setLevelDb(@FloatRange(from = -10000, to = 10000) double levelDb) { + Preconditions.checkArgument(levelDb >= -10000 && levelDb <= 10000); + mLevelDb = levelDb; + return this; + } + + /** + * Sets the constellation type. + */ + @NonNull + public Builder setConstellationType(@GnssStatus.ConstellationType int constellationType) { + mConstellationType = constellationType; + return this; + } + + /** + * Sets the Carrier frequency in Hz. + */ + @NonNull public Builder setCarrierFrequencyHz(@IntRange(from = 0) long carrierFrequencyHz) { + Preconditions.checkArgumentNonnegative(carrierFrequencyHz); + mCarrierFrequencyHz = carrierFrequencyHz; + return this; + } + + /** Builds a {@link GnssAutomaticGainControl} instance as specified by this builder. */ + @NonNull + public GnssAutomaticGainControl build() { + return new GnssAutomaticGainControl(mLevelDb, mConstellationType, mCarrierFrequencyHz); + } + } +} diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index ecdd4b616e0f..cdfa02c8b28f 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -1381,7 +1381,10 @@ public final class GnssMeasurement implements Parcelable { /** * Returns {@code true} if {@link #getAutomaticGainControlLevelDb()} is available, * {@code false} otherwise. + * + * @deprecated Use {@link GnssMeasurementsEvent#getGnssAutomaticGainControls()} instead. */ + @Deprecated public boolean hasAutomaticGainControlLevelDb() { return isFlagSet(HAS_AUTOMATIC_GAIN_CONTROL); } @@ -1401,7 +1404,10 @@ public final class GnssMeasurement implements Parcelable { * indicative of changes on input signal power in the frequency band for this measurement. * *

The value is only available if {@link #hasAutomaticGainControlLevelDb()} is {@code true} + * + * @deprecated Use {@link GnssMeasurementsEvent#getGnssAutomaticGainControls()} instead. */ + @Deprecated public double getAutomaticGainControlLevelDb() { return mAutomaticGainControlLevelInDb; } @@ -1409,7 +1415,9 @@ public final class GnssMeasurement implements Parcelable { /** * Sets the Automatic Gain Control level in dB. * @hide + * @deprecated Use {@link GnssMeasurementsEvent.Builder#setGnssAutomaticGainControls()} instead. */ + @Deprecated @TestApi public void setAutomaticGainControlLevelInDb(double agcLevelDb) { setFlag(HAS_AUTOMATIC_GAIN_CONTROL); diff --git a/location/java/android/location/GnssMeasurementsEvent.java b/location/java/android/location/GnssMeasurementsEvent.java index a07a64acb6e6..075ddebc859f 100644 --- a/location/java/android/location/GnssMeasurementsEvent.java +++ b/location/java/android/location/GnssMeasurementsEvent.java @@ -18,16 +18,19 @@ package android.location; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.TestApi; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.Preconditions; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.security.InvalidParameterException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * A class implementing a container for data associated with a measurement event. @@ -35,7 +38,8 @@ import java.util.Collections; */ public final class GnssMeasurementsEvent implements Parcelable { private final GnssClock mClock; - private final Collection mReadOnlyMeasurements; + private final List mMeasurements; + private final List mGnssAgcs; /** * Used for receiving GNSS satellite measurements from the GNSS engine. @@ -116,20 +120,13 @@ public final class GnssMeasurementsEvent implements Parcelable { } /** - * @hide + * Create a {@link GnssMeasurementsEvent} instance with a full list of parameters. */ - @TestApi - public GnssMeasurementsEvent(GnssClock clock, GnssMeasurement[] measurements) { - if (clock == null) { - throw new InvalidParameterException("Parameter 'clock' must not be null."); - } - if (measurements == null || measurements.length == 0) { - mReadOnlyMeasurements = Collections.emptyList(); - } else { - Collection measurementCollection = Arrays.asList(measurements); - mReadOnlyMeasurements = Collections.unmodifiableCollection(measurementCollection); - } - + private GnssMeasurementsEvent(@NonNull GnssClock clock, + @NonNull List measurements, + @NonNull List agcs) { + mMeasurements = measurements; + mGnssAgcs = agcs; mClock = clock; } @@ -143,26 +140,31 @@ public final class GnssMeasurementsEvent implements Parcelable { } /** - * Gets a read-only collection of measurements associated with the current event. + * Gets the collection of measurements associated with the current event. */ @NonNull public Collection getMeasurements() { - return mReadOnlyMeasurements; + return mMeasurements; + } + + /** + * Gets the collection of {@link GnssAutomaticGainControl} associated with the + * current event. + */ + @NonNull + public Collection getGnssAutomaticGainControls() { + return mGnssAgcs; } public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public GnssMeasurementsEvent createFromParcel(Parcel in) { - ClassLoader classLoader = getClass().getClassLoader(); - - GnssClock clock = in.readParcelable(classLoader); - - int measurementsLength = in.readInt(); - GnssMeasurement[] measurementsArray = new GnssMeasurement[measurementsLength]; - in.readTypedArray(measurementsArray, GnssMeasurement.CREATOR); - - return new GnssMeasurementsEvent(clock, measurementsArray); + GnssClock clock = in.readParcelable(getClass().getClassLoader()); + List measurements = in.createTypedArrayList(GnssMeasurement.CREATOR); + List agcs = in.createTypedArrayList( + GnssAutomaticGainControl.CREATOR); + return new GnssMeasurementsEvent(clock, measurements, agcs); } @Override @@ -179,28 +181,105 @@ public final class GnssMeasurementsEvent implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeParcelable(mClock, flags); - - int measurementsCount = mReadOnlyMeasurements.size(); - GnssMeasurement[] measurementsArray = - mReadOnlyMeasurements.toArray(new GnssMeasurement[measurementsCount]); - parcel.writeInt(measurementsArray.length); - parcel.writeTypedArray(measurementsArray, flags); + parcel.writeTypedList(mMeasurements); + parcel.writeTypedList(mGnssAgcs); } @Override public String toString() { - StringBuilder builder = new StringBuilder("[ GnssMeasurementsEvent:\n\n"); + StringBuilder builder = new StringBuilder("GnssMeasurementsEvent["); + builder.append(mClock); + builder.append(' ').append(mMeasurements.toString()); + builder.append(' ').append(mGnssAgcs.toString()); + builder.append("]"); + return builder.toString(); + } - builder.append(mClock.toString()); - builder.append("\n"); + /** Builder for {@link GnssMeasurementsEvent} */ + public static final class Builder { + private GnssClock mClock; + private List mMeasurements; + private List mGnssAgcs; - for (GnssMeasurement measurement : mReadOnlyMeasurements) { - builder.append(measurement.toString()); - builder.append("\n"); + /** + * Constructs a {@link GnssMeasurementsEvent.Builder} instance. + */ + public Builder() { + mClock = new GnssClock(); + mMeasurements = new ArrayList<>(); + mGnssAgcs = new ArrayList<>(); } - builder.append("]"); + /** + * Constructs a {@link GnssMeasurementsEvent.Builder} instance by copying a + * {@link GnssMeasurementsEvent}. + */ + public Builder(@NonNull GnssMeasurementsEvent event) { + mClock = event.getClock(); + mMeasurements = (List) event.getMeasurements(); + mGnssAgcs = (List) event.getGnssAutomaticGainControls(); + } - return builder.toString(); + /** + * Sets the {@link GnssClock}. + */ + @NonNull + public Builder setClock(@NonNull GnssClock clock) { + Preconditions.checkNotNull(clock); + mClock = clock; + return this; + } + + /** + * Sets the collection of {@link GnssMeasurement}. + * + * This API exists for JNI since it is easier for JNI to work with an array than a + * collection. + * @hide + */ + @NonNull + public Builder setMeasurements(@Nullable GnssMeasurement... measurements) { + mMeasurements = measurements == null ? Collections.emptyList() : Arrays.asList( + measurements); + return this; + } + + /** + * Sets the collection of {@link GnssMeasurement}. + */ + @NonNull + public Builder setMeasurements(@NonNull Collection measurements) { + mMeasurements = new ArrayList<>(measurements); + return this; + } + + /** + * Sets the collection of {@link GnssAutomaticGainControl}. + * + * This API exists for JNI since it is easier for JNI to work with an array than a + * collection. + * @hide + */ + @NonNull + public Builder setGnssAutomaticGainControls(@Nullable GnssAutomaticGainControl... agcs) { + mGnssAgcs = agcs == null ? Collections.emptyList() : Arrays.asList(agcs); + return this; + } + + /** + * Sets the collection of {@link GnssAutomaticGainControl}. + */ + @NonNull + public Builder setGnssAutomaticGainControls( + @NonNull Collection agcs) { + mGnssAgcs = new ArrayList<>(agcs); + return this; + } + + /** Builds a {@link GnssMeasurementsEvent} instance as specified by this builder. */ + @NonNull + public GnssMeasurementsEvent build() { + return new GnssMeasurementsEvent(mClock, mMeasurements, mGnssAgcs); + } } } -- cgit v1.2.3-59-g8ed1b