blob: dfcaf814f9c9acac2ea71aabe52a034908513e3f [file] [log] [blame]
/*
* 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.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
* A class that contains information about a GNSS antenna. GNSS antenna characteristics can change
* with device configuration, such as when a device is folded open or closed. Antenna information is
* delivered to registered instances of {@link Callback}.
*/
public final class GnssAntennaInfo implements Parcelable {
private final double mCarrierFrequencyMHz;
private final PhaseCenterOffsetCoordinates mPhaseCenterOffsetCoordinates;
private final PhaseCenterVariationCorrections mPhaseCenterVariationCorrections;
private final SignalGainCorrections mSignalGainCorrections;
/**
* Used for receiving GNSS antenna info from the GNSS engine. You can implement this interface
* and call {@link LocationManager#registerAntennaInfoCallback};
*/
public abstract static class Callback {
/**
* The status of GNSS antenna info.
*
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_LOCATION_DISABLED})
public @interface GnssAntennaInfoStatus {
}
/**
* The system does not support GNSS antenna info.
*
* This status will not change in the future.
*/
public static final int STATUS_NOT_SUPPORTED = 0;
/**
* GNSS antenna info updates are being successfully tracked.
*/
public static final int STATUS_READY = 1;
/**
* GNSS provider or Location is disabled, updated will not be received until they are
* enabled.
*/
public static final int STATUS_LOCATION_DISABLED = 2;
/**
* Returns the latest GNSS antenna info. This event is triggered when a callback is
* registered, and whenever the antenna info changes (due to a device configuration change).
*/
public void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos) {}
/**
* Returns the latest status of the GNSS antenna info sub-system.
*/
public void onStatusChanged(@GnssAntennaInfoStatus int status) {}
}
/**
* Class containing information about the antenna phase center offset (PCO). PCO is defined with
* respect to the origin of the Android sensor coordinate system, e.g., center of primary screen
* for mobiles - see sensor or form factor documents for details. Uncertainties are reported
* to 1-sigma.
*/
public static final class PhaseCenterOffsetCoordinates implements Parcelable {
private final double mPhaseCenterOffsetCoordinateXMillimeters;
private final double mPhaseCenterOffsetCoordinateXUncertaintyMillimeters;
private final double mPhaseCenterOffsetCoordinateYMillimeters;
private final double mPhaseCenterOffsetCoordinateYUncertaintyMillimeters;
private final double mPhaseCenterOffsetCoordinateZMillimeters;
private final double mPhaseCenterOffsetCoordinateZUncertaintyMillimeters;
@VisibleForTesting
public PhaseCenterOffsetCoordinates(double phaseCenterOffsetCoordinateXMillimeters,
double phaseCenterOffsetCoordinateXUncertaintyMillimeters,
double phaseCenterOffsetCoordinateYMillimeters,
double phaseCenterOffsetCoordinateYUncertaintyMillimeters,
double phaseCenterOffsetCoordinateZMillimeters,
double phaseCenterOffsetCoordinateZUncertaintyMillimeters) {
mPhaseCenterOffsetCoordinateXMillimeters = phaseCenterOffsetCoordinateXMillimeters;
mPhaseCenterOffsetCoordinateYMillimeters = phaseCenterOffsetCoordinateYMillimeters;
mPhaseCenterOffsetCoordinateZMillimeters = phaseCenterOffsetCoordinateZMillimeters;
mPhaseCenterOffsetCoordinateXUncertaintyMillimeters =
phaseCenterOffsetCoordinateXUncertaintyMillimeters;
mPhaseCenterOffsetCoordinateYUncertaintyMillimeters =
phaseCenterOffsetCoordinateYUncertaintyMillimeters;
mPhaseCenterOffsetCoordinateZUncertaintyMillimeters =
phaseCenterOffsetCoordinateZUncertaintyMillimeters;
}
public static final @NonNull Creator<PhaseCenterOffsetCoordinates> CREATOR =
new Creator<PhaseCenterOffsetCoordinates>() {
@Override
public PhaseCenterOffsetCoordinates createFromParcel(Parcel in) {
return new PhaseCenterOffsetCoordinates(
in.readDouble(),
in.readDouble(),
in.readDouble(),
in.readDouble(),
in.readDouble(),
in.readDouble()
);
}
@Override
public PhaseCenterOffsetCoordinates[] newArray(int size) {
return new PhaseCenterOffsetCoordinates[size];
}
};
public double getXCoordMillimeters() {
return mPhaseCenterOffsetCoordinateXMillimeters;
}
public double getXCoordUncertaintyMillimeters() {
return mPhaseCenterOffsetCoordinateXUncertaintyMillimeters;
}
public double getYCoordMillimeters() {
return mPhaseCenterOffsetCoordinateYMillimeters;
}
public double getYCoordUncertaintyMillimeters() {
return mPhaseCenterOffsetCoordinateYUncertaintyMillimeters;
}
public double getZCoordMillimeters() {
return mPhaseCenterOffsetCoordinateZMillimeters;
}
public double getZCoordUncertaintyMillimeters() {
return mPhaseCenterOffsetCoordinateZUncertaintyMillimeters;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeDouble(mPhaseCenterOffsetCoordinateXMillimeters);
dest.writeDouble(mPhaseCenterOffsetCoordinateXUncertaintyMillimeters);
dest.writeDouble(mPhaseCenterOffsetCoordinateYMillimeters);
dest.writeDouble(mPhaseCenterOffsetCoordinateYUncertaintyMillimeters);
dest.writeDouble(mPhaseCenterOffsetCoordinateZMillimeters);
dest.writeDouble(mPhaseCenterOffsetCoordinateZUncertaintyMillimeters);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("PhaseCenteroffset:\n");
builder.append("X: " + mPhaseCenterOffsetCoordinateXMillimeters + " +/- "
+ mPhaseCenterOffsetCoordinateXUncertaintyMillimeters + "\n");
builder.append("Y: " + mPhaseCenterOffsetCoordinateYMillimeters + " +/- "
+ mPhaseCenterOffsetCoordinateYUncertaintyMillimeters + "\n");
builder.append("Z: " + mPhaseCenterOffsetCoordinateZMillimeters + " +/- "
+ mPhaseCenterOffsetCoordinateZUncertaintyMillimeters + "\n");
return builder.toString();
}
}
/**
* Class containing information about the phase center variation (PCV) corrections. The PCV
* correction is added to the phase measurement to obtain the corrected value.
*
* The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays.
*
* Each row (major indices) represents a fixed theta. The first row corresponds to a
* theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
* degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
* = 360 / (number of rows).
*
* The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
* at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
* i.e., deltaPhi = 180 / (number of columns - 1).
*/
public static final class PhaseCenterVariationCorrections extends SphericalCorrections {
@VisibleForTesting
public PhaseCenterVariationCorrections(
@NonNull double[][] phaseCenterVariationCorrectionsMillimeters,
@NonNull double[][] phaseCenterVariationCorrectionUncertaintiesMillimeters) {
super(phaseCenterVariationCorrectionsMillimeters,
phaseCenterVariationCorrectionUncertaintiesMillimeters);
}
private PhaseCenterVariationCorrections(@NonNull Parcel in) {
super(in);
}
/**
* Get the phase center variation correction in millimeters at the specified row and column
* in the underlying 2D array.
* @param row zero-based major index in the array
* @param column zero-based minor index in the array
* @return phase center correction in millimeters
*/
public double getPhaseCenterVariationCorrectionMillimetersAt(int row, int column) {
return super.getCorrectionAt(row, column);
}
/**
* Get the phase center variation correction uncertainty in millimeters at the specified row
* and column in the underlying 2D array.
* @param row zero-based major index in the array
* @param column zero-based minor index in the array
* @return 1-sigma phase center correction uncertainty in millimeters
*/
public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt(
int row, int column) {
return super.getCorrectionUncertaintyAt(row, column);
}
public @NonNull double[][] getRawCorrectionsArray() {
return super.getRawCorrectionsArray().clone();
}
public @NonNull double[][] getRawCorrectionUncertaintiesArray() {
return super.getRawCorrectionUncertaintiesArray().clone();
}
public int getNumRows() {
return super.getNumRows();
}
public int getNumColumns() {
return super.getNumColumns();
}
/**
* The fixed theta angle separation between successive rows.
*/
public double getDeltaTheta() {
return super.getDeltaTheta();
}
/**
* The fixed phi angle separation between successive columns.
*/
public double getDeltaPhi() {
return super.getDeltaPhi();
}
public static final @NonNull Creator<PhaseCenterVariationCorrections> CREATOR =
new Creator<PhaseCenterVariationCorrections>() {
@Override
public PhaseCenterVariationCorrections createFromParcel(Parcel in) {
return new PhaseCenterVariationCorrections(in);
}
@Override
public PhaseCenterVariationCorrections[] newArray(int size) {
return new PhaseCenterVariationCorrections[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("PhaseCenterVariationCorrections:\n");
builder.append(super.toString());
return builder.toString();
}
}
/**
* Class containing information about the signal gain (SG) corrections. The SG
* correction is added to the signal gain to obtain the corrected value.
*
* The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays.
*
* Each row (major indices) represents a fixed theta. The first row corresponds to a
* theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
* degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
* = 360 / (number of rows).
*
* The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
* at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
* i.e., deltaPhi = 180 / (number of columns - 1).
*/
public static final class SignalGainCorrections extends SphericalCorrections {
@VisibleForTesting
public SignalGainCorrections(
@NonNull double[][] signalGainCorrectionsDbi,
@NonNull double[][] signalGainCorrectionUncertaintiesDbi) {
super(signalGainCorrectionsDbi,
signalGainCorrectionUncertaintiesDbi);
}
private SignalGainCorrections(@NonNull Parcel in) {
super(in);
}
/**
* Get the signal gain correction in dbi at the specified row and column
* in the underlying 2D array.
* @param row zero-based major index in the array
* @param column zero-based minor index in the array
* @return signal gain correction in dbi
*/
public double getSignalGainCorrectionDbiAt(int row, int column) {
return super.getCorrectionAt(row, column);
}
/**
* Get the signal gain correction correction uncertainty in dbi at the specified row
* and column in the underlying 2D array.
* @param row zero-based major index in the array
* @param column zero-based minor index in the array
* @return 1-sigma signal gain correction uncertainty in dbi
*/
public double getSignalGainCorrectionUncertaintyDbiAt(int row, int column) {
return super.getCorrectionUncertaintyAt(row, column);
}
public @NonNull double[][] getRawCorrectionsArray() {
return super.getRawCorrectionsArray().clone();
}
public @NonNull double[][] getRawCorrectionUncertaintiesArray() {
return super.getRawCorrectionUncertaintiesArray().clone();
}
public int getNumRows() {
return super.getNumRows();
}
public int getNumColumns() {
return super.getNumColumns();
}
/**
* The fixed theta angle separation between successive rows.
*/
public double getDeltaTheta() {
return super.getDeltaTheta();
}
/**
* The fixed phi angle separation between successive columns.
*/
public double getDeltaPhi() {
return super.getDeltaPhi();
}
public static final @NonNull Creator<SignalGainCorrections> CREATOR =
new Creator<SignalGainCorrections>() {
@Override
public SignalGainCorrections createFromParcel(Parcel in) {
return new SignalGainCorrections(in);
}
@Override
public SignalGainCorrections[] newArray(int size) {
return new SignalGainCorrections[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("SignalGainCorrections:\n");
builder.append(super.toString());
return builder.toString();
}
}
/**
* Represents corrections on a spherical mapping.
*
* Each row (major indices) represents a fixed theta. The first row corresponds to a
* theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
* degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
* = 360 / (number of rows).
*
* The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
* at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
* i.e., deltaPhi = 180 / (number of columns - 1).
*/
private abstract static 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;
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.");
}
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.");
}
mCorrections = corrections;
mCorrectionUncertainties = correctionUncertainties;
mDeltaTheta = 360.0d / mNumRows;
mDeltaPhi = 180.0d / (mNumColumns - 1);
}
SphericalCorrections(Parcel in) {
int numRows = in.readInt();
int numColumns = in.readInt();
double[][] corrections =
new double[numRows][numColumns];
double[][] correctionUncertainties =
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]);
}
mNumRows = corrections.length;
mNumColumns = corrections[0].length;
mCorrections = corrections;
mCorrectionUncertainties = correctionUncertainties;
mDeltaTheta = 360.0d / mNumRows;
mDeltaPhi = 180.0d / (mNumColumns - 1);
}
private double getCorrectionAt(int row, int column) {
return mCorrections[row][column];
}
private double getCorrectionUncertaintyAt(int row, int column) {
return mCorrectionUncertainties[row][column];
}
@NonNull
private double[][] getRawCorrectionsArray() {
return mCorrections;
}
@NonNull
private double[][] getRawCorrectionUncertaintiesArray() {
return mCorrectionUncertainties;
}
private int getNumRows() {
return mNumRows;
}
private int getNumColumns() {
return mNumColumns;
}
/**
* The fixed theta angle separation between successive rows.
*/
private double getDeltaTheta() {
return mDeltaTheta;
}
/**
* The fixed phi angle separation between successive columns.
*/
private double getDeltaPhi() {
return mDeltaPhi;
}
@Override
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);
}
}
private String arrayToString(double[][] array) {
StringBuilder builder = new StringBuilder();
for (int row = 0; row < mNumRows; row++) {
builder.append("[ ");
for (int column = 0; column < mNumColumns - 1; column++) {
builder.append(array[row][column] + ", ");
}
builder.append(array[row][mNumColumns - 1] + " ]\n");
}
return builder.toString();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("DeltaTheta: " + mDeltaTheta + "\n");
builder.append("DeltaPhi: " + mDeltaPhi + "\n");
builder.append("CorrectionsArray:\n");
builder.append(arrayToString(mCorrections));
builder.append("CorrectionUncertaintiesArray:\n");
builder.append(arrayToString(mCorrectionUncertainties));
return builder.toString();
}
}
@VisibleForTesting
public GnssAntennaInfo(
double carrierFrequencyMHz,
@NonNull PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates,
@Nullable PhaseCenterVariationCorrections phaseCenterVariationCorrections,
@Nullable SignalGainCorrections signalGainCorrectionDbi) {
if (phaseCenterOffsetCoordinates == null) {
throw new IllegalArgumentException("Phase Center Offset Coordinates cannot be null.");
}
mCarrierFrequencyMHz = carrierFrequencyMHz;
mPhaseCenterOffsetCoordinates = phaseCenterOffsetCoordinates;
mPhaseCenterVariationCorrections = phaseCenterVariationCorrections;
mSignalGainCorrections = signalGainCorrectionDbi;
}
public double getCarrierFrequencyMHz() {
return mCarrierFrequencyMHz;
}
@NonNull
public PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates() {
return mPhaseCenterOffsetCoordinates;
}
@Nullable
public PhaseCenterVariationCorrections getPhaseCenterVariationCorrections() {
return mPhaseCenterVariationCorrections;
}
@Nullable
public SignalGainCorrections getSignalGainCorrections() {
return mSignalGainCorrections;
}
public static final @android.annotation.NonNull
Creator<GnssAntennaInfo> CREATOR = new Creator<GnssAntennaInfo>() {
@Override
public GnssAntennaInfo createFromParcel(Parcel in) {
double carrierFrequencyMHz = in.readDouble();
ClassLoader classLoader = getClass().getClassLoader();
PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates =
in.readParcelable(classLoader);
PhaseCenterVariationCorrections phaseCenterVariationCorrections =
in.readParcelable(classLoader);
SignalGainCorrections signalGainCorrections =
in.readParcelable(classLoader);
return new GnssAntennaInfo(carrierFrequencyMHz,
phaseCenterOffsetCoordinates,
phaseCenterVariationCorrections, signalGainCorrections);
}
@Override
public GnssAntennaInfo[] newArray(int size) {
return new GnssAntennaInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeDouble(mCarrierFrequencyMHz);
// Write Phase Center Offset
parcel.writeParcelable(mPhaseCenterOffsetCoordinates, flags);
// Write Phase Center Variation Corrections
parcel.writeParcelable(mPhaseCenterVariationCorrections, flags);
// Write Signal Gain Corrections
parcel.writeParcelable(mSignalGainCorrections, flags);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("[ GnssAntennaInfo:\n");
builder.append("CarrierFrequencyMHz: " + mCarrierFrequencyMHz + "\n");
builder.append(mPhaseCenterOffsetCoordinates.toString());
builder.append(mPhaseCenterVariationCorrections == null
? "PhaseCenterVariationCorrections: null\n"
: mPhaseCenterVariationCorrections.toString());
builder.append(mSignalGainCorrections == null
? "SignalGainCorrections: null\n"
: mSignalGainCorrections.toString());
builder.append("]");
return builder.toString();
}
}