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