Add GnssAntennaInfo framework APIs

Test: End to end test: run "atest GnssAntennaInfoRegistrationTest" on cuttlefish and watch "adb logcat | grep -i GnssAntennaInfo". Other tests:  atest GnssAntennaInfoTest, atest GnssAntennaInfoProviderTest, atest GnssManagerServiceTest, atest VtsHalGnssV2_1TargetTest, atest LocationManagerFineTest.
Bug:124556515
Change-Id: I70e4014dd3959b0570c35bd2aa8bb839ef167d70
This commit is contained in:
Sasha Kuznetsov
2020-01-16 14:02:53 -08:00
parent 0b58264796
commit dcbeb75fc1
16 changed files with 1689 additions and 5 deletions

View File

@@ -23465,6 +23465,69 @@ package android.location {
method public static boolean isPresent();
}
public final class GnssAntennaInfo implements android.os.Parcelable {
ctor public GnssAntennaInfo(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates, @Nullable android.location.GnssAntennaInfo.PhaseCenterVariationCorrections, @Nullable android.location.GnssAntennaInfo.SignalGainCorrections);
method public int describeContents();
method public double getCarrierFrequencyMHz();
method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates getPhaseCenterOffsetCoordinates();
method @Nullable public android.location.GnssAntennaInfo.PhaseCenterVariationCorrections getPhaseCenterVariationCorrections();
method @Nullable public android.location.GnssAntennaInfo.SignalGainCorrections getSignalGainCorrections();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
}
public abstract static class GnssAntennaInfo.Callback {
ctor public GnssAntennaInfo.Callback();
method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
method public void onStatusChanged(int);
field public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
field public static final int STATUS_READY = 1; // 0x1
}
public static final class GnssAntennaInfo.PhaseCenterOffsetCoordinates implements android.os.Parcelable {
ctor public GnssAntennaInfo.PhaseCenterOffsetCoordinates(double, double, double, double, double, double);
method public int describeContents();
method public double getXCoordMillimeters();
method public double getXCoordUncertaintyMillimeters();
method public double getYCoordMillimeters();
method public double getYCoordUncertaintyMillimeters();
method public double getZCoordMillimeters();
method public double getZCoordUncertaintyMillimeters();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffsetCoordinates> CREATOR;
}
public static final class GnssAntennaInfo.PhaseCenterVariationCorrections implements android.os.Parcelable {
ctor public GnssAntennaInfo.PhaseCenterVariationCorrections(@NonNull double[][], @NonNull double[][]);
method public int describeContents();
method public double getDeltaPhi();
method public double getDeltaTheta();
method public int getNumColumns();
method public int getNumRows();
method public double getPhaseCenterVariationCorrectionMillimetersAt(int, int);
method public double getPhaseCenterVariationCorrectionUncertaintyMillimetersAt(int, int);
method @NonNull public double[][] getRawCorrectionUncertaintiesArray();
method @NonNull public double[][] getRawCorrectionsArray();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterVariationCorrections> CREATOR;
}
public static final class GnssAntennaInfo.SignalGainCorrections implements android.os.Parcelable {
ctor public GnssAntennaInfo.SignalGainCorrections(@NonNull double[][], @NonNull double[][]);
method public int describeContents();
method public double getDeltaPhi();
method public double getDeltaTheta();
method public int getNumColumns();
method public int getNumRows();
method @NonNull public double[][] getRawCorrectionUncertaintiesArray();
method @NonNull public double[][] getRawCorrectionsArray();
method public double getSignalGainCorrectionDbiAt(int, int);
method public double getSignalGainCorrectionUncertaintyDbiAt(int, int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SignalGainCorrections> CREATOR;
}
public final class GnssClock implements android.os.Parcelable {
method public int describeContents();
method public double getBiasNanos();
@@ -23782,6 +23845,7 @@ package android.location {
method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
method public boolean isLocationEnabled();
method public boolean isProviderEnabled(@NonNull String);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Callback);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -23813,6 +23877,7 @@ package android.location {
method public void setTestProviderEnabled(@NonNull String, boolean);
method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
method public void unregisterAntennaInfoCallback(@NonNull android.location.GnssAntennaInfo.Callback);
method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);

View File

@@ -3806,6 +3806,7 @@ package android.location {
public final class GnssCapabilities {
method public boolean hasGeofencing();
method public boolean hasGnssAntennaInfo();
method public boolean hasLowPowerMode();
method public boolean hasMeasurementCorrections();
method public boolean hasMeasurementCorrectionsExcessPathLength();

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable GnssAntennaInfo;

View File

@@ -0,0 +1,654 @@
/*
* 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();
}
}

View File

@@ -82,6 +82,12 @@ public final class GnssCapabilities {
*/
public static final long MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1L << 8;
/**
* Bit mask indicating GNSS chipset supports GNSS antenna info.
* @hide
*/
public static final long ANTENNA_INFO = 1L << 9;
/** @hide */
public static final long INVALID_CAPABILITIES = -1;
@@ -165,6 +171,13 @@ public final class GnssCapabilities {
return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE);
}
/**
* Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise.
*/
public boolean hasGnssAntennaInfo() {
return hasCapability(ANTENNA_INFO);
}
@NonNull
@Override
public String toString() {
@@ -172,6 +185,7 @@ public final class GnssCapabilities {
if (hasLowPowerMode()) sb.append("LOW_POWER_MODE ");
if (hasSatelliteBlacklist()) sb.append("SATELLITE_BLACKLIST ");
if (hasGeofencing()) sb.append("GEOFENCING ");
if (hasGnssAntennaInfo()) sb.append("ANTENNA_INFO ");
if (hasMeasurements()) sb.append("MEASUREMENTS ");
if (hasNavMessages()) sb.append("NAV_MESSAGES ");
if (hasMeasurementCorrections()) sb.append("MEASUREMENT_CORRECTIONS ");

View File

@@ -0,0 +1,27 @@
/*
* 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> gnssAntennaInfo);
void onStatusChanged(in int status);
}

View File

@@ -23,6 +23,7 @@ import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
import android.location.IGnssNavigationMessageListener;
@@ -76,6 +77,10 @@ interface ILocationManager
long getGnssCapabilities(in String packageName);
void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
boolean addGnssAntennaInfoListener(in IGnssAntennaInfoListener listener,
String packageName, String featureId, String listenerIdentifier);
void removeGnssAntennaInfoListener(in IGnssAntennaInfoListener listener);
boolean addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener,
String packageName, String featureId, String listenerIdentifier);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);

View File

@@ -278,6 +278,8 @@ public class LocationManager {
new GnssMeasurementsListenerManager();
private final GnssNavigationMessageListenerManager mGnssNavigationMessageListenerTransport =
new GnssNavigationMessageListenerManager();
private final GnssAntennaInfoListenerManager mGnssAntennaInfoListenerManager =
new GnssAntennaInfoListenerManager();
/**
* @hide
@@ -2198,6 +2200,41 @@ public class LocationManager {
}
}
/**
* Registers a Gnss Antenna Info callback.
*
* @param executor the executor that the callback runs on.
* @param callback a {@link GnssAntennaInfo.Callback} object to register.
* @return {@code true} if the callback was added successfully, {@code false} otherwise.
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if callback is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean registerAntennaInfoCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull GnssAntennaInfo.Callback callback) {
try {
return mGnssAntennaInfoListenerManager.addListener(callback, executor);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Unregisters a GNSS Antenna Info callback.
*
* @param callback a {@link GnssAntennaInfo.Callback} object to remove.
*/
public void unregisterAntennaInfoCallback(@NonNull GnssAntennaInfo.Callback callback) {
try {
mGnssAntennaInfoListenerManager.removeListener(callback);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* No-op method to keep backward-compatibility.
*
@@ -2929,6 +2966,48 @@ public class LocationManager {
}
}
private class GnssAntennaInfoListenerManager extends
AbstractListenerManager<GnssAntennaInfo.Callback> {
@Nullable
private IGnssAntennaInfoListener mListenerTransport;
@Override
protected boolean registerService() throws RemoteException {
Preconditions.checkState(mListenerTransport == null);
GnssAntennaInfoListener transport = new GnssAntennaInfoListener();
if (mService.addGnssAntennaInfoListener(transport, mContext.getPackageName(),
mContext.getFeatureId(), "gnss antenna info callback")) {
mListenerTransport = transport;
return true;
} else {
return false;
}
}
@Override
protected void unregisterService() throws RemoteException {
Preconditions.checkState(mListenerTransport != null);
mService.removeGnssAntennaInfoListener(mListenerTransport);
mListenerTransport = null;
}
private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub {
@Override
public void onGnssAntennaInfoReceived(final List<GnssAntennaInfo> gnssAntennaInfos) {
execute((callback) -> callback.onGnssAntennaInfoReceived(gnssAntennaInfos));
}
@Override
public void onStatusChanged(int status) {
execute((listener) -> listener.onStatusChanged(status));
}
}
}
private class BatchedLocationCallbackManager extends
AbstractListenerManager<BatchedLocationCallback> {
@@ -2941,7 +3020,7 @@ public class LocationManager {
BatchedLocationCallback transport = new BatchedLocationCallback();
if (mService.addGnssBatchingCallback(transport, mContext.getPackageName(),
mContext.getFeatureId(), "batched location callback")) {
mContext.getFeatureId(), "batched location callback")) {
mListenerTransport = transport;
return true;
} else {

View File

@@ -43,6 +43,7 @@ import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
@@ -2317,6 +2318,22 @@ public class LocationManagerService extends ILocationManager.Stub {
packageName);
}
@Override
public boolean addGnssAntennaInfoListener(IGnssAntennaInfoListener listener,
String packageName, String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
return mGnssManagerService != null && mGnssManagerService.addGnssAntennaInfoListener(
listener, packageName, featureId, listenerIdentifier);
}
@Override
public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
if (mGnssManagerService != null) {
mGnssManagerService.removeGnssAntennaInfoListener(listener);
}
}
@Override
public boolean addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
String packageName, String featureId, String listenerIdentifier) {

View File

@@ -0,0 +1,178 @@
/*
* 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 com.android.server.location;
import android.content.Context;
import android.location.GnssAntennaInfo;
import android.location.IGnssAntennaInfoListener;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
/**
* An base implementation for GNSS antenna info provider. It abstracts out the responsibility of
* handling listeners, while still allowing technology specific implementations to be built.
*
* @hide
*/
public abstract class GnssAntennaInfoProvider
extends RemoteListenerHelper<IGnssAntennaInfoListener> {
private static final String TAG = "GnssAntennaInfoProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final GnssAntennaInfoProviderNative mNative;
private boolean mIsListeningStarted;
protected GnssAntennaInfoProvider(Context context, Handler handler) {
this(context, handler, new GnssAntennaInfoProviderNative());
}
@VisibleForTesting
public GnssAntennaInfoProvider(
Context context, Handler handler, GnssAntennaInfoProviderNative aNative) {
super(context, handler, TAG);
mNative = aNative;
}
void resumeIfStarted() {
if (DEBUG) {
Log.d(TAG, "resumeIfStarted");
}
if (mIsListeningStarted) {
mNative.startAntennaInfoListening();
}
}
@Override
public boolean isAvailableInPlatform() {
return mNative.isAntennaInfoSupported();
}
@Override
protected int registerWithService() {
boolean started = mNative.startAntennaInfoListening();
if (started) {
mIsListeningStarted = true;
return RemoteListenerHelper.RESULT_SUCCESS;
}
return RemoteListenerHelper.RESULT_INTERNAL_ERROR;
}
@Override
protected void unregisterFromService() {
boolean stopped = mNative.stopAntennaInfoListening();
if (stopped) {
mIsListeningStarted = false;
}
}
/** Handle GNSS capabilities update from the GNSS HAL implementation. */
public void onCapabilitiesUpdated(boolean isAntennaInfoSupported) {
setSupported(isAntennaInfoSupported);
updateResult();
}
/** Handle GNSS enabled changes.*/
public void onGpsEnabledChanged() {
tryUpdateRegistrationWithService();
updateResult();
}
@Override
protected ListenerOperation<IGnssAntennaInfoListener> getHandlerOperation(int result) {
int status;
switch (result) {
case RESULT_SUCCESS:
status = GnssAntennaInfo.Callback.STATUS_READY;
break;
case RESULT_NOT_AVAILABLE:
case RESULT_NOT_SUPPORTED:
case RESULT_INTERNAL_ERROR:
status = GnssAntennaInfo.Callback.STATUS_NOT_SUPPORTED;
break;
case RESULT_GPS_LOCATION_DISABLED:
status = GnssAntennaInfo.Callback.STATUS_LOCATION_DISABLED;
break;
case RESULT_UNKNOWN:
return null;
default:
Log.v(TAG, "Unhandled addListener result: " + result);
return null;
}
return new StatusChangedOperation(status);
}
private static class StatusChangedOperation
implements ListenerOperation<IGnssAntennaInfoListener> {
private final int mStatus;
StatusChangedOperation(int status) {
mStatus = status;
}
@Override
public void execute(IGnssAntennaInfoListener listener,
CallerIdentity callerIdentity) throws RemoteException {
listener.onStatusChanged(mStatus);
}
}
/** Handle Gnss Antenna Info report. */
public void onGnssAntennaInfoAvailable(final List<GnssAntennaInfo> gnssAntennaInfos) {
foreach((IGnssAntennaInfoListener listener, CallerIdentity callerIdentity) -> {
if (!hasPermission(mContext, callerIdentity)) {
logPermissionDisabledEventNotReported(
TAG, callerIdentity.mPackageName, "GNSS antenna info");
return;
}
listener.onGnssAntennaInfoReceived(gnssAntennaInfos);
});
}
/**
* Wrapper class for native methods. This is mocked for testing.
*/
@VisibleForTesting
public static class GnssAntennaInfoProviderNative {
public boolean isAntennaInfoSupported() {
return native_is_antenna_info_supported();
}
/** Start antenna info listening. */
public boolean startAntennaInfoListening() {
return native_start_antenna_info_listening();
}
/** Stop antenna info listening. */
public boolean stopAntennaInfoListening() {
return native_stop_antenna_info_listening();
}
}
private static native boolean native_is_antenna_info_supported();
private static native boolean native_start_antenna_info_listening();
private static native boolean native_stop_antenna_info_listening();
}

View File

@@ -77,6 +77,9 @@ public class GnssCapabilitiesProvider {
if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES)) {
gnssCapabilities |= GnssCapabilities.NAV_MESSAGES;
}
if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_ANTENNA_INFO)) {
gnssCapabilities |= GnssCapabilities.ANTENNA_INFO;
}
synchronized (this) {
mGnssCapabilities &= ~GNSS_CAPABILITIES_TOP_HAL;

View File

@@ -29,6 +29,7 @@ import android.hardware.location.GeofenceHardware;
import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
import android.location.FusedBatchOptions;
import android.location.GnssAntennaInfo;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssStatus;
@@ -182,6 +183,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
public static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400;
public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800;
// The AGPS SUPL mode
private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -397,6 +399,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private final GnssStatusListenerHelper mGnssStatusListenerHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
@@ -469,6 +472,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return mGnssMeasurementCorrectionsProvider;
}
public GnssAntennaInfoProvider getGnssAntennaInfoProvider() {
return mGnssAntennaInfoProvider;
}
public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
return mGnssNavigationMessageProvider;
}
@@ -693,6 +700,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(mContext, mHandler) {
@Override
protected boolean isGpsEnabled() {
return GnssLocationProvider.this.isGpsEnabled();
}
};
mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
@Override
protected boolean isGpsEnabled() {
@@ -992,6 +1006,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mGnssMeasurementsProvider.onGpsEnabledChanged();
mGnssNavigationMessageProvider.onGpsEnabledChanged();
mGnssAntennaInfoProvider.onGpsEnabledChanged();
mGnssBatchingProvider.enable();
if (mGnssVisibilityControl != null) {
mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true);
@@ -1018,6 +1033,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// do this before releasing wakelock
native_cleanup();
mGnssAntennaInfoProvider.onGpsEnabledChanged();
mGnssMeasurementsProvider.onGpsEnabledChanged();
mGnssNavigationMessageProvider.onGpsEnabledChanged();
}
@@ -1562,6 +1578,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
@NativeEntryPoint
private void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
mHandler.post(() -> mGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(antennaInfos));
}
@NativeEntryPoint
private void reportNavigationMessage(GnssNavigationMessage event) {
if (!mItarSpeedLimitExceeded) {
@@ -1585,6 +1606,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mGnssNavigationMessageProvider.onCapabilitiesUpdated(
hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
restartRequests();
mGnssAntennaInfoProvider.onCapabilitiesUpdated(
hasCapability(GPS_CAPABILITY_ANTENNA_INFO));
mGnssCapabilitiesProvider.setTopHalCapabilities(mTopHalCapabilities);
});
@@ -1606,6 +1629,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
Log.i(TAG, "restartRequests");
restartLocationRequest();
mGnssAntennaInfoProvider.resumeIfStarted();
mGnssMeasurementsProvider.resumeIfStarted();
mGnssNavigationMessageProvider.resumeIfStarted();
mGnssBatchingProvider.resumeIfStarted();
@@ -2198,6 +2222,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
s.append(" ago)").append('\n');
s.append("mFixInterval=").append(mFixInterval).append('\n');
s.append("mLowPowerMode=").append(mLowPowerMode).append('\n');
s.append("mGnssAntennaInfoProvider.isRegistered()=")
.append(mGnssAntennaInfoProvider.isRegistered()).append('\n');
s.append("mGnssMeasurementsProvider.isRegistered()=")
.append(mGnssMeasurementsProvider.isRegistered()).append('\n');
s.append("mGnssNavigationMessageProvider.isRegistered()=")

View File

@@ -26,6 +26,7 @@ import android.content.Context;
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
@@ -51,6 +52,7 @@ import com.android.server.LocationManagerServiceUtils.LinkedListener;
import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
import com.android.server.location.AppForegroundHelper;
import com.android.server.location.CallerIdentity;
import com.android.server.location.GnssAntennaInfoProvider;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssCapabilitiesProvider;
import com.android.server.location.GnssLocationProvider;
@@ -87,6 +89,7 @@ public class GnssManagerService {
private final GnssStatusListenerHelper mGnssStatusProvider;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
@@ -99,6 +102,11 @@ public class GnssManagerService {
private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
mGnssMeasurementsListeners = new ArrayMap<>();
@GuardedBy("mGnssAntennaInfoListeners")
private final ArrayMap<IBinder,
LinkedListener<IGnssAntennaInfoListener>>
mGnssAntennaInfoListeners = new ArrayMap<>();
@GuardedBy("mGnssNavigationMessageListeners")
private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
mGnssNavigationMessageListeners = new ArrayMap<>();
@@ -147,6 +155,7 @@ public class GnssManagerService {
mGnssLocationProvider = gnssLocationProvider;
mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
mGnssAntennaInfoProvider = mGnssLocationProvider.getGnssAntennaInfoProvider();
mGnssMeasurementCorrectionsProvider =
mGnssLocationProvider.getGnssMeasurementCorrectionsProvider();
mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider();
@@ -354,6 +363,14 @@ public class GnssManagerService {
uid,
foreground);
}
synchronized (mGnssAntennaInfoListeners) {
updateListenersOnForegroundChangedLocked(
mGnssAntennaInfoListeners,
mGnssAntennaInfoProvider,
IGnssAntennaInfoListener.Stub::asInterface,
uid,
foreground);
}
}
private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
@@ -530,6 +547,40 @@ public class GnssManagerService {
}
}
/**
* Adds a GNSS Antenna Info listener.
*
* @param listener called when GNSS antenna info is received
* @param packageName name of requesting package
* @return true if listener is successfully added, false otherwise
*/
public boolean addGnssAntennaInfoListener(
IGnssAntennaInfoListener listener, String packageName,
@Nullable String featureId, @NonNull String listenerIdentifier) {
synchronized (mGnssAntennaInfoListeners) {
return addGnssDataListenerLocked(
listener,
packageName,
featureId,
listenerIdentifier,
mGnssAntennaInfoProvider,
mGnssAntennaInfoListeners,
this::removeGnssAntennaInfoListener);
}
}
/**
* Removes a GNSS Antenna Info listener.
*
* @param listener called when GNSS antenna info is received
*/
public void removeGnssAntennaInfoListener(IGnssAntennaInfoListener listener) {
synchronized (mGnssAntennaInfoListeners) {
removeGnssDataListenerLocked(
listener, mGnssAntennaInfoProvider, mGnssAntennaInfoListeners);
}
}
/**
* Adds a GNSS navigation message listener.
*/

View File

@@ -26,17 +26,18 @@
#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
#include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
#include "hardware_legacy/power.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "hardware_legacy/power.h"
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include <arpa/inet.h>
#include <cinttypes>
@@ -54,6 +55,12 @@ static jclass class_location;
static jclass class_gnssNavigationMessage;
static jclass class_gnssClock;
static jclass class_gnssConfiguration_halInterfaceVersion;
static jclass class_gnssAntennaInfo;
static jclass class_phaseCenterOffsetCoordinates;
static jclass class_phaseCenterVariationCorrections;
static jclass class_signalGainCorrections;
static jclass class_arrayList;
static jclass class_doubleArray;
static jobject mCallbacksObj = nullptr;
@@ -78,6 +85,7 @@ static jmethodID method_reportGeofenceRemoveStatus;
static jmethodID method_reportGeofencePauseStatus;
static jmethodID method_reportGeofenceResumeStatus;
static jmethodID method_reportMeasurementData;
static jmethodID method_reportAntennaInfo;
static jmethodID method_reportNavigationMessages;
static jmethodID method_reportLocationBatch;
static jmethodID method_reportGnssServiceDied;
@@ -114,6 +122,12 @@ static jmethodID method_gnssNavigationMessageCtor;
static jmethodID method_gnssClockCtor;
static jmethodID method_gnssMeasurementCtor;
static jmethodID method_halInterfaceVersionCtor;
static jmethodID method_gnssAntennaInfoCtor;
static jmethodID method_phaseCenterOffsetCoordinatesCtor;
static jmethodID method_phaseCenterVariationCorrectionsCtor;
static jmethodID method_signalGainCorrectionsCtor;
static jmethodID method_arrayListCtor;
static jmethodID method_arrayListAdd;
/*
* Save a pointer to JavaVm to attach/detach threads executing
@@ -171,6 +185,8 @@ using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguratio
using IGnssConfiguration_V2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
using IGnssAntennaInfo = android::hardware::gnss::V2_1::IGnssAntennaInfo;
using IGnssAntennaInfoCallback = android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
@@ -241,6 +257,7 @@ sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
sp<IMeasurementCorrections_V1_0> gnssCorrectionsIface_V1_0 = nullptr;
sp<IMeasurementCorrections_V1_1> gnssCorrectionsIface_V1_1 = nullptr;
sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
sp<IGnssAntennaInfo> gnssAntennaInfoIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -1050,6 +1067,195 @@ Return<void> GnssNavigationMessageCallback::gnssNavigationMessageCb(
return Void();
}
/*
* GnssAntennaInfoCallback implements the callback methods required for the
* GnssAntennaInfo interface.
*/
struct GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
// Methods from V2_1::GnssAntennaInfoCallback follow.
Return<void> gnssAntennaInfoCb(
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
private:
jobject translateAllGnssAntennaInfos(
JNIEnv* env,
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
jobject translateSingleGnssAntennaInfo(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
jobject translatePhaseCenterOffsetCoordinates(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
jobject translatePhaseCenterVariationCorrections(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
jobject translateSignalGainCorrections(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo);
jobjectArray translate2dDoubleArray(JNIEnv* env,
const hidl_vec<IGnssAntennaInfoCallback::Row>& array);
void translateAndReportGnssAntennaInfo(
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
void reportAntennaInfo(JNIEnv* env, const jobject antennaInfosArray);
};
Return<void> GnssAntennaInfoCallback::gnssAntennaInfoCb(
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
translateAndReportGnssAntennaInfo(gnssAntennaInfos);
return Void();
}
jobjectArray GnssAntennaInfoCallback::translate2dDoubleArray(
JNIEnv* env, const hidl_vec<IGnssAntennaInfoCallback::Row>& array) {
jsize numRows = array.size();
if (numRows == 0) {
// Empty array
return NULL;
}
jsize numCols = array[0].row.size();
if (numCols <= 1) {
// phi angle separation is computed as 180.0 / (numColumns - 1), so can't be < 2.
return NULL;
}
// Allocate array of double arrays
jobjectArray returnArray = env->NewObjectArray(numRows, class_doubleArray, NULL);
// Create each double array
for (uint8_t i = 0; i < numRows; i++) {
jdoubleArray doubleArray = env->NewDoubleArray(numCols);
env->SetDoubleArrayRegion(doubleArray, (jsize)0, numCols, array[i].row.data());
env->SetObjectArrayElement(returnArray, (jsize)i, doubleArray);
env->DeleteLocalRef(doubleArray);
}
return returnArray;
}
jobject GnssAntennaInfoCallback::translateAllGnssAntennaInfos(
JNIEnv* env, const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
jobject arrayList = env->NewObject(class_arrayList,
method_arrayListCtor); // Create new ArrayList instance
for (auto gnssAntennaInfo : gnssAntennaInfos) {
jobject gnssAntennaInfoObject = translateSingleGnssAntennaInfo(env, gnssAntennaInfo);
env->CallBooleanMethod(arrayList, method_arrayListAdd,
gnssAntennaInfoObject); // Add the antennaInfo to the ArrayList
// Delete Local Refs
env->DeleteLocalRef(gnssAntennaInfoObject);
}
return arrayList;
}
jobject GnssAntennaInfoCallback::translatePhaseCenterOffsetCoordinates(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
jobject phaseCenterOffsetCoordinates =
env->NewObject(class_phaseCenterOffsetCoordinates,
method_phaseCenterOffsetCoordinatesCtor,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.x,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.xUncertainty,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.y,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.yUncertainty,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z,
gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty);
return phaseCenterOffsetCoordinates;
}
jobject GnssAntennaInfoCallback::translatePhaseCenterVariationCorrections(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
if (gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters == NULL ||
gnssAntennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters == NULL) {
return NULL;
}
jobjectArray phaseCenterVariationCorrectionsArray =
translate2dDoubleArray(env, gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters);
jobjectArray phaseCenterVariationCorrectionsUncertaintiesArray =
translate2dDoubleArray(env,
gnssAntennaInfo
.phaseCenterVariationCorrectionUncertaintyMillimeters);
if (phaseCenterVariationCorrectionsArray == NULL ||
phaseCenterVariationCorrectionsUncertaintiesArray == NULL) {
return NULL;
}
jobject phaseCenterVariationCorrections =
env->NewObject(class_phaseCenterVariationCorrections,
method_phaseCenterVariationCorrectionsCtor,
phaseCenterVariationCorrectionsArray,
phaseCenterVariationCorrectionsUncertaintiesArray);
env->DeleteLocalRef(phaseCenterVariationCorrectionsArray);
env->DeleteLocalRef(phaseCenterVariationCorrectionsUncertaintiesArray);
return phaseCenterVariationCorrections;
}
jobject GnssAntennaInfoCallback::translateSignalGainCorrections(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
if (gnssAntennaInfo.signalGainCorrectionDbi == NULL ||
gnssAntennaInfo.signalGainCorrectionUncertaintyDbi == NULL) {
return NULL;
}
jobjectArray signalGainCorrectionsArray =
translate2dDoubleArray(env, gnssAntennaInfo.signalGainCorrectionDbi);
jobjectArray signalGainCorrectionsUncertaintiesArray =
translate2dDoubleArray(env, gnssAntennaInfo.signalGainCorrectionUncertaintyDbi);
if (signalGainCorrectionsArray == NULL || signalGainCorrectionsUncertaintiesArray == NULL) {
return NULL;
}
jobject signalGainCorrections =
env->NewObject(class_signalGainCorrections, method_signalGainCorrectionsCtor,
signalGainCorrectionsArray, signalGainCorrectionsUncertaintiesArray);
env->DeleteLocalRef(signalGainCorrectionsArray);
env->DeleteLocalRef(signalGainCorrectionsUncertaintiesArray);
return signalGainCorrections;
}
jobject GnssAntennaInfoCallback::translateSingleGnssAntennaInfo(
JNIEnv* env, const IGnssAntennaInfoCallback::GnssAntennaInfo& gnssAntennaInfo) {
jobject phaseCenterOffsetCoordinates =
translatePhaseCenterOffsetCoordinates(env, gnssAntennaInfo);
// Nullable
jobject phaseCenterVariationCorrections =
translatePhaseCenterVariationCorrections(env, gnssAntennaInfo);
// Nullable
jobject signalGainCorrections = translateSignalGainCorrections(env, gnssAntennaInfo);
jobject gnssAntennaInfoObject =
env->NewObject(class_gnssAntennaInfo, method_gnssAntennaInfoCtor,
gnssAntennaInfo.carrierFrequencyMHz, phaseCenterOffsetCoordinates,
phaseCenterVariationCorrections, signalGainCorrections);
// Delete Local Refs
env->DeleteLocalRef(phaseCenterOffsetCoordinates);
env->DeleteLocalRef(phaseCenterVariationCorrections);
env->DeleteLocalRef(signalGainCorrections);
return gnssAntennaInfoObject;
}
void GnssAntennaInfoCallback::translateAndReportGnssAntennaInfo(
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
JNIEnv* env = getJniEnv();
jobject arrayList = translateAllGnssAntennaInfos(env, gnssAntennaInfos);
reportAntennaInfo(env, arrayList);
env->DeleteLocalRef(arrayList);
}
void GnssAntennaInfoCallback::reportAntennaInfo(JNIEnv* env, const jobject antennaInfosArray) {
env->CallVoidMethod(mCallbacksObj, method_reportAntennaInfo, antennaInfosArray);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
/*
* GnssMeasurementCallback implements the callback methods required for the
* GnssMeasurement interface.
@@ -1708,6 +1914,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
"(II)V");
method_reportGeofencePauseStatus = env->GetMethodID(clazz, "reportGeofencePauseStatus",
"(II)V");
method_reportAntennaInfo = env->GetMethodID(clazz, "reportAntennaInfo", "(Ljava/util/List;)V");
method_reportMeasurementData = env->GetMethodID(
clazz,
"reportMeasurementData",
@@ -1791,6 +1998,36 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
class_gnssMeasurement = (jclass) env->NewGlobalRef(gnssMeasurementClass);
method_gnssMeasurementCtor = env->GetMethodID(class_gnssMeasurement, "<init>", "()V");
jclass gnssAntennaInfoClass = env->FindClass("android/location/GnssAntennaInfo");
class_gnssAntennaInfo = (jclass)env->NewGlobalRef(gnssAntennaInfoClass);
method_gnssAntennaInfoCtor =
env->GetMethodID(class_gnssAntennaInfo, "<init>",
"(D"
"Landroid/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates;"
"Landroid/location/GnssAntennaInfo$PhaseCenterVariationCorrections;"
"Landroid/location/GnssAntennaInfo$SignalGainCorrections;"
")V");
jclass phaseCenterOffsetCoordinatesClass =
env->FindClass("android/location/GnssAntennaInfo$PhaseCenterOffsetCoordinates");
class_phaseCenterOffsetCoordinates =
(jclass)env->NewGlobalRef(phaseCenterOffsetCoordinatesClass);
method_phaseCenterOffsetCoordinatesCtor =
env->GetMethodID(class_phaseCenterOffsetCoordinates, "<init>", "(DDDDDD)V");
jclass phaseCenterVariationCorrectionsClass =
env->FindClass("android/location/GnssAntennaInfo$PhaseCenterVariationCorrections");
class_phaseCenterVariationCorrections =
(jclass)env->NewGlobalRef(phaseCenterVariationCorrectionsClass);
method_phaseCenterVariationCorrectionsCtor =
env->GetMethodID(class_phaseCenterVariationCorrections, "<init>", "([[D[[D)V");
jclass signalGainCorrectionsClass =
env->FindClass("android/location/GnssAntennaInfo$SignalGainCorrections");
class_signalGainCorrections = (jclass)env->NewGlobalRef(signalGainCorrectionsClass);
method_signalGainCorrectionsCtor =
env->GetMethodID(class_signalGainCorrections, "<init>", "([[D[[D)V");
jclass locationClass = env->FindClass("android/location/Location");
class_location = (jclass) env->NewGlobalRef(locationClass);
method_locationCtor = env->GetMethodID(class_location, "<init>", "(Ljava/lang/String;)V");
@@ -1809,6 +2046,14 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
(jclass) env->NewGlobalRef(gnssConfiguration_halInterfaceVersionClass);
method_halInterfaceVersionCtor =
env->GetMethodID(class_gnssConfiguration_halInterfaceVersion, "<init>", "(II)V");
jclass arrayListClass = env->FindClass("java/util/ArrayList");
class_arrayList = (jclass)env->NewGlobalRef(arrayListClass);
method_arrayListCtor = env->GetMethodID(class_arrayList, "<init>", "()V");
method_arrayListAdd = env->GetMethodID(class_arrayList, "add", "(Ljava/lang/Object;)Z");
jclass doubleArrayClass = env->FindClass("[D");
class_doubleArray = (jclass)env->NewGlobalRef(doubleArrayClass);
}
/* Initialization needed at system boot and whenever GNSS service dies. */
@@ -1934,6 +2179,15 @@ static void android_location_GnssLocationProvider_init_once(JNIEnv* env, jclass
}
}
if (gnssHal_V2_1 != nullptr) {
auto gnssAntennaInfo = gnssHal_V2_1->getExtensionGnssAntennaInfo();
if (!gnssAntennaInfo.isOk()) {
ALOGD("Unable to get a handle to GnssAntennaInfo");
} else {
gnssAntennaInfoIface = gnssAntennaInfo;
}
}
if (gnssHal_V2_1 != nullptr) {
auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
if (!gnssCorrections.isOk()) {
@@ -2725,6 +2979,52 @@ static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /*
return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
}
static jboolean android_location_GnssAntennaInfoProvider_is_antenna_info_supported(JNIEnv* env,
jclass clazz) {
if (gnssAntennaInfoIface != nullptr) {
return JNI_TRUE;
}
return JNI_FALSE;
}
static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_listening(
JNIEnv* /* env */, jobject /* obj */) {
if (gnssAntennaInfoIface == nullptr) {
ALOGE("%s: IGnssAntennaInfo interface not available.", __func__);
return JNI_FALSE;
}
sp<GnssAntennaInfoCallback> cbIface = new GnssAntennaInfoCallback();
auto result = gnssAntennaInfoIface->setCallback(cbIface);
if (!checkHidlReturn(result, "IGnssAntennaInfo setCallback() failed.")) {
return JNI_FALSE;
}
IGnssAntennaInfo::GnssAntennaInfoStatus initRet = result;
if (initRet != IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS) {
ALOGE("An error has been found on GnssAntennaInfoInterface::init, status=%d",
static_cast<int32_t>(initRet));
return JNI_FALSE;
} else {
ALOGD("gnss antenna info has been enabled");
}
return JNI_TRUE;
}
static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_listening(
JNIEnv* /* env */, jobject /* obj */) {
if (gnssAntennaInfoIface == nullptr) {
ALOGE("%s: IGnssAntennaInfo interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssAntennaInfoIface->close();
return checkHidlReturn(result, "IGnssAntennaInfo close() failed.");
}
static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported(
JNIEnv* env, jclass clazz) {
if (gnssMeasurementIface != nullptr) {
@@ -3286,6 +3586,19 @@ static const JNINativeMethod sMethodsBatching[] = {
reinterpret_cast<void *>(android_location_GnssBatchingProvider_cleanup_batching)},
};
static const JNINativeMethod sAntennaInfoMethods[] = {
/* name, signature, funcPtr */
{"native_is_antenna_info_supported", "()Z",
reinterpret_cast<void*>(
android_location_GnssAntennaInfoProvider_is_antenna_info_supported)},
{"native_start_antenna_info_listening", "()Z",
reinterpret_cast<void*>(
android_location_GnssAntennaInfoProvider_start_antenna_info_listening)},
{"native_stop_antenna_info_listening", "()Z",
reinterpret_cast<void*>(
android_location_GnssAntennaInfoProvider_stop_antenna_info_listening)},
};
static const JNINativeMethod sGeofenceMethods[] = {
/* name, signature, funcPtr */
{"native_is_geofence_supported",
@@ -3407,6 +3720,8 @@ static const JNINativeMethod sVisibilityControlMethods[] = {
};
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
jniRegisterNativeMethods(env, "com/android/server/location/GnssAntennaInfoProvider",
sAntennaInfoMethods, NELEM(sAntennaInfoMethods));
jniRegisterNativeMethods(
env,
"com/android/server/location/GnssBatchingProvider",

View File

@@ -0,0 +1,94 @@
/*
* 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 com.android.server.location;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/**
* Unit tests for {@link GnssAntennaInfoProvider}.
*/
@RunWith(RobolectricTestRunner.class)
@Presubmit
public class GnssAntennaInfoProviderTest {
@Mock
private GnssAntennaInfoProvider.GnssAntennaInfoProviderNative mMockNative;
private GnssAntennaInfoProvider mTestProvider;
/** Setup. */
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mMockNative.startAntennaInfoListening()).thenReturn(true);
when(mMockNative.stopAntennaInfoListening()).thenReturn(true);
mTestProvider = new GnssAntennaInfoProvider(RuntimeEnvironment.application,
new Handler(Looper.myLooper()), mMockNative) {
@Override
public boolean isGpsEnabled() {
return true;
}
};
}
/**
* Test that registerWithService calls the native startAntennaInfoListening method.
*/
@Test
public void register_nativeStarted() {
mTestProvider.registerWithService();
verify(mMockNative, times(1)).startAntennaInfoListening();
}
/**
* Test that unregisterFromService calls the native stopAntennaInfoListening method.
*/
@Test
public void unregister_nativeStopped() {
mTestProvider.registerWithService();
mTestProvider.unregisterFromService();
verify(mMockNative, times(1)).stopAntennaInfoListening();
}
/**
* Test that GnssAntennaInfoProvider.isAntennaInfoSupported() returns the result of the
* native isAntennaInfoSupported method.
*/
@Test
public void isSupported_nativeIsSupported() {
when(mMockNative.isAntennaInfoSupported()).thenReturn(true);
assertThat(mTestProvider.isAvailableInPlatform()).isTrue();
when(mMockNative.isAntennaInfoSupported()).thenReturn(false);
assertThat(mTestProvider.isAvailableInPlatform()).isFalse();
}
}

View File

@@ -35,12 +35,14 @@ import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.GnssAntennaInfo;
import android.location.GnssClock;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssSingleSatCorrection;
import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
@@ -55,6 +57,8 @@ import android.os.RemoteException;
import com.android.server.LocalServices;
import com.android.server.location.AppForegroundHelper;
import com.android.server.location.GnssAntennaInfoProvider;
import com.android.server.location.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssCapabilitiesProvider;
import com.android.server.location.GnssLocationProvider;
@@ -101,6 +105,7 @@ public class GnssManagerServiceTest {
private GnssMeasurementsProvider mTestGnssMeasurementsProvider;
private GnssStatusListenerHelper mTestGnssStatusProvider;
private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider;
private GnssAntennaInfoProvider mTestGnssAntennaInfoProvider;
// Managers and services
@Mock
@@ -151,6 +156,8 @@ public class GnssManagerServiceTest {
mMockContext, mMockHandler);
mTestGnssNavigationMessageProvider = createGnssNavigationMessageProvider(
mMockContext, mMockHandler);
mTestGnssAntennaInfoProvider = createGnssAntennaInfoProvider(
mMockContext, mMockHandler);
// Setup GnssLocationProvider to return providers
when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn(
@@ -169,6 +176,8 @@ public class GnssManagerServiceTest {
mTestGnssNavigationMessageProvider);
when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn(
mNetInitiatedListener);
when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn(
mTestGnssAntennaInfoProvider);
// Setup GnssBatching provider
when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
@@ -204,6 +213,12 @@ public class GnssManagerServiceTest {
return mockListener;
}
private IGnssAntennaInfoListener createMockGnssAntennaInfoListener() {
IGnssAntennaInfoListener mockListener = mock(IGnssAntennaInfoListener.class);
overrideAsBinder(mockListener);
return mockListener;
}
private IBatchedLocationCallback createMockBatchedLocationCallback() {
IBatchedLocationCallback mockedCallback = mock(IBatchedLocationCallback.class);
overrideAsBinder(mockedCallback);
@@ -224,6 +239,39 @@ public class GnssManagerServiceTest {
Arrays.asList(gnssSingleSatCorrection)).build();
}
private static List<GnssAntennaInfo> createDummyGnssAntennaInfos() {
double carrierFrequencyMHz = 13758.0;
GnssAntennaInfo.PhaseCenterOffsetCoordinates phaseCenterOffsetCoordinates = new
GnssAntennaInfo.PhaseCenterOffsetCoordinates(
4.3d,
1.4d,
2.10d,
2.1d,
3.12d,
0.5d);
double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10];
double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10];
GnssAntennaInfo.PhaseCenterVariationCorrections
phaseCenterVariationCorrections =
new GnssAntennaInfo.PhaseCenterVariationCorrections(
phaseCenterVariationCorrectionsMillimeters,
phaseCenterVariationCorrectionsUncertaintyMillimeters);
double[][] signalGainCorrectionsDbi = new double[10][10];
double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10];
GnssAntennaInfo.SignalGainCorrections signalGainCorrections = new
GnssAntennaInfo.SignalGainCorrections(
signalGainCorrectionsDbi,
signalGainCorrectionsUncertaintyDbi);
List<GnssAntennaInfo> gnssAntennaInfos = new ArrayList();
gnssAntennaInfos.add(new GnssAntennaInfo(carrierFrequencyMHz, phaseCenterOffsetCoordinates,
phaseCenterVariationCorrections, signalGainCorrections));
return gnssAntennaInfos;
}
private void enableLocationPermissions() {
Mockito.doThrow(new SecurityException()).when(
mMockContext).enforceCallingPermission(
@@ -298,6 +346,18 @@ public class GnssManagerServiceTest {
};
}
private GnssAntennaInfoProvider createGnssAntennaInfoProvider(Context context,
Handler handler) {
GnssAntennaInfoProviderNative mockGnssAntenaInfoProviderNative = mock(
GnssAntennaInfoProviderNative.class);
return new GnssAntennaInfoProvider(context, handler, mockGnssAntenaInfoProviderNative) {
@Override
protected boolean isGpsEnabled() {
return true;
}
};
}
@Test
public void getGnssYearOfHardwareTest() {
final int gnssYearOfHardware = 2012;
@@ -661,6 +721,82 @@ public class GnssManagerServiceTest {
gnssMeasurementsEvent);
}
@Test
public void addGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException {
IGnssAntennaInfoListener mockGnssAntennaInfoListener =
createMockGnssAntennaInfoListener();
List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
disableLocationPermissions();
assertThrows(SecurityException.class,
() -> mGnssManagerService.addGnssAntennaInfoListener(
mockGnssAntennaInfoListener,
"com.android.server", "abcd123", "TestGnssAntennaInfoListener"));
mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
verify(mockGnssAntennaInfoListener, times(0))
.onGnssAntennaInfoReceived(gnssAntennaInfos);
}
@Test
public void addGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException {
IGnssAntennaInfoListener mockGnssAntennaInfoListener =
createMockGnssAntennaInfoListener();
List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
enableLocationPermissions();
assertThat(mGnssManagerService.addGnssAntennaInfoListener(mockGnssAntennaInfoListener,
"com.android.server", "abcd123", "TestGnssAntennaInfoListener")).isEqualTo(true);
mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
verify(mockGnssAntennaInfoListener, times(1))
.onGnssAntennaInfoReceived(gnssAntennaInfos);
}
@Test
public void removeGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException {
IGnssAntennaInfoListener mockGnssAntennaInfoListener =
createMockGnssAntennaInfoListener();
List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
enableLocationPermissions();
mGnssManagerService.addGnssAntennaInfoListener(
mockGnssAntennaInfoListener,
"com.android.server", "abcd123", "TestGnssAntennaInfoListener");
disableLocationPermissions();
mGnssManagerService.removeGnssAntennaInfoListener(
mockGnssAntennaInfoListener);
mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
verify(mockGnssAntennaInfoListener, times(0)).onGnssAntennaInfoReceived(
gnssAntennaInfos);
}
@Test
public void removeGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException {
IGnssAntennaInfoListener mockGnssAntennaInfoListener =
createMockGnssAntennaInfoListener();
List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
enableLocationPermissions();
mGnssManagerService.addGnssAntennaInfoListener(
mockGnssAntennaInfoListener,
"com.android.server", "abcd123", "TestGnssAntennaInfoListener");
mGnssManagerService.removeGnssAntennaInfoListener(
mockGnssAntennaInfoListener);
mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
verify(mockGnssAntennaInfoListener, times(0)).onGnssAntennaInfoReceived(
gnssAntennaInfos);
}
@Test
public void addGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException {
IGnssNavigationMessageListener mockGnssNavigationMessageListener =