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