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 &amp; 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