1 /* 2 * Copyright (C) 2016 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.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Objects; 29 30 /** 31 * This class represents the current state of the GNSS engine and is used in conjunction with 32 * {@link GnssStatus.Callback}. 33 * 34 * @see LocationManager#registerGnssStatusCallback 35 * @see GnssStatus.Callback 36 */ 37 public final class GnssStatus { 38 39 // These must match the definitions in GNSS HAL. 40 // 41 // Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support 42 // library. if adding a constellation, please update that file as well. 43 44 /** Unknown constellation type. */ 45 public static final int CONSTELLATION_UNKNOWN = 0; 46 /** Constellation type constant for GPS. */ 47 public static final int CONSTELLATION_GPS = 1; 48 /** Constellation type constant for SBAS. */ 49 public static final int CONSTELLATION_SBAS = 2; 50 /** Constellation type constant for Glonass. */ 51 public static final int CONSTELLATION_GLONASS = 3; 52 /** Constellation type constant for QZSS. */ 53 public static final int CONSTELLATION_QZSS = 4; 54 /** Constellation type constant for Beidou. */ 55 public static final int CONSTELLATION_BEIDOU = 5; 56 /** Constellation type constant for Galileo. */ 57 public static final int CONSTELLATION_GALILEO = 6; 58 /** Constellation type constant for IRNSS. */ 59 public static final int CONSTELLATION_IRNSS = 7; 60 /** @hide */ 61 public static final int CONSTELLATION_COUNT = 8; 62 63 private static final int SVID_FLAGS_NONE = 0; 64 private static final int SVID_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0); 65 private static final int SVID_FLAGS_HAS_ALMANAC_DATA = (1 << 1); 66 private static final int SVID_FLAGS_USED_IN_FIX = (1 << 2); 67 private static final int SVID_FLAGS_HAS_CARRIER_FREQUENCY = (1 << 3); 68 private static final int SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4); 69 70 private static final int SVID_SHIFT_WIDTH = 12; 71 private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 8; 72 private static final int CONSTELLATION_TYPE_MASK = 0xf; 73 74 /** 75 * Used for receiving notifications when GNSS events happen. 76 * 77 * @see LocationManager#registerGnssStatusCallback 78 */ 79 public static abstract class Callback { 80 /** 81 * Called when GNSS system has started. 82 */ onStarted()83 public void onStarted() { 84 } 85 86 /** 87 * Called when GNSS system has stopped. 88 */ onStopped()89 public void onStopped() { 90 } 91 92 /** 93 * Called when the GNSS system has received its first fix since starting. 94 * 95 * @param ttffMillis the time from start to first fix in milliseconds. 96 */ onFirstFix(int ttffMillis)97 public void onFirstFix(int ttffMillis) { 98 } 99 100 /** 101 * Called periodically to report GNSS satellite status. 102 * 103 * @param status the current status of all satellites. 104 */ onSatelliteStatusChanged(@onNull GnssStatus status)105 public void onSatelliteStatusChanged(@NonNull GnssStatus status) { 106 } 107 } 108 109 /** 110 * Constellation type. 111 * 112 * @hide 113 */ 114 @Retention(RetentionPolicy.SOURCE) 115 @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS, 116 CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO, CONSTELLATION_IRNSS}) 117 public @interface ConstellationType { 118 } 119 120 /** 121 * Create a GnssStatus that wraps the given arguments without any additional overhead. Callers 122 * are responsible for guaranteeing that the arguments are never modified after calling this 123 * method. 124 * 125 * @hide 126 */ 127 @NonNull wrap(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations, float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs)128 public static GnssStatus wrap(int svCount, int[] svidWithFlags, float[] cn0DbHzs, 129 float[] elevations, float[] azimuths, float[] carrierFrequencies, 130 float[] basebandCn0DbHzs) { 131 return new GnssStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, 132 carrierFrequencies, basebandCn0DbHzs); 133 } 134 135 private final int mSvCount; 136 private final int[] mSvidWithFlags; 137 private final float[] mCn0DbHzs; 138 private final float[] mElevations; 139 private final float[] mAzimuths; 140 private final float[] mCarrierFrequencies; 141 private final float[] mBasebandCn0DbHzs; 142 GnssStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations, float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs)143 private GnssStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations, 144 float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs) { 145 mSvCount = svCount; 146 mSvidWithFlags = svidWithFlags; 147 mCn0DbHzs = cn0DbHzs; 148 mElevations = elevations; 149 mAzimuths = azimuths; 150 mCarrierFrequencies = carrierFrequencies; 151 mBasebandCn0DbHzs = basebandCn0DbHzs; 152 } 153 154 /** 155 * Gets the total number of satellites in satellite list. 156 */ 157 @IntRange(from = 0) getSatelliteCount()158 public int getSatelliteCount() { 159 return mSvCount; 160 } 161 162 /** 163 * Retrieves the constellation type of the satellite at the specified index. 164 * 165 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 166 */ 167 @ConstellationType getConstellationType(@ntRangefrom = 0) int satelliteIndex)168 public int getConstellationType(@IntRange(from = 0) int satelliteIndex) { 169 return ((mSvidWithFlags[satelliteIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH) 170 & CONSTELLATION_TYPE_MASK); 171 } 172 173 /** 174 * Gets the identification number for the satellite at the specific index. 175 * 176 * <p>This svid is pseudo-random number for most constellations. It is FCN & OSN number for 177 * Glonass. 178 * 179 * <p>The distinction is made by looking at constellation field 180 * {@link #getConstellationType(int)} Expected values are in the range of: 181 * 182 * <ul> 183 * <li>GPS: 1-32</li> 184 * <li>SBAS: 120-151, 183-192</li> 185 * <li>GLONASS: One of: OSN, or FCN+100 186 * <ul> 187 * <li>1-24 as the orbital slot number (OSN) (preferred, if known)</li> 188 * <li>93-106 as the frequency channel number (FCN) (-7 to +6) plus 100. 189 * i.e. encode FCN of -7 as 93, 0 as 100, and +6 as 106</li> 190 * </ul></li> 191 * <li>QZSS: 193-200</li> 192 * <li>Galileo: 1-36</li> 193 * <li>Beidou: 1-37</li> 194 * <li>IRNSS: 1-14</li> 195 * </ul> 196 * 197 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 198 */ 199 @IntRange(from = 1, to = 200) getSvid(@ntRangefrom = 0) int satelliteIndex)200 public int getSvid(@IntRange(from = 0) int satelliteIndex) { 201 return mSvidWithFlags[satelliteIndex] >> SVID_SHIFT_WIDTH; 202 } 203 204 /** 205 * Retrieves the carrier-to-noise density at the antenna of the satellite at the specified index 206 * in dB-Hz. 207 * 208 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 209 */ 210 @FloatRange(from = 0, to = 63) getCn0DbHz(@ntRangefrom = 0) int satelliteIndex)211 public float getCn0DbHz(@IntRange(from = 0) int satelliteIndex) { 212 return mCn0DbHzs[satelliteIndex]; 213 } 214 215 /** 216 * Retrieves the elevation of the satellite at the specified index. 217 * 218 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 219 */ 220 @FloatRange(from = -90, to = 90) getElevationDegrees(@ntRangefrom = 0) int satelliteIndex)221 public float getElevationDegrees(@IntRange(from = 0) int satelliteIndex) { 222 return mElevations[satelliteIndex]; 223 } 224 225 /** 226 * Retrieves the azimuth the satellite at the specified index. 227 * 228 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 229 */ 230 @FloatRange(from = 0, to = 360) getAzimuthDegrees(@ntRangefrom = 0) int satelliteIndex)231 public float getAzimuthDegrees(@IntRange(from = 0) int satelliteIndex) { 232 return mAzimuths[satelliteIndex]; 233 } 234 235 /** 236 * Reports whether the satellite at the specified index has ephemeris data. 237 * 238 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 239 */ hasEphemerisData(@ntRangefrom = 0) int satelliteIndex)240 public boolean hasEphemerisData(@IntRange(from = 0) int satelliteIndex) { 241 return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_EPHEMERIS_DATA) != 0; 242 } 243 244 /** 245 * Reports whether the satellite at the specified index has almanac data. 246 * 247 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 248 */ hasAlmanacData(@ntRangefrom = 0) int satelliteIndex)249 public boolean hasAlmanacData(@IntRange(from = 0) int satelliteIndex) { 250 return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_ALMANAC_DATA) != 0; 251 } 252 253 /** 254 * Reports whether the satellite at the specified index was used in the calculation of the most 255 * recent position fix. 256 * 257 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 258 */ usedInFix(@ntRangefrom = 0) int satelliteIndex)259 public boolean usedInFix(@IntRange(from = 0) int satelliteIndex) { 260 return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_USED_IN_FIX) != 0; 261 } 262 263 /** 264 * Reports whether a valid {@link #getCarrierFrequencyHz(int satelliteIndex)} is available. 265 * 266 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 267 */ hasCarrierFrequencyHz(@ntRangefrom = 0) int satelliteIndex)268 public boolean hasCarrierFrequencyHz(@IntRange(from = 0) int satelliteIndex) { 269 return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_CARRIER_FREQUENCY) != 0; 270 } 271 272 /** 273 * Gets the carrier frequency of the signal tracked. 274 * 275 * <p>For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 276 * MHz, L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary 277 * common use central frequency, e.g. L1 = 1575.45 MHz for GPS. 278 * 279 * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two measurements 280 * will be reported for this same satellite, in one all the values related to L1 will be 281 * filled, and in the other all of the values related to L5 will be filled. 282 * 283 * <p>The value is only available if {@link #hasCarrierFrequencyHz(int satelliteIndex)} is 284 * {@code true}. 285 * 286 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 287 */ 288 @FloatRange(from = 0) getCarrierFrequencyHz(@ntRangefrom = 0) int satelliteIndex)289 public float getCarrierFrequencyHz(@IntRange(from = 0) int satelliteIndex) { 290 return mCarrierFrequencies[satelliteIndex]; 291 } 292 293 /** 294 * Reports whether a valid {@link #getBasebandCn0DbHz(int satelliteIndex)} is available. 295 * 296 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 297 */ hasBasebandCn0DbHz(@ntRangefrom = 0) int satelliteIndex)298 public boolean hasBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) { 299 return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_BASEBAND_CN0) != 0; 300 } 301 302 /** 303 * Retrieves the baseband carrier-to-noise density of the satellite at the specified index in 304 * dB-Hz. 305 * 306 * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1 307 */ 308 @FloatRange(from = 0, to = 63) getBasebandCn0DbHz(@ntRangefrom = 0) int satelliteIndex)309 public float getBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) { 310 return mBasebandCn0DbHzs[satelliteIndex]; 311 } 312 313 /** 314 * Returns the string representation of a constellation type. 315 * 316 * @param constellationType the constellation type. 317 * @return the string representation. 318 * @hide 319 */ 320 @NonNull constellationTypeToString(@onstellationType int constellationType)321 public static String constellationTypeToString(@ConstellationType int constellationType) { 322 switch (constellationType) { 323 case CONSTELLATION_UNKNOWN: 324 return "UNKNOWN"; 325 case CONSTELLATION_GPS: 326 return "GPS"; 327 case CONSTELLATION_SBAS: 328 return "SBAS"; 329 case CONSTELLATION_GLONASS: 330 return "GLONASS"; 331 case CONSTELLATION_QZSS: 332 return "QZSS"; 333 case CONSTELLATION_BEIDOU: 334 return "BEIDOU"; 335 case CONSTELLATION_GALILEO: 336 return "GALILEO"; 337 case CONSTELLATION_IRNSS: 338 return "IRNSS"; 339 default: 340 return Integer.toString(constellationType); 341 } 342 } 343 344 @Override equals(Object o)345 public boolean equals(Object o) { 346 if (this == o) { 347 return true; 348 } 349 if (!(o instanceof GnssStatus)) { 350 return false; 351 } 352 353 GnssStatus that = (GnssStatus) o; 354 return mSvCount == that.mSvCount 355 && Arrays.equals(mSvidWithFlags, that.mSvidWithFlags) 356 && Arrays.equals(mCn0DbHzs, that.mCn0DbHzs) 357 && Arrays.equals(mElevations, that.mElevations) 358 && Arrays.equals(mAzimuths, that.mAzimuths) 359 && Arrays.equals(mCarrierFrequencies, that.mCarrierFrequencies) 360 && Arrays.equals(mBasebandCn0DbHzs, that.mBasebandCn0DbHzs); 361 } 362 363 @Override hashCode()364 public int hashCode() { 365 int result = Objects.hash(mSvCount); 366 result = 31 * result + Arrays.hashCode(mSvidWithFlags); 367 result = 31 * result + Arrays.hashCode(mCn0DbHzs); 368 return result; 369 } 370 371 /** 372 * Builder class to help create new GnssStatus instances. 373 */ 374 public static final class Builder { 375 376 private final ArrayList<GnssSvInfo> mSatellites = new ArrayList<>(); 377 378 /** 379 * Adds a new satellite to the Builder. 380 * 381 * @param constellationType one of the CONSTELLATION_* constants 382 * @param svid the space vehicle identifier 383 * @param cn0DbHz carrier-to-noise density at the antenna in dB-Hz 384 * @param elevation satellite elevation in degrees 385 * @param azimuth satellite azimuth in degrees 386 * @param hasEphemeris whether the satellite has ephemeris data 387 * @param hasAlmanac whether the satellite has almanac data 388 * @param usedInFix whether the satellite was used in the most recent location fix 389 * @param hasCarrierFrequency whether carrier frequency data is available 390 * @param carrierFrequency satellite carrier frequency in Hz 391 * @param hasBasebandCn0DbHz whether baseband carrier-to-noise density is available 392 * @param basebandCn0DbHz baseband carrier-to-noise density in dB-Hz 393 */ 394 @NonNull addSatellite(@onstellationType int constellationType, @IntRange(from = 1, to = 200) int svid, @FloatRange(from = 0, to = 63) float cn0DbHz, @FloatRange(from = -90, to = 90) float elevation, @FloatRange(from = 0, to = 360) float azimuth, boolean hasEphemeris, boolean hasAlmanac, boolean usedInFix, boolean hasCarrierFrequency, @FloatRange(from = 0) float carrierFrequency, boolean hasBasebandCn0DbHz, @FloatRange(from = 0, to = 63) float basebandCn0DbHz)395 public Builder addSatellite(@ConstellationType int constellationType, 396 @IntRange(from = 1, to = 200) int svid, 397 @FloatRange(from = 0, to = 63) float cn0DbHz, 398 @FloatRange(from = -90, to = 90) float elevation, 399 @FloatRange(from = 0, to = 360) float azimuth, 400 boolean hasEphemeris, 401 boolean hasAlmanac, 402 boolean usedInFix, 403 boolean hasCarrierFrequency, 404 @FloatRange(from = 0) float carrierFrequency, 405 boolean hasBasebandCn0DbHz, 406 @FloatRange(from = 0, to = 63) float basebandCn0DbHz) { 407 mSatellites.add(new GnssSvInfo(constellationType, svid, cn0DbHz, elevation, azimuth, 408 hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency, 409 hasBasebandCn0DbHz, basebandCn0DbHz)); 410 return this; 411 } 412 413 /** 414 * Clears all satellites in the Builder. 415 */ 416 @NonNull clearSatellites()417 public Builder clearSatellites() { 418 mSatellites.clear(); 419 return this; 420 } 421 422 /** 423 * Builds a new GnssStatus based on the satellite information in the Builder. 424 */ 425 @NonNull build()426 public GnssStatus build() { 427 int svCount = mSatellites.size(); 428 int[] svidWithFlags = new int[svCount]; 429 float[] cn0DbHzs = new float[svCount]; 430 float[] elevations = new float[svCount]; 431 float[] azimuths = new float[svCount]; 432 float[] carrierFrequencies = new float[svCount]; 433 float[] basebandCn0DbHzs = new float[svCount]; 434 435 for (int i = 0; i < svidWithFlags.length; i++) { 436 svidWithFlags[i] = mSatellites.get(i).mSvidWithFlags; 437 } 438 for (int i = 0; i < cn0DbHzs.length; i++) { 439 cn0DbHzs[i] = mSatellites.get(i).mCn0DbHz; 440 } 441 for (int i = 0; i < elevations.length; i++) { 442 elevations[i] = mSatellites.get(i).mElevation; 443 } 444 for (int i = 0; i < azimuths.length; i++) { 445 azimuths[i] = mSatellites.get(i).mAzimuth; 446 } 447 for (int i = 0; i < carrierFrequencies.length; i++) { 448 carrierFrequencies[i] = mSatellites.get(i).mCarrierFrequency; 449 } 450 for (int i = 0; i < basebandCn0DbHzs.length; i++) { 451 basebandCn0DbHzs[i] = mSatellites.get(i).mBasebandCn0DbHz; 452 } 453 454 return wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths, 455 carrierFrequencies, basebandCn0DbHzs); 456 } 457 } 458 459 private static class GnssSvInfo { 460 461 private final int mSvidWithFlags; 462 private final float mCn0DbHz; 463 private final float mElevation; 464 private final float mAzimuth; 465 private final float mCarrierFrequency; 466 private final float mBasebandCn0DbHz; 467 GnssSvInfo(int constellationType, int svid, float cn0DbHz, float elevation, float azimuth, boolean hasEphemeris, boolean hasAlmanac, boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency, boolean hasBasebandCn0DbHz, float basebandCn0DbHz)468 private GnssSvInfo(int constellationType, int svid, float cn0DbHz, 469 float elevation, float azimuth, boolean hasEphemeris, boolean hasAlmanac, 470 boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency, 471 boolean hasBasebandCn0DbHz, float basebandCn0DbHz) { 472 mSvidWithFlags = (svid << SVID_SHIFT_WIDTH) 473 | ((constellationType & CONSTELLATION_TYPE_MASK) 474 << CONSTELLATION_TYPE_SHIFT_WIDTH) 475 | (hasEphemeris ? SVID_FLAGS_HAS_EPHEMERIS_DATA : SVID_FLAGS_NONE) 476 | (hasAlmanac ? SVID_FLAGS_HAS_ALMANAC_DATA : SVID_FLAGS_NONE) 477 | (usedInFix ? SVID_FLAGS_USED_IN_FIX : SVID_FLAGS_NONE) 478 | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE) 479 | (hasBasebandCn0DbHz ? SVID_FLAGS_HAS_BASEBAND_CN0 : SVID_FLAGS_NONE); 480 mCn0DbHz = cn0DbHz; 481 mElevation = elevation; 482 mAzimuth = azimuth; 483 mCarrierFrequency = hasCarrierFrequency ? carrierFrequency : 0; 484 mBasebandCn0DbHz = hasBasebandCn0DbHz ? basebandCn0DbHz : 0; 485 } 486 } 487 } 488