• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.location;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 
29 /**
30  * A class that contains information about a GNSS antenna. GNSS antenna characteristics can change
31  * with device configuration, such as when a device is folded open or closed. Antenna information is
32  * delivered to registered instances of {@link Listener}.
33  */
34 public final class GnssAntennaInfo implements Parcelable {
35     private final double mCarrierFrequencyMHz;
36     private final PhaseCenterOffset mPhaseCenterOffset;
37     private final @Nullable SphericalCorrections mPhaseCenterVariationCorrections;
38     private final @Nullable SphericalCorrections mSignalGainCorrections;
39 
40     /**
41      * Used for receiving GNSS antenna info from the GNSS engine.
42      */
43     public interface Listener {
44         /**
45          * Invoked on a change to GNSS antenna info.
46          */
onGnssAntennaInfoReceived(@onNull List<GnssAntennaInfo> gnssAntennaInfos)47         void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos);
48     }
49 
50     /**
51      * Class containing information about the antenna phase center offset (PCO). PCO is defined with
52      * respect to the origin of the Android sensor coordinate system, e.g., center of primary screen
53      * for mobiles - see sensor or form factor documents for details. Uncertainties are reported
54      * to 1-sigma.
55      */
56     public static final class PhaseCenterOffset implements Parcelable {
57         private final double mOffsetXMm;
58         private final double mOffsetXUncertaintyMm;
59         private final double mOffsetYMm;
60         private final double mOffsetYUncertaintyMm;
61         private final double mOffsetZMm;
62         private final double mOffsetZUncertaintyMm;
63 
PhaseCenterOffset( double offsetXMm, double offsetXUncertaintyMm, double offsetYMm, double offsetYUncertaintyMm, double offsetZMm, double offsetZUncertaintyMm)64         public PhaseCenterOffset(
65                 double offsetXMm, double offsetXUncertaintyMm,
66                 double offsetYMm, double offsetYUncertaintyMm,
67                 double offsetZMm, double offsetZUncertaintyMm) {
68             mOffsetXMm = offsetXMm;
69             mOffsetYMm = offsetYMm;
70             mOffsetZMm = offsetZMm;
71             mOffsetXUncertaintyMm = offsetXUncertaintyMm;
72             mOffsetYUncertaintyMm = offsetYUncertaintyMm;
73             mOffsetZUncertaintyMm = offsetZUncertaintyMm;
74         }
75 
76         public static final @NonNull Creator<PhaseCenterOffset> CREATOR =
77                 new Creator<PhaseCenterOffset>() {
78                     @Override
79                     public PhaseCenterOffset createFromParcel(Parcel in) {
80                         return new PhaseCenterOffset(
81                                 in.readDouble(),
82                                 in.readDouble(),
83                                 in.readDouble(),
84                                 in.readDouble(),
85                                 in.readDouble(),
86                                 in.readDouble()
87                         );
88                     }
89 
90                     @Override
91                     public PhaseCenterOffset[] newArray(int size) {
92                         return new PhaseCenterOffset[size];
93                     }
94                 };
95 
96         /**
97          * Returns the x-axis offset of the phase center from the origin of the Android sensor
98          * coordinate system, in millimeters.
99          */
100         @FloatRange()
getXOffsetMm()101         public double getXOffsetMm() {
102             return mOffsetXMm;
103         }
104 
105         /**
106          * Returns the 1-sigma uncertainty of the x-axis offset of the phase center from the origin
107          * of the Android sensor coordinate system, in millimeters.
108          */
109         @FloatRange()
getXOffsetUncertaintyMm()110         public double getXOffsetUncertaintyMm() {
111             return mOffsetXUncertaintyMm;
112         }
113 
114         /**
115          * Returns the y-axis offset of the phase center from the origin of the Android sensor
116          * coordinate system, in millimeters.
117          */
118         @FloatRange()
getYOffsetMm()119         public double getYOffsetMm() {
120             return mOffsetYMm;
121         }
122 
123         /**
124          * Returns the 1-sigma uncertainty of the y-axis offset of the phase center from the origin
125          * of the Android sensor coordinate system, in millimeters.
126          */
127         @FloatRange()
getYOffsetUncertaintyMm()128         public double getYOffsetUncertaintyMm() {
129             return mOffsetYUncertaintyMm;
130         }
131 
132         /**
133          * Returns the z-axis offset of the phase center from the origin of the Android sensor
134          * coordinate system, in millimeters.
135          */
136         @FloatRange()
getZOffsetMm()137         public double getZOffsetMm() {
138             return mOffsetZMm;
139         }
140 
141         /**
142          * Returns the 1-sigma uncertainty of the z-axis offset of the phase center from the origin
143          * of the Android sensor coordinate system, in millimeters.
144          */
145         @FloatRange()
getZOffsetUncertaintyMm()146         public double getZOffsetUncertaintyMm() {
147             return mOffsetZUncertaintyMm;
148         }
149 
150         @Override
describeContents()151         public int describeContents() {
152             return 0;
153         }
154 
155         @Override
writeToParcel(@onNull Parcel dest, int flags)156         public void writeToParcel(@NonNull Parcel dest, int flags) {
157             dest.writeDouble(mOffsetXMm);
158             dest.writeDouble(mOffsetXUncertaintyMm);
159             dest.writeDouble(mOffsetYMm);
160             dest.writeDouble(mOffsetYUncertaintyMm);
161             dest.writeDouble(mOffsetZMm);
162             dest.writeDouble(mOffsetZUncertaintyMm);
163         }
164 
165         @Override
toString()166         public String toString() {
167             return "PhaseCenterOffset{"
168                     + "OffsetXMm=" + mOffsetXMm + " +/-" + mOffsetXUncertaintyMm
169                     + ", OffsetYMm=" + mOffsetYMm + " +/-" + mOffsetYUncertaintyMm
170                     + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm
171                     + '}';
172         }
173 
174         @Override
equals(Object o)175         public boolean equals(Object o) {
176             if (this == o) {
177                 return true;
178             }
179             if (!(o instanceof PhaseCenterOffset)) {
180                 return false;
181             }
182             PhaseCenterOffset that = (PhaseCenterOffset) o;
183             return Double.compare(that.mOffsetXMm, mOffsetXMm) == 0
184                     && Double.compare(that.mOffsetXUncertaintyMm, mOffsetXUncertaintyMm) == 0
185                     && Double.compare(that.mOffsetYMm, mOffsetYMm) == 0
186                     && Double.compare(that.mOffsetYUncertaintyMm, mOffsetYUncertaintyMm) == 0
187                     && Double.compare(that.mOffsetZMm, mOffsetZMm) == 0
188                     && Double.compare(that.mOffsetZUncertaintyMm, mOffsetZUncertaintyMm) == 0;
189         }
190 
191         @Override
hashCode()192         public int hashCode() {
193             return Objects.hash(mOffsetXMm, mOffsetYMm, mOffsetZMm);
194         }
195     }
196 
197     /**
198      * Represents corrections on a spherical mapping. Corrections are added to measurements to
199      * obtain the corrected values.
200      *
201      * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays.
202      *
203      * Each row (major indices) represents a fixed theta. The first row corresponds to a
204      * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
205      * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta
206      * = 360 / (number of rows).
207      *
208      * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending
209      * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles,
210      * i.e., deltaPhi = 180 / (number of columns - 1).
211      */
212     public static final class SphericalCorrections implements Parcelable {
213 
214         private final int mNumRows;
215         private final int mNumColumns;
216         private final double[][] mCorrections;
217         private final double[][] mCorrectionUncertainties;
218 
SphericalCorrections(@onNull double[][] corrections, @NonNull double[][] correctionUncertainties)219         public SphericalCorrections(@NonNull double[][] corrections,
220                 @NonNull double[][] correctionUncertainties) {
221             if (corrections.length != correctionUncertainties.length || corrections.length < 1) {
222                 throw new IllegalArgumentException("correction and uncertainty arrays must have "
223                         + "the same (non-zero) dimensions");
224             }
225 
226             mNumRows = corrections.length;
227             mNumColumns = corrections[0].length;
228             for (int i = 0; i < corrections.length; i++) {
229                 if (corrections[i].length != mNumColumns
230                         || correctionUncertainties[i].length != mNumColumns || mNumColumns < 2) {
231                     throw new IllegalArgumentException("correction and uncertainty arrays must all "
232                             + " have the same (greater than 2) number of columns");
233                 }
234             }
235 
236             mCorrections = corrections;
237             mCorrectionUncertainties = correctionUncertainties;
238         }
239 
SphericalCorrections(Parcel in)240         private SphericalCorrections(Parcel in) {
241             int numRows = in.readInt();
242             int numColumns = in.readInt();
243 
244             double[][] corrections =
245                     new double[numRows][numColumns];
246             double[][] correctionUncertainties =
247                     new double[numRows][numColumns];
248 
249             for (int row = 0; row < numRows; row++) {
250                 for (int col = 0; col < numColumns; col++) {
251                     corrections[row][col] = in.readDouble();
252                     correctionUncertainties[row][col] = in.readDouble();
253                 }
254             }
255 
256             mNumRows = numRows;
257             mNumColumns = numColumns;
258             mCorrections = corrections;
259             mCorrectionUncertainties = correctionUncertainties;
260         }
261 
262         /**
263          * Array representing corrections on a spherical mapping. Corrections are added to
264          * measurements to obtain the corrected values.
265          *
266          * Each row (major indices) represents a fixed theta. The first row corresponds to a
267          * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
268          * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e.,
269          * deltaTheta = 360 / (number of rows).
270          *
271          * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and
272          * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith
273          * angles, i.e., deltaPhi = 180 / (number of columns - 1).
274          */
275         @NonNull
getCorrectionsArray()276         public double[][] getCorrectionsArray() {
277             return mCorrections;
278         }
279 
280         /**
281          * Array representing uncertainty on corrections on a spherical mapping.
282          *
283          * Each row (major indices) represents a fixed theta. The first row corresponds to a
284          * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta)
285          * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e.,
286          * deltaTheta = 360 / (number of rows).
287          *
288          * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and
289          * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith
290          * angles, i.e., deltaPhi = 180 / (number of columns - 1).
291          */
292         @NonNull
getCorrectionUncertaintiesArray()293         public double[][] getCorrectionUncertaintiesArray() {
294             return mCorrectionUncertainties;
295         }
296 
297         /**
298          * The fixed theta angle separation between successive rows.
299          */
300         @FloatRange(from = 0.0f, to = 360.0f)
getDeltaTheta()301         public double getDeltaTheta() {
302             return 360.0D / mNumRows;
303         }
304 
305         /**
306          * The fixed phi angle separation between successive columns.
307          */
308         @FloatRange(from = 0.0f, to = 180.0f)
getDeltaPhi()309         public double getDeltaPhi() {
310             return 180.0D / (mNumColumns - 1);
311         }
312 
313 
314         public static final @NonNull Creator<SphericalCorrections> CREATOR =
315                 new Creator<SphericalCorrections>() {
316                     @Override
317                     public SphericalCorrections createFromParcel(Parcel in) {
318                         return new SphericalCorrections(in);
319                     }
320 
321                     @Override
322                     public SphericalCorrections[] newArray(int size) {
323                         return new SphericalCorrections[size];
324                     }
325                 };
326 
327         @Override
describeContents()328         public int describeContents() {
329             return 0;
330         }
331 
332         @Override
writeToParcel(@onNull Parcel dest, int flags)333         public void writeToParcel(@NonNull Parcel dest, int flags) {
334             dest.writeInt(mNumRows);
335             dest.writeInt(mNumColumns);
336             for (int row = 0; row < mNumRows; row++) {
337                 for (int col = 0; col < mNumColumns; col++) {
338                     dest.writeDouble(mCorrections[row][col]);
339                     dest.writeDouble(mCorrectionUncertainties[row][col]);
340                 }
341             }
342         }
343 
344         @Override
toString()345         public String toString() {
346             return "SphericalCorrections{"
347                     + "Corrections=" + Arrays.toString(mCorrections)
348                     + ", CorrectionUncertainties=" + Arrays.toString(mCorrectionUncertainties)
349                     + ", DeltaTheta=" + getDeltaTheta()
350                     + ", DeltaPhi=" + getDeltaPhi()
351                     + '}';
352         }
353 
354         @Override
equals(Object o)355         public boolean equals(Object o) {
356             if (this == o) {
357                 return true;
358             }
359             if (!(o instanceof SphericalCorrections)) {
360                 return false;
361             }
362             SphericalCorrections that = (SphericalCorrections) o;
363             return mNumRows == that.mNumRows
364                     && mNumColumns == that.mNumColumns
365                     && Arrays.deepEquals(mCorrections, that.mCorrections)
366                     && Arrays.deepEquals(mCorrectionUncertainties, that.mCorrectionUncertainties);
367         }
368 
369         @Override
hashCode()370         public int hashCode() {
371             int result = Arrays.deepHashCode(mCorrections);
372             result = 31 * result + Arrays.deepHashCode(mCorrectionUncertainties);
373             return result;
374         }
375     }
376 
GnssAntennaInfo( double carrierFrequencyMHz, PhaseCenterOffset phaseCenterOffset, @Nullable SphericalCorrections phaseCenterVariationCorrections, @Nullable SphericalCorrections signalGainCorrectionDbi)377     private GnssAntennaInfo(
378             double carrierFrequencyMHz,
379             PhaseCenterOffset phaseCenterOffset,
380             @Nullable SphericalCorrections phaseCenterVariationCorrections,
381             @Nullable SphericalCorrections signalGainCorrectionDbi) {
382         mCarrierFrequencyMHz = carrierFrequencyMHz;
383         mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset);
384         mPhaseCenterVariationCorrections = phaseCenterVariationCorrections;
385         mSignalGainCorrections = signalGainCorrectionDbi;
386     }
387 
388     /**
389      * Builder class for GnssAntennaInfo.
390      */
391     public static class Builder {
392         private double mCarrierFrequencyMHz;
393         private PhaseCenterOffset mPhaseCenterOffset;
394         private @Nullable SphericalCorrections mPhaseCenterVariationCorrections;
395         private @Nullable SphericalCorrections mSignalGainCorrections;
396 
397         /**
398          * @deprecated Prefer {@link #Builder(double, PhaseCenterOffset)}.
399          */
400         @Deprecated
Builder()401         public Builder() {
402             this(0, new PhaseCenterOffset(0, 0, 0, 0, 0, 0));
403         }
404 
Builder(double carrierFrequencyMHz, @NonNull PhaseCenterOffset phaseCenterOffset)405         public Builder(double carrierFrequencyMHz, @NonNull PhaseCenterOffset phaseCenterOffset) {
406             mCarrierFrequencyMHz = carrierFrequencyMHz;
407             mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset);
408         }
409 
Builder(@onNull GnssAntennaInfo antennaInfo)410         public Builder(@NonNull GnssAntennaInfo antennaInfo) {
411             mCarrierFrequencyMHz = antennaInfo.mCarrierFrequencyMHz;
412             mPhaseCenterOffset = antennaInfo.mPhaseCenterOffset;
413             mPhaseCenterVariationCorrections = antennaInfo.mPhaseCenterVariationCorrections;
414             mSignalGainCorrections = antennaInfo.mSignalGainCorrections;
415         }
416 
417         /**
418          * Set antenna carrier frequency (MHz).
419          *
420          * @param carrierFrequencyMHz antenna carrier frequency (MHz)
421          * @return Builder builder object
422          */
423         @NonNull
setCarrierFrequencyMHz(@loatRangefrom = 0.0f) double carrierFrequencyMHz)424         public Builder setCarrierFrequencyMHz(@FloatRange(from = 0.0f) double carrierFrequencyMHz) {
425             mCarrierFrequencyMHz = carrierFrequencyMHz;
426             return this;
427         }
428 
429         /**
430          * Set antenna phase center offset.
431          *
432          * @param phaseCenterOffset phase center offset object
433          * @return Builder builder object
434          */
435         @NonNull
setPhaseCenterOffset(@onNull PhaseCenterOffset phaseCenterOffset)436         public Builder setPhaseCenterOffset(@NonNull PhaseCenterOffset phaseCenterOffset) {
437             mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset);
438             return this;
439         }
440 
441         /**
442          * Set phase center variation corrections.
443          *
444          * @param phaseCenterVariationCorrections phase center variation corrections object
445          * @return Builder builder object
446          */
447         @NonNull
setPhaseCenterVariationCorrections( @ullable SphericalCorrections phaseCenterVariationCorrections)448         public Builder setPhaseCenterVariationCorrections(
449                 @Nullable SphericalCorrections phaseCenterVariationCorrections) {
450             mPhaseCenterVariationCorrections = phaseCenterVariationCorrections;
451             return this;
452         }
453 
454         /**
455          * Set signal gain corrections.
456          *
457          * @param signalGainCorrections signal gain corrections object
458          * @return Builder builder object
459          */
460         @NonNull
setSignalGainCorrections( @ullable SphericalCorrections signalGainCorrections)461         public Builder setSignalGainCorrections(
462                 @Nullable SphericalCorrections signalGainCorrections) {
463             mSignalGainCorrections = signalGainCorrections;
464             return this;
465         }
466 
467         /**
468          * Build GnssAntennaInfo object.
469          *
470          * @return instance of GnssAntennaInfo
471          */
472         @NonNull
build()473         public GnssAntennaInfo build() {
474             return new GnssAntennaInfo(mCarrierFrequencyMHz, mPhaseCenterOffset,
475                     mPhaseCenterVariationCorrections, mSignalGainCorrections);
476         }
477     }
478 
479     @FloatRange(from = 0.0f)
getCarrierFrequencyMHz()480     public double getCarrierFrequencyMHz() {
481         return mCarrierFrequencyMHz;
482     }
483 
484     /**
485      * Returns a {@link PhaseCenterOffset} object encapsulating the phase center offset and
486      * corresponding uncertainties in millimeters.
487      *
488      * @return {@link PhaseCenterOffset}
489      */
490     @NonNull
getPhaseCenterOffset()491     public PhaseCenterOffset getPhaseCenterOffset() {
492         return mPhaseCenterOffset;
493     }
494 
495     /**
496      * Returns a {@link SphericalCorrections} object encapsulating the phase center variation
497      * corrections and corresponding uncertainties in millimeters.
498      *
499      * @return phase center variation corrections as {@link SphericalCorrections}
500      */
501     @Nullable
getPhaseCenterVariationCorrections()502     public SphericalCorrections getPhaseCenterVariationCorrections() {
503         return mPhaseCenterVariationCorrections;
504     }
505 
506     /**
507      * Returns a {@link SphericalCorrections} object encapsulating the signal gain
508      * corrections and corresponding uncertainties in dBi.
509      *
510      * @return signal gain corrections as {@link SphericalCorrections}
511      */
512     @Nullable
getSignalGainCorrections()513     public SphericalCorrections getSignalGainCorrections() {
514         return mSignalGainCorrections;
515     }
516 
517     public static final @NonNull Creator<GnssAntennaInfo> CREATOR = new Creator<GnssAntennaInfo>() {
518         @Override
519         public GnssAntennaInfo createFromParcel(Parcel in) {
520             double carrierFrequencyMHz = in.readDouble();
521             PhaseCenterOffset phaseCenterOffset =
522                     in.readTypedObject(PhaseCenterOffset.CREATOR);
523             SphericalCorrections phaseCenterVariationCorrections =
524                     in.readTypedObject(SphericalCorrections.CREATOR);
525             SphericalCorrections signalGainCorrections =
526                     in.readTypedObject(SphericalCorrections.CREATOR);
527 
528             return new GnssAntennaInfo(
529                     carrierFrequencyMHz,
530                     phaseCenterOffset,
531                     phaseCenterVariationCorrections,
532                     signalGainCorrections);
533         }
534 
535         @Override
536         public GnssAntennaInfo[] newArray(int size) {
537             return new GnssAntennaInfo[size];
538         }
539     };
540 
541     @Override
describeContents()542     public int describeContents() {
543         return 0;
544     }
545 
546     @Override
writeToParcel(@onNull Parcel parcel, int flags)547     public void writeToParcel(@NonNull Parcel parcel, int flags) {
548         parcel.writeDouble(mCarrierFrequencyMHz);
549         parcel.writeTypedObject(mPhaseCenterOffset, flags);
550         parcel.writeTypedObject(mPhaseCenterVariationCorrections, flags);
551         parcel.writeTypedObject(mSignalGainCorrections, flags);
552     }
553 
554     @Override
toString()555     public String toString() {
556         return "GnssAntennaInfo{"
557                 + "CarrierFrequencyMHz=" + mCarrierFrequencyMHz
558                 + ", PhaseCenterOffset=" + mPhaseCenterOffset
559                 + ", PhaseCenterVariationCorrections=" + mPhaseCenterVariationCorrections
560                 + ", SignalGainCorrections=" + mSignalGainCorrections
561                 + '}';
562     }
563 
564     @Override
equals(Object o)565     public boolean equals(Object o) {
566         if (this == o) {
567             return true;
568         }
569         if (!(o instanceof GnssAntennaInfo)) {
570             return false;
571         }
572         GnssAntennaInfo that = (GnssAntennaInfo) o;
573         return Double.compare(that.mCarrierFrequencyMHz, mCarrierFrequencyMHz) == 0
574                 && mPhaseCenterOffset.equals(that.mPhaseCenterOffset)
575                 && Objects.equals(mPhaseCenterVariationCorrections,
576                     that.mPhaseCenterVariationCorrections)
577                 && Objects.equals(mSignalGainCorrections, that.mSignalGainCorrections);
578     }
579 
580     @Override
hashCode()581     public int hashCode() {
582         return Objects.hash(mCarrierFrequencyMHz, mPhaseCenterOffset,
583                 mPhaseCenterVariationCorrections, mSignalGainCorrections);
584     }
585 }
586