GpsStatus.java revision 9363b949a104786c87cd2cd18f206ff3c1957e5e
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
17package android.location;
18
19import android.util.SparseArray;
20
21import java.util.Iterator;
22import 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 */
29public 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        private final int mSatellitesCount;
38
39        private int mIndex = 0;
40
41        SatelliteIterator() {
42            mSatellitesCount = mSatellites.size();
43        }
44
45        @Override
46        public boolean hasNext() {
47            for (; mIndex < mSatellitesCount; ++mIndex) {
48                GpsSatellite satellite = mSatellites.valueAt(mIndex);
49                if (satellite.mValid) {
50                    return true;
51                }
52            }
53            return false;
54        }
55
56        @Override
57        public GpsSatellite next() {
58            while (mIndex < mSatellitesCount) {
59                GpsSatellite satellite = mSatellites.valueAt(mIndex);
60                ++mIndex;
61                if (satellite.mValid) {
62                    return satellite;
63                }
64            }
65            throw new NoSuchElementException();
66        }
67
68        @Override
69        public void remove() {
70            throw new UnsupportedOperationException();
71        }
72    }
73
74    private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
75        @Override
76        public Iterator<GpsSatellite> iterator() {
77            return new SatelliteIterator();
78        }
79    };
80
81    /**
82     * Event sent when the GPS system has started.
83     */
84    public static final int GPS_EVENT_STARTED = 1;
85
86    /**
87     * Event sent when the GPS system has stopped.
88     */
89    public static final int GPS_EVENT_STOPPED = 2;
90
91    /**
92     * Event sent when the GPS system has received its first fix since starting.
93     * Call {@link #getTimeToFirstFix()} to find the time from start to first fix.
94     */
95    public static final int GPS_EVENT_FIRST_FIX = 3;
96
97    /**
98     * Event sent periodically to report GPS satellite status.
99     * Call {@link #getSatellites()} to retrieve the status for each satellite.
100     */
101    public static final int GPS_EVENT_SATELLITE_STATUS = 4;
102
103    /**
104     * Used for receiving notifications when GPS status has changed.
105     */
106    public interface Listener {
107        /**
108         * Called to report changes in the GPS status.
109         * The event number is one of:
110         * <ul>
111         * <li> {@link GpsStatus#GPS_EVENT_STARTED}
112         * <li> {@link GpsStatus#GPS_EVENT_STOPPED}
113         * <li> {@link GpsStatus#GPS_EVENT_FIRST_FIX}
114         * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
115         * </ul>
116         *
117         * When this method is called, the client should call
118         * {@link LocationManager#getGpsStatus} to get additional
119         * status information.
120         *
121         * @param event event number for this notification
122         */
123        void onGpsStatusChanged(int event);
124    }
125
126    /**
127     * Used for receiving NMEA sentences from the GPS.
128     * NMEA 0183 is a standard for communicating with marine electronic devices
129     * and is a common method for receiving data from a GPS, typically over a serial port.
130     * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
131     * You can implement this interface and call {@link LocationManager#addNmeaListener}
132     * to receive NMEA data from the GPS engine.
133     */
134    public interface NmeaListener {
135        void onNmeaReceived(long timestamp, String nmea);
136    }
137
138    // For API-compat a public ctor() is not available
139    GpsStatus() {}
140
141    private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
142            float[] azimuths) {
143        clearSatellites();
144        for (int i = 0; i < svCount; i++) {
145            final int constellationType =
146                    (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
147                    & GnssStatus.CONSTELLATION_TYPE_MASK;
148            // Skip all non-GPS satellites.
149            if (constellationType != GnssStatus.CONSTELLATION_GPS) {
150                continue;
151            }
152            int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
153            if (prn > 0 && prn <= NUM_SATELLITES) {
154                GpsSatellite satellite = mSatellites.get(prn);
155                if (satellite == null) {
156                    satellite = new GpsSatellite(prn);
157                    mSatellites.put(prn, satellite);
158                }
159
160                satellite.mValid = true;
161                satellite.mSnr = snrs[i];
162                satellite.mElevation = elevations[i];
163                satellite.mAzimuth = azimuths[i];
164                satellite.mHasEphemeris =
165                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
166                satellite.mHasAlmanac =
167                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
168                satellite.mUsedInFix =
169                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
170            }
171        }
172    }
173
174    /**
175     * Copies GPS satellites information from GnssStatus object.
176     * Since this method is only used within {@link LocationManager#getGpsStatus},
177     * it does not need to be synchronized.
178     * @hide
179     */
180    void setStatus(GnssStatus status, int timeToFirstFix) {
181        mTimeToFirstFix = timeToFirstFix;
182        setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
183                status.mAzimuths);
184    }
185
186    void setTimeToFirstFix(int ttff) {
187        mTimeToFirstFix = ttff;
188    }
189
190    /**
191     * Returns the time required to receive the first fix since the most recent
192     * restart of the GPS engine.
193     *
194     * @return time to first fix in milliseconds
195     */
196    public int getTimeToFirstFix() {
197        return mTimeToFirstFix;
198    }
199
200    /**
201     * Returns an array of {@link GpsSatellite} objects, which represent the
202     * current state of the GPS engine.
203     *
204     * @return the list of satellites
205     */
206    public Iterable<GpsSatellite> getSatellites() {
207        return mSatelliteList;
208    }
209
210    /**
211     * Returns the maximum number of satellites that can be in the satellite
212     * list that can be returned by {@link #getSatellites()}.
213     *
214     * @return the maximum number of satellites
215     */
216    public int getMaxSatellites() {
217        return NUM_SATELLITES;
218    }
219
220    private void clearSatellites() {
221        int satellitesCount = mSatellites.size();
222        for (int i = 0; i < satellitesCount; i++) {
223            GpsSatellite satellite = mSatellites.valueAt(i);
224            satellite.mValid = false;
225        }
226    }
227}
228