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 SphericalCorrections mPhaseCenterVariationCorrections; 38 private final SphericalCorrections mSignalGainCorrections; 39 40 /** 41 * Used for receiving GNSS antenna info from the GNSS engine. You can implement this interface 42 * and call {@link LocationManager#registerAntennaInfoListener}; 43 */ 44 public interface Listener { 45 /** 46 * Returns the latest GNSS antenna info. This event is triggered when a listener is 47 * registered, and whenever the antenna info changes (due to a device configuration change). 48 */ onGnssAntennaInfoReceived(@onNull List<GnssAntennaInfo> gnssAntennaInfos)49 void onGnssAntennaInfoReceived(@NonNull List<GnssAntennaInfo> gnssAntennaInfos); 50 } 51 52 /** 53 * Class containing information about the antenna phase center offset (PCO). PCO is defined with 54 * respect to the origin of the Android sensor coordinate system, e.g., center of primary screen 55 * for mobiles - see sensor or form factor documents for details. Uncertainties are reported 56 * to 1-sigma. 57 */ 58 public static final class PhaseCenterOffset implements Parcelable { 59 private final double mOffsetXMm; 60 private final double mOffsetXUncertaintyMm; 61 private final double mOffsetYMm; 62 private final double mOffsetYUncertaintyMm; 63 private final double mOffsetZMm; 64 private final double mOffsetZUncertaintyMm; 65 PhaseCenterOffset( double offsetXMm, double offsetXUncertaintyMm, double offsetYMm, double offsetYUncertaintyMm, double offsetZMm, double offsetZUncertaintyMm)66 public PhaseCenterOffset( 67 double offsetXMm, double offsetXUncertaintyMm, 68 double offsetYMm, double offsetYUncertaintyMm, 69 double offsetZMm, double offsetZUncertaintyMm) { 70 mOffsetXMm = offsetXMm; 71 mOffsetYMm = offsetYMm; 72 mOffsetZMm = offsetZMm; 73 mOffsetXUncertaintyMm = offsetXUncertaintyMm; 74 mOffsetYUncertaintyMm = offsetYUncertaintyMm; 75 mOffsetZUncertaintyMm = offsetZUncertaintyMm; 76 } 77 78 public static final @NonNull Creator<PhaseCenterOffset> CREATOR = 79 new Creator<PhaseCenterOffset>() { 80 @Override 81 public PhaseCenterOffset createFromParcel(Parcel in) { 82 return new PhaseCenterOffset( 83 in.readDouble(), 84 in.readDouble(), 85 in.readDouble(), 86 in.readDouble(), 87 in.readDouble(), 88 in.readDouble() 89 ); 90 } 91 92 @Override 93 public PhaseCenterOffset[] newArray(int size) { 94 return new PhaseCenterOffset[size]; 95 } 96 }; 97 98 @FloatRange() getXOffsetMm()99 public double getXOffsetMm() { 100 return mOffsetXMm; 101 } 102 103 @FloatRange() getXOffsetUncertaintyMm()104 public double getXOffsetUncertaintyMm() { 105 return mOffsetXUncertaintyMm; 106 } 107 108 @FloatRange() getYOffsetMm()109 public double getYOffsetMm() { 110 return mOffsetYMm; 111 } 112 113 @FloatRange() getYOffsetUncertaintyMm()114 public double getYOffsetUncertaintyMm() { 115 return mOffsetYUncertaintyMm; 116 } 117 118 @FloatRange() getZOffsetMm()119 public double getZOffsetMm() { 120 return mOffsetZMm; 121 } 122 123 @FloatRange() getZOffsetUncertaintyMm()124 public double getZOffsetUncertaintyMm() { 125 return mOffsetZUncertaintyMm; 126 } 127 128 @Override describeContents()129 public int describeContents() { 130 return 0; 131 } 132 133 @Override writeToParcel(@onNull Parcel dest, int flags)134 public void writeToParcel(@NonNull Parcel dest, int flags) { 135 dest.writeDouble(mOffsetXMm); 136 dest.writeDouble(mOffsetXUncertaintyMm); 137 dest.writeDouble(mOffsetYMm); 138 dest.writeDouble(mOffsetYUncertaintyMm); 139 dest.writeDouble(mOffsetZMm); 140 dest.writeDouble(mOffsetZUncertaintyMm); 141 } 142 143 @Override toString()144 public String toString() { 145 return "PhaseCenterOffset{" 146 + "OffsetXMm=" + mOffsetXMm + " +/-" + mOffsetXUncertaintyMm 147 + ", OffsetYMm=" + mOffsetYMm + " +/-" + mOffsetYUncertaintyMm 148 + ", OffsetZMm=" + mOffsetZMm + " +/-" + mOffsetZUncertaintyMm 149 + '}'; 150 } 151 } 152 153 /** 154 * Represents corrections on a spherical mapping. Corrections are added to measurements to 155 * obtain the corrected values. 156 * 157 * The corrections and associated (1-sigma) uncertainties are represented by respect 2D arrays. 158 * 159 * Each row (major indices) represents a fixed theta. The first row corresponds to a 160 * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) 161 * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., deltaTheta 162 * = 360 / (number of rows). 163 * 164 * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and ending 165 * at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith angles, 166 * i.e., deltaPhi = 180 / (number of columns - 1). 167 */ 168 public static final class SphericalCorrections implements Parcelable{ 169 private final double[][] mCorrections; 170 private final double[][] mCorrectionUncertainties; 171 private final double mDeltaTheta; 172 private final double mDeltaPhi; 173 private final int mNumRows; 174 private final int mNumColumns; 175 SphericalCorrections(@onNull double[][] corrections, @NonNull double[][] correctionUncertainties)176 public SphericalCorrections(@NonNull double[][] corrections, 177 @NonNull double[][] correctionUncertainties) { 178 if (corrections.length != correctionUncertainties.length 179 || corrections[0].length != correctionUncertainties[0].length) { 180 throw new IllegalArgumentException("Correction and correction uncertainty arrays " 181 + "must have the same dimensions."); 182 } 183 184 mNumRows = corrections.length; 185 if (mNumRows < 1) { 186 throw new IllegalArgumentException("Arrays must have at least one row."); 187 } 188 189 mNumColumns = corrections[0].length; 190 if (mNumColumns < 2) { 191 throw new IllegalArgumentException("Arrays must have at least two columns."); 192 } 193 194 mCorrections = corrections; 195 mCorrectionUncertainties = correctionUncertainties; 196 mDeltaTheta = 360.0d / mNumRows; 197 mDeltaPhi = 180.0d / (mNumColumns - 1); 198 } 199 SphericalCorrections(Parcel in)200 SphericalCorrections(Parcel in) { 201 int numRows = in.readInt(); 202 int numColumns = in.readInt(); 203 204 double[][] corrections = 205 new double[numRows][numColumns]; 206 double[][] correctionUncertainties = 207 new double[numRows][numColumns]; 208 209 for (int row = 0; row < numRows; row++) { 210 in.readDoubleArray(corrections[row]); 211 } 212 213 for (int row = 0; row < numRows; row++) { 214 in.readDoubleArray(correctionUncertainties[row]); 215 } 216 217 mNumRows = numRows; 218 mNumColumns = numColumns; 219 mCorrections = corrections; 220 mCorrectionUncertainties = correctionUncertainties; 221 mDeltaTheta = 360.0d / mNumRows; 222 mDeltaPhi = 180.0d / (mNumColumns - 1); 223 } 224 225 /** 226 * Array representing corrections on a spherical mapping. Corrections are added to 227 * measurements to obtain the corrected values. 228 * 229 * Each row (major indices) represents a fixed theta. The first row corresponds to a 230 * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) 231 * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., 232 * deltaTheta = 360 / (number of rows). 233 * 234 * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and 235 * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith 236 * angles, i.e., deltaPhi = 180 / (number of columns - 1). 237 */ 238 @NonNull getCorrectionsArray()239 public double[][] getCorrectionsArray() { 240 return mCorrections; 241 } 242 243 /** 244 * Array representing uncertainty on corrections on a spherical mapping. 245 * 246 * Each row (major indices) represents a fixed theta. The first row corresponds to a 247 * theta angle of 0 degrees. The last row corresponds to a theta angle of (360 - deltaTheta) 248 * degrees, where deltaTheta is the regular spacing between azimuthal angles, i.e., 249 * deltaTheta = 360 / (number of rows). 250 * 251 * The columns (minor indices) represent fixed zenith angles, beginning at 0 degrees and 252 * ending at 180 degrees. They are separated by deltaPhi, the regular spacing between zenith 253 * angles, i.e., deltaPhi = 180 / (number of columns - 1). 254 */ 255 @NonNull getCorrectionUncertaintiesArray()256 public double[][] getCorrectionUncertaintiesArray() { 257 return mCorrectionUncertainties; 258 } 259 260 /** 261 * The fixed theta angle separation between successive rows. 262 */ 263 @FloatRange(from = 0.0f, to = 360.0f) getDeltaTheta()264 public double getDeltaTheta() { 265 return mDeltaTheta; 266 } 267 268 /** 269 * The fixed phi angle separation between successive columns. 270 */ 271 @FloatRange(from = 0.0f, to = 180.0f) getDeltaPhi()272 public double getDeltaPhi() { 273 return mDeltaPhi; 274 } 275 276 277 public static final @NonNull Creator<SphericalCorrections> CREATOR = 278 new Creator<SphericalCorrections>() { 279 @Override 280 public SphericalCorrections createFromParcel(Parcel in) { 281 return new SphericalCorrections(in); 282 } 283 284 @Override 285 public SphericalCorrections[] newArray(int size) { 286 return new SphericalCorrections[size]; 287 } 288 }; 289 290 @Override describeContents()291 public int describeContents() { 292 return 0; 293 } 294 295 @Override writeToParcel(@onNull Parcel dest, int flags)296 public void writeToParcel(@NonNull Parcel dest, int flags) { 297 dest.writeInt(mNumRows); 298 dest.writeInt(mNumColumns); 299 for (double[] row: mCorrections) { 300 dest.writeDoubleArray(row); 301 } 302 for (double[] row: mCorrectionUncertainties) { 303 dest.writeDoubleArray(row); 304 } 305 } 306 307 @Override toString()308 public String toString() { 309 return "SphericalCorrections{" 310 + "Corrections=" + Arrays.toString(mCorrections) 311 + ", CorrectionUncertainties=" + Arrays.toString(mCorrectionUncertainties) 312 + ", DeltaTheta=" + mDeltaTheta 313 + ", DeltaPhi=" + mDeltaPhi 314 + '}'; 315 } 316 } 317 GnssAntennaInfo( double carrierFrequencyMHz, @NonNull PhaseCenterOffset phaseCenterOffset, @Nullable SphericalCorrections phaseCenterVariationCorrections, @Nullable SphericalCorrections signalGainCorrectionDbi)318 private GnssAntennaInfo( 319 double carrierFrequencyMHz, 320 @NonNull PhaseCenterOffset phaseCenterOffset, 321 @Nullable SphericalCorrections phaseCenterVariationCorrections, 322 @Nullable SphericalCorrections signalGainCorrectionDbi) { 323 if (phaseCenterOffset == null) { 324 throw new IllegalArgumentException("Phase Center Offset Coordinates cannot be null."); 325 } 326 mCarrierFrequencyMHz = carrierFrequencyMHz; 327 mPhaseCenterOffset = phaseCenterOffset; 328 mPhaseCenterVariationCorrections = phaseCenterVariationCorrections; 329 mSignalGainCorrections = signalGainCorrectionDbi; 330 } 331 332 /** 333 * Builder class for GnssAntennaInfo. 334 */ 335 public static class Builder { 336 private double mCarrierFrequencyMHz; 337 private PhaseCenterOffset mPhaseCenterOffset; 338 private SphericalCorrections mPhaseCenterVariationCorrections; 339 private SphericalCorrections mSignalGainCorrections; 340 341 /** 342 * Set antenna carrier frequency (MHz). 343 * @param carrierFrequencyMHz antenna carrier frequency (MHz) 344 * @return Builder builder object 345 */ 346 @NonNull setCarrierFrequencyMHz(@loatRangefrom = 0.0f) double carrierFrequencyMHz)347 public Builder setCarrierFrequencyMHz(@FloatRange(from = 0.0f) double carrierFrequencyMHz) { 348 mCarrierFrequencyMHz = carrierFrequencyMHz; 349 return this; 350 } 351 352 /** 353 * Set antenna phase center offset. 354 * @param phaseCenterOffset phase center offset object 355 * @return Builder builder object 356 */ 357 @NonNull setPhaseCenterOffset(@onNull PhaseCenterOffset phaseCenterOffset)358 public Builder setPhaseCenterOffset(@NonNull PhaseCenterOffset phaseCenterOffset) { 359 mPhaseCenterOffset = Objects.requireNonNull(phaseCenterOffset); 360 return this; 361 } 362 363 /** 364 * Set phase center variation corrections. 365 * @param phaseCenterVariationCorrections phase center variation corrections object 366 * @return Builder builder object 367 */ 368 @NonNull setPhaseCenterVariationCorrections( @ullable SphericalCorrections phaseCenterVariationCorrections)369 public Builder setPhaseCenterVariationCorrections( 370 @Nullable SphericalCorrections phaseCenterVariationCorrections) { 371 mPhaseCenterVariationCorrections = phaseCenterVariationCorrections; 372 return this; 373 } 374 375 /** 376 * Set signal gain corrections. 377 * @param signalGainCorrections signal gain corrections object 378 * @return Builder builder object 379 */ 380 @NonNull setSignalGainCorrections( @ullable SphericalCorrections signalGainCorrections)381 public Builder setSignalGainCorrections( 382 @Nullable SphericalCorrections signalGainCorrections) { 383 mSignalGainCorrections = signalGainCorrections; 384 return this; 385 } 386 387 /** 388 * Build GnssAntennaInfo object. 389 * @return instance of GnssAntennaInfo 390 */ 391 @NonNull build()392 public GnssAntennaInfo build() { 393 return new GnssAntennaInfo(mCarrierFrequencyMHz, mPhaseCenterOffset, 394 mPhaseCenterVariationCorrections, mSignalGainCorrections); 395 } 396 } 397 398 @FloatRange(from = 0.0f) getCarrierFrequencyMHz()399 public double getCarrierFrequencyMHz() { 400 return mCarrierFrequencyMHz; 401 } 402 403 @NonNull getPhaseCenterOffset()404 public PhaseCenterOffset getPhaseCenterOffset() { 405 return mPhaseCenterOffset; 406 } 407 408 @Nullable getPhaseCenterVariationCorrections()409 public SphericalCorrections getPhaseCenterVariationCorrections() { 410 return mPhaseCenterVariationCorrections; 411 } 412 413 @Nullable getSignalGainCorrections()414 public SphericalCorrections getSignalGainCorrections() { 415 return mSignalGainCorrections; 416 } 417 418 public static final @android.annotation.NonNull 419 Creator<GnssAntennaInfo> CREATOR = new Creator<GnssAntennaInfo>() { 420 @Override 421 public GnssAntennaInfo createFromParcel(Parcel in) { 422 double carrierFrequencyMHz = in.readDouble(); 423 424 ClassLoader classLoader = getClass().getClassLoader(); 425 PhaseCenterOffset phaseCenterOffset = 426 in.readParcelable(classLoader); 427 SphericalCorrections phaseCenterVariationCorrections = 428 in.readParcelable(classLoader); 429 SphericalCorrections signalGainCorrections = 430 in.readParcelable(classLoader); 431 432 return new GnssAntennaInfo( 433 carrierFrequencyMHz, 434 phaseCenterOffset, 435 phaseCenterVariationCorrections, 436 signalGainCorrections); 437 } 438 439 @Override 440 public GnssAntennaInfo[] newArray(int size) { 441 return new GnssAntennaInfo[size]; 442 } 443 }; 444 445 @Override describeContents()446 public int describeContents() { 447 return 0; 448 } 449 450 @Override writeToParcel(@onNull Parcel parcel, int flags)451 public void writeToParcel(@NonNull Parcel parcel, int flags) { 452 parcel.writeDouble(mCarrierFrequencyMHz); 453 parcel.writeParcelable(mPhaseCenterOffset, flags); 454 parcel.writeParcelable(mPhaseCenterVariationCorrections, flags); 455 parcel.writeParcelable(mSignalGainCorrections, flags); 456 } 457 458 @Override toString()459 public String toString() { 460 return "GnssAntennaInfo{" 461 + "CarrierFrequencyMHz=" + mCarrierFrequencyMHz 462 + ", PhaseCenterOffset=" + mPhaseCenterOffset 463 + ", PhaseCenterVariationCorrections=" + mPhaseCenterVariationCorrections 464 + ", SignalGainCorrections=" + mSignalGainCorrections 465 + '}'; 466 } 467 } 468