1 /*
2  * Copyright (C) 2008 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.compat.annotation.UnsupportedAppUsage;
20 import android.os.Build;
21 import android.util.SparseArray;
22 
23 import java.util.Iterator;
24 import java.util.NoSuchElementException;
25 
26 
27 /**
28  * This class represents the current state of the GPS engine.
29  *
30  * <p>This class is used in conjunction with the {@link Listener} interface.
31  *
32  * @deprecated use {@link GnssStatus} and {@link GnssStatus.Callback}.
33  */
34 @Deprecated
35 public final class GpsStatus {
36     private static final int NUM_SATELLITES = 255;
37     private static final int GLONASS_SVID_OFFSET = 64;
38     private static final int BEIDOU_SVID_OFFSET = 200;
39     private static final int SBAS_SVID_OFFSET = -87;
40 
41     /* These package private values are modified by the LocationManager class */
42     private int mTimeToFirstFix;
43     private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
44 
45     private final class SatelliteIterator implements Iterator<GpsSatellite> {
46         private final int mSatellitesCount;
47 
48         private int mIndex = 0;
49 
SatelliteIterator()50         SatelliteIterator() {
51             mSatellitesCount = mSatellites.size();
52         }
53 
54         @Override
hasNext()55         public boolean hasNext() {
56             for (; mIndex < mSatellitesCount; ++mIndex) {
57                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
58                 if (satellite.mValid) {
59                     return true;
60                 }
61             }
62             return false;
63         }
64 
65         @Override
next()66         public GpsSatellite next() {
67             while (mIndex < mSatellitesCount) {
68                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
69                 ++mIndex;
70                 if (satellite.mValid) {
71                     return satellite;
72                 }
73             }
74             throw new NoSuchElementException();
75         }
76 
77         @Override
remove()78         public void remove() {
79             throw new UnsupportedOperationException();
80         }
81     }
82 
83     private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
84         @Override
85         public Iterator<GpsSatellite> iterator() {
86             return new SatelliteIterator();
87         }
88     };
89 
90     /**
91      * Event sent when the GPS system has started.
92      */
93     public static final int GPS_EVENT_STARTED = 1;
94 
95     /**
96      * Event sent when the GPS system has stopped.
97      */
98     public static final int GPS_EVENT_STOPPED = 2;
99 
100     /**
101      * Event sent when the GPS system has received its first fix since starting.
102      * Call {@link #getTimeToFirstFix()} to find the time from start to first fix.
103      */
104     public static final int GPS_EVENT_FIRST_FIX = 3;
105 
106     /**
107      * Event sent periodically to report GPS satellite status.
108      * Call {@link #getSatellites()} to retrieve the status for each satellite.
109      */
110     public static final int GPS_EVENT_SATELLITE_STATUS = 4;
111 
112     /**
113      * Used for receiving notifications when GPS status has changed.
114      * @deprecated use {@link GnssStatus.Callback} instead.
115      */
116     @Deprecated
117     public interface Listener {
118         /**
119          * Called to report changes in the GPS status.
120          * The event number is one of:
121          * <ul>
122          * <li> {@link GpsStatus#GPS_EVENT_STARTED}
123          * <li> {@link GpsStatus#GPS_EVENT_STOPPED}
124          * <li> {@link GpsStatus#GPS_EVENT_FIRST_FIX}
125          * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
126          * </ul>
127          *
128          * When this method is called, the client should call
129          * {@link LocationManager#getGpsStatus} to get additional
130          * status information.
131          *
132          * @param event event number for this notification
133          */
onGpsStatusChanged(int event)134         void onGpsStatusChanged(int event);
135     }
136 
137     /**
138      * Used for receiving NMEA sentences from the GPS.
139      * NMEA 0183 is a standard for communicating with marine electronic devices
140      * and is a common method for receiving data from a GPS, typically over a serial port.
141      * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
142      * You can implement this interface and call {@link LocationManager#addNmeaListener}
143      * to receive NMEA data from the GPS engine.
144      * @deprecated use {@link OnNmeaMessageListener} instead.
145      */
146     @Deprecated
147     public interface NmeaListener {
onNmeaReceived(long timestamp, String nmea)148         void onNmeaReceived(long timestamp, String nmea);
149     }
150 
151     // For API-compat a public ctor() is not available
GpsStatus()152     GpsStatus() {}
153 
setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations, float[] azimuths)154     private void setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
155             float[] azimuths) {
156         clearSatellites();
157         for (int i = 0; i < svCount; i++) {
158             final int constellationType =
159                     (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
160                     & GnssStatus.CONSTELLATION_TYPE_MASK;
161             int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
162             // Other satellites passed through these APIs before GnssSvStatus was availble.
163             // GPS, SBAS & QZSS can pass through at their nominally
164             // assigned prn number (as long as it fits in the valid 0-255 range below.)
165             // Glonass, and Beidou are passed through with the defacto standard offsets
166             // Other future constellation reporting (e.g. Galileo) needs to use
167             // GnssSvStatus on (N level) HAL & Java layers.
168             if (constellationType == GnssStatus.CONSTELLATION_GLONASS) {
169                 prn += GLONASS_SVID_OFFSET;
170             } else if (constellationType == GnssStatus.CONSTELLATION_BEIDOU) {
171                 prn += BEIDOU_SVID_OFFSET;
172             } else if (constellationType == GnssStatus.CONSTELLATION_SBAS) {
173                 prn += SBAS_SVID_OFFSET;
174             } else if ((constellationType != GnssStatus.CONSTELLATION_GPS) &&
175                     (constellationType != GnssStatus.CONSTELLATION_QZSS)) {
176                 continue;
177             }
178             if (prn > 0 && prn <= NUM_SATELLITES) {
179                 GpsSatellite satellite = mSatellites.get(prn);
180                 if (satellite == null) {
181                     satellite = new GpsSatellite(prn);
182                     mSatellites.put(prn, satellite);
183                 }
184 
185                 satellite.mValid = true;
186                 satellite.mSnr = cn0s[i];
187                 satellite.mElevation = elevations[i];
188                 satellite.mAzimuth = azimuths[i];
189                 satellite.mHasEphemeris =
190                         (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
191                 satellite.mHasAlmanac =
192                         (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
193                 satellite.mUsedInFix =
194                         (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
195             }
196         }
197     }
198 
199     /**
200      * Copies GPS satellites information from GnssStatus object.
201      * Since this method is only used within {@link LocationManager#getGpsStatus},
202      * it does not need to be synchronized.
203      * @hide
204      */
setStatus(GnssStatus status, int timeToFirstFix)205     void setStatus(GnssStatus status, int timeToFirstFix) {
206         mTimeToFirstFix = timeToFirstFix;
207         setStatus(status.mSvCount, status.mSvidWithFlags, status.mCn0DbHz, status.mElevations,
208                 status.mAzimuths);
209     }
210 
211     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
setTimeToFirstFix(int ttff)212     void setTimeToFirstFix(int ttff) {
213         mTimeToFirstFix = ttff;
214     }
215 
216     /**
217      * Returns the time required to receive the first fix since the most recent
218      * restart of the GPS engine.
219      *
220      * @return time to first fix in milliseconds
221      */
getTimeToFirstFix()222     public int getTimeToFirstFix() {
223         return mTimeToFirstFix;
224     }
225 
226     /**
227      * Returns an array of {@link GpsSatellite} objects, which represent the
228      * current state of the GPS engine.
229      *
230      * @return the list of satellites
231      */
getSatellites()232     public Iterable<GpsSatellite> getSatellites() {
233         return mSatelliteList;
234     }
235 
236     /**
237      * Returns the maximum number of satellites that can be in the satellite
238      * list that can be returned by {@link #getSatellites()}.
239      *
240      * @return the maximum number of satellites
241      */
getMaxSatellites()242     public int getMaxSatellites() {
243         return NUM_SATELLITES;
244     }
245 
clearSatellites()246     private void clearSatellites() {
247         int satellitesCount = mSatellites.size();
248         for (int i = 0; i < satellitesCount; i++) {
249             GpsSatellite satellite = mSatellites.valueAt(i);
250             satellite.mValid = false;
251         }
252     }
253 }
254