• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.SparseArray;
20 
21 import java.util.Iterator;
22 import java.util.NoSuchElementException;
23 
24 
25 /**
26  * This class represents the current state of the GPS engine.
27  * This class is used in conjunction with the {@link Listener} interface.
28  */
29 public final class GpsStatus {
30     private static final int NUM_SATELLITES = 255;
31 
32     /* These package private values are modified by the LocationManager class */
33     private int mTimeToFirstFix;
34     private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
35 
36     private final class SatelliteIterator implements Iterator<GpsSatellite> {
37 
38         private final SparseArray<GpsSatellite> mSatellites;
39         private final int mSatellitesCount;
40 
41         private int mIndex = 0;
42 
SatelliteIterator(SparseArray<GpsSatellite> satellites)43         SatelliteIterator(SparseArray<GpsSatellite> satellites) {
44             mSatellites = satellites;
45             mSatellitesCount = satellites.size();
46         }
47 
hasNext()48         public boolean hasNext() {
49             for (; mIndex < mSatellitesCount; ++mIndex) {
50                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
51                 if (satellite.mValid) {
52                     return true;
53                 }
54             }
55             return false;
56         }
57 
next()58         public GpsSatellite next() {
59             while (mIndex < mSatellitesCount) {
60                 GpsSatellite satellite = mSatellites.valueAt(mIndex);
61                 ++mIndex;
62                 if (satellite.mValid) {
63                     return satellite;
64                 }
65             }
66             throw new NoSuchElementException();
67         }
68 
remove()69         public void remove() {
70             throw new UnsupportedOperationException();
71         }
72     }
73 
74     private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
75         public Iterator<GpsSatellite> iterator() {
76             return new SatelliteIterator(mSatellites);
77         }
78     };
79 
80     /**
81      * Event sent when the GPS system has started.
82      */
83     public static final int GPS_EVENT_STARTED = 1;
84 
85     /**
86      * Event sent when the GPS system has stopped.
87      */
88     public static final int GPS_EVENT_STOPPED = 2;
89 
90     /**
91      * Event sent when the GPS system has received its first fix since starting.
92      * Call {@link #getTimeToFirstFix()} to find the time from start to first fix.
93      */
94     public static final int GPS_EVENT_FIRST_FIX = 3;
95 
96     /**
97      * Event sent periodically to report GPS satellite status.
98      * Call {@link #getSatellites()} to retrieve the status for each satellite.
99      */
100     public static final int GPS_EVENT_SATELLITE_STATUS = 4;
101 
102     /**
103      * Used for receiving notifications when GPS status has changed.
104      */
105     public interface Listener {
106         /**
107          * Called to report changes in the GPS status.
108          * The event number is one of:
109          * <ul>
110          * <li> {@link GpsStatus#GPS_EVENT_STARTED}
111          * <li> {@link GpsStatus#GPS_EVENT_STOPPED}
112          * <li> {@link GpsStatus#GPS_EVENT_FIRST_FIX}
113          * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
114          * </ul>
115          *
116          * When this method is called, the client should call
117          * {@link LocationManager#getGpsStatus} to get additional
118          * status information.
119          *
120          * @param event event number for this notification
121          */
onGpsStatusChanged(int event)122         void onGpsStatusChanged(int event);
123     }
124 
125     /**
126      * Used for receiving NMEA sentences from the GPS.
127      * NMEA 0183 is a standard for communicating with marine electronic devices
128      * and is a common method for receiving data from a GPS, typically over a serial port.
129      * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
130      * You can implement this interface and call {@link LocationManager#addNmeaListener}
131      * to receive NMEA data from the GPS engine.
132      */
133     public interface NmeaListener {
onNmeaReceived(long timestamp, String nmea)134         void onNmeaReceived(long timestamp, String nmea);
135     }
136 
137     // For API-compat a public ctor() is not available
GpsStatus()138     GpsStatus() {}
139 
140     /**
141      * Used internally within {@link LocationManager} to copy GPS status
142      * data from the Location Manager Service to its cached GpsStatus instance.
143      * Is synchronized to ensure that GPS status updates are atomic.
144      */
setStatus(int svCount, int[] prns, float[] snrs, float[] elevations, float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask)145     synchronized void setStatus(int svCount, int[] prns, float[] snrs,
146             float[] elevations, float[] azimuths, int ephemerisMask,
147             int almanacMask, int usedInFixMask) {
148         clearSatellites();
149         for (int i = 0; i < svCount; i++) {
150             int prn = prns[i];
151             int prnShift = (1 << (prn - 1));
152             if (prn > 0 && prn <= NUM_SATELLITES) {
153                 GpsSatellite satellite = mSatellites.get(prn);
154                 if (satellite == null) {
155                     satellite = new GpsSatellite(prn);
156                     mSatellites.put(prn, satellite);
157                 }
158 
159                 satellite.mValid = true;
160                 satellite.mSnr = snrs[i];
161                 satellite.mElevation = elevations[i];
162                 satellite.mAzimuth = azimuths[i];
163                 satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0);
164                 satellite.mHasAlmanac = ((almanacMask & prnShift) != 0);
165                 satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0);
166             }
167         }
168     }
169 
170     /**
171      * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's
172      * cached GpsStatus instance to the client's copy.
173      * Since this method is only used within {@link LocationManager#getGpsStatus},
174      * it does not need to be synchronized.
175      */
setStatus(GpsStatus status)176     void setStatus(GpsStatus status) {
177         mTimeToFirstFix = status.getTimeToFirstFix();
178         clearSatellites();
179 
180         SparseArray<GpsSatellite> otherSatellites = status.mSatellites;
181         int otherSatellitesCount = otherSatellites.size();
182         int satelliteIndex = 0;
183         // merge both sparse arrays, note that we have already invalidated the elements in the
184         // receiver array
185         for (int i = 0; i < otherSatellitesCount; ++i) {
186             GpsSatellite otherSatellite = otherSatellites.valueAt(i);
187             int otherSatellitePrn = otherSatellite.getPrn();
188 
189             int satellitesCount = mSatellites.size();
190             while (satelliteIndex < satellitesCount
191                     && mSatellites.valueAt(satelliteIndex).getPrn() < otherSatellitePrn) {
192                 ++satelliteIndex;
193             }
194 
195             if (satelliteIndex < mSatellites.size()) {
196                 GpsSatellite satellite = mSatellites.valueAt(satelliteIndex);
197                 if (satellite.getPrn() == otherSatellitePrn) {
198                     satellite.setStatus(otherSatellite);
199                 } else {
200                     satellite = new GpsSatellite(otherSatellitePrn);
201                     satellite.setStatus(otherSatellite);
202                     mSatellites.put(otherSatellitePrn, satellite);
203                 }
204             } else {
205                 GpsSatellite satellite = new GpsSatellite(otherSatellitePrn);
206                 satellite.setStatus(otherSatellite);
207                 mSatellites.append(otherSatellitePrn, satellite);
208             }
209         }
210     }
211 
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