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