Location.java revision 54ca7aef2e12b240caa6fb1a1e65abd234bea337
1/*
2 * Copyright (C) 2007 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.os.Bundle;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.os.SystemClock;
23import android.util.Printer;
24import android.util.TimeUtils;
25
26import java.text.DecimalFormat;
27import java.util.StringTokenizer;
28
29/**
30 * A data class representing a geographic location.
31 *
32 * <p>A location can consist of a latitude, longitude, timestamp,
33 * and other information such as bearing, altitude and velocity.
34 *
35 * <p>All locations generated by the {@link LocationManager} are
36 * guaranteed to have a valid latitude, longitude, and timestamp
37 * (both UTC time and elapsed real-time since boot), all other
38 * parameters are optional.
39 */
40public class Location implements Parcelable {
41    /**
42     * Constant used to specify formatting of a latitude or longitude
43     * in the form "[+-]DDD.DDDDD where D indicates degrees.
44     */
45    public static final int FORMAT_DEGREES = 0;
46
47    /**
48     * Constant used to specify formatting of a latitude or longitude
49     * in the form "[+-]DDD:MM.MMMMM" where D indicates degrees and
50     * M indicates minutes of arc (1 minute = 1/60th of a degree).
51     */
52    public static final int FORMAT_MINUTES = 1;
53
54    /**
55     * Constant used to specify formatting of a latitude or longitude
56     * in the form "DDD:MM:SS.SSSSS" where D indicates degrees, M
57     * indicates minutes of arc, and S indicates seconds of arc (1
58     * minute = 1/60th of a degree, 1 second = 1/3600th of a degree).
59     */
60    public static final int FORMAT_SECONDS = 2;
61
62    /**
63     * Bundle key for a version of the location that has been fed through
64     * LocationFudger. Allows location providers to flag locations as being
65     * safe for use with ACCESS_COARSE_LOCATION permission.
66     *
67     * @hide
68     */
69    public static final String EXTRA_COARSE_LOCATION = "coarseLocation";
70
71    /**
72     * Bundle key for a version of the location containing no GPS data.
73     * Allows location providers to flag locations as being safe to
74     * feed to LocationFudger.
75     *
76     * @hide
77     */
78    public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
79
80    private String mProvider;
81    private long mTime = 0;
82    private long mElapsedRealtimeNanos = 0;
83    private double mLatitude = 0.0;
84    private double mLongitude = 0.0;
85    private boolean mHasAltitude = false;
86    private double mAltitude = 0.0f;
87    private boolean mHasSpeed = false;
88    private float mSpeed = 0.0f;
89    private boolean mHasBearing = false;
90    private float mBearing = 0.0f;
91    private boolean mHasAccuracy = false;
92    private float mAccuracy = 0.0f;
93    private Bundle mExtras = null;
94    private boolean mIsFromMockProvider = false;
95
96    // Cache the inputs and outputs of computeDistanceAndBearing
97    // so calls to distanceTo() and bearingTo() can share work
98    private double mLat1 = 0.0;
99    private double mLon1 = 0.0;
100    private double mLat2 = 0.0;
101    private double mLon2 = 0.0;
102    private float mDistance = 0.0f;
103    private float mInitialBearing = 0.0f;
104    // Scratchpad
105    private final float[] mResults = new float[2];
106
107    /**
108     * Construct a new Location with a named provider.
109     *
110     * <p>By default time, latitude and longitude are 0, and the location
111     * has no bearing, altitude, speed, accuracy or extras.
112     *
113     * @param provider the name of the provider that generated this location
114     */
115    public Location(String provider) {
116        mProvider = provider;
117    }
118
119    /**
120     * Construct a new Location object that is copied from an existing one.
121     */
122    public Location(Location l) {
123        set(l);
124    }
125
126    /**
127     * Sets the contents of the location to the values from the given location.
128     */
129    public void set(Location l) {
130        mProvider = l.mProvider;
131        mTime = l.mTime;
132        mElapsedRealtimeNanos = l.mElapsedRealtimeNanos;
133        mLatitude = l.mLatitude;
134        mLongitude = l.mLongitude;
135        mHasAltitude = l.mHasAltitude;
136        mAltitude = l.mAltitude;
137        mHasSpeed = l.mHasSpeed;
138        mSpeed = l.mSpeed;
139        mHasBearing = l.mHasBearing;
140        mBearing = l.mBearing;
141        mHasAccuracy = l.mHasAccuracy;
142        mAccuracy = l.mAccuracy;
143        mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
144        mIsFromMockProvider = l.mIsFromMockProvider;
145    }
146
147    /**
148     * Clears the contents of the location.
149     */
150    public void reset() {
151        mProvider = null;
152        mTime = 0;
153        mElapsedRealtimeNanos = 0;
154        mLatitude = 0;
155        mLongitude = 0;
156        mHasAltitude = false;
157        mAltitude = 0;
158        mHasSpeed = false;
159        mSpeed = 0;
160        mHasBearing = false;
161        mBearing = 0;
162        mHasAccuracy = false;
163        mAccuracy = 0;
164        mExtras = null;
165        mIsFromMockProvider = false;
166    }
167
168    /**
169     * Converts a coordinate to a String representation. The outputType
170     * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
171     * The coordinate must be a valid double between -180.0 and 180.0.
172     *
173     * @throws IllegalArgumentException if coordinate is less than
174     * -180.0, greater than 180.0, or is not a number.
175     * @throws IllegalArgumentException if outputType is not one of
176     * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
177     */
178    public static String convert(double coordinate, int outputType) {
179        if (coordinate < -180.0 || coordinate > 180.0 ||
180            Double.isNaN(coordinate)) {
181            throw new IllegalArgumentException("coordinate=" + coordinate);
182        }
183        if ((outputType != FORMAT_DEGREES) &&
184            (outputType != FORMAT_MINUTES) &&
185            (outputType != FORMAT_SECONDS)) {
186            throw new IllegalArgumentException("outputType=" + outputType);
187        }
188
189        StringBuilder sb = new StringBuilder();
190
191        // Handle negative values
192        if (coordinate < 0) {
193            sb.append('-');
194            coordinate = -coordinate;
195        }
196
197        DecimalFormat df = new DecimalFormat("###.#####");
198        if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) {
199            int degrees = (int) Math.floor(coordinate);
200            sb.append(degrees);
201            sb.append(':');
202            coordinate -= degrees;
203            coordinate *= 60.0;
204            if (outputType == FORMAT_SECONDS) {
205                int minutes = (int) Math.floor(coordinate);
206                sb.append(minutes);
207                sb.append(':');
208                coordinate -= minutes;
209                coordinate *= 60.0;
210            }
211        }
212        sb.append(df.format(coordinate));
213        return sb.toString();
214    }
215
216    /**
217     * Converts a String in one of the formats described by
218     * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a
219     * double.
220     *
221     * @throws NullPointerException if coordinate is null
222     * @throws IllegalArgumentException if the coordinate is not
223     * in one of the valid formats.
224     */
225    public static double convert(String coordinate) {
226        // IllegalArgumentException if bad syntax
227        if (coordinate == null) {
228            throw new NullPointerException("coordinate");
229        }
230
231        boolean negative = false;
232        if (coordinate.charAt(0) == '-') {
233            coordinate = coordinate.substring(1);
234            negative = true;
235        }
236
237        StringTokenizer st = new StringTokenizer(coordinate, ":");
238        int tokens = st.countTokens();
239        if (tokens < 1) {
240            throw new IllegalArgumentException("coordinate=" + coordinate);
241        }
242        try {
243            String degrees = st.nextToken();
244            double val;
245            if (tokens == 1) {
246                val = Double.parseDouble(degrees);
247                return negative ? -val : val;
248            }
249
250            String minutes = st.nextToken();
251            int deg = Integer.parseInt(degrees);
252            double min;
253            double sec = 0.0;
254
255            if (st.hasMoreTokens()) {
256                min = Integer.parseInt(minutes);
257                String seconds = st.nextToken();
258                sec = Double.parseDouble(seconds);
259            } else {
260                min = Double.parseDouble(minutes);
261            }
262
263            boolean isNegative180 = negative && (deg == 180) &&
264                (min == 0) && (sec == 0);
265
266            // deg must be in [0, 179] except for the case of -180 degrees
267            if ((deg < 0.0) || (deg > 179 && !isNegative180)) {
268                throw new IllegalArgumentException("coordinate=" + coordinate);
269            }
270            if (min < 0 || min > 59) {
271                throw new IllegalArgumentException("coordinate=" +
272                        coordinate);
273            }
274            if (sec < 0 || sec > 59) {
275                throw new IllegalArgumentException("coordinate=" +
276                        coordinate);
277            }
278
279            val = deg*3600.0 + min*60.0 + sec;
280            val /= 3600.0;
281            return negative ? -val : val;
282        } catch (NumberFormatException nfe) {
283            throw new IllegalArgumentException("coordinate=" + coordinate);
284        }
285    }
286
287    private static void computeDistanceAndBearing(double lat1, double lon1,
288        double lat2, double lon2, float[] results) {
289        // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
290        // using the "Inverse Formula" (section 4)
291
292        int MAXITERS = 20;
293        // Convert lat/long to radians
294        lat1 *= Math.PI / 180.0;
295        lat2 *= Math.PI / 180.0;
296        lon1 *= Math.PI / 180.0;
297        lon2 *= Math.PI / 180.0;
298
299        double a = 6378137.0; // WGS84 major axis
300        double b = 6356752.3142; // WGS84 semi-major axis
301        double f = (a - b) / a;
302        double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
303
304        double L = lon2 - lon1;
305        double A = 0.0;
306        double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
307        double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
308
309        double cosU1 = Math.cos(U1);
310        double cosU2 = Math.cos(U2);
311        double sinU1 = Math.sin(U1);
312        double sinU2 = Math.sin(U2);
313        double cosU1cosU2 = cosU1 * cosU2;
314        double sinU1sinU2 = sinU1 * sinU2;
315
316        double sigma = 0.0;
317        double deltaSigma = 0.0;
318        double cosSqAlpha = 0.0;
319        double cos2SM = 0.0;
320        double cosSigma = 0.0;
321        double sinSigma = 0.0;
322        double cosLambda = 0.0;
323        double sinLambda = 0.0;
324
325        double lambda = L; // initial guess
326        for (int iter = 0; iter < MAXITERS; iter++) {
327            double lambdaOrig = lambda;
328            cosLambda = Math.cos(lambda);
329            sinLambda = Math.sin(lambda);
330            double t1 = cosU2 * sinLambda;
331            double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
332            double sinSqSigma = t1 * t1 + t2 * t2; // (14)
333            sinSigma = Math.sqrt(sinSqSigma);
334            cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
335            sigma = Math.atan2(sinSigma, cosSigma); // (16)
336            double sinAlpha = (sinSigma == 0) ? 0.0 :
337                cosU1cosU2 * sinLambda / sinSigma; // (17)
338            cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
339            cos2SM = (cosSqAlpha == 0) ? 0.0 :
340                cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
341
342            double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
343            A = 1 + (uSquared / 16384.0) * // (3)
344                (4096.0 + uSquared *
345                 (-768 + uSquared * (320.0 - 175.0 * uSquared)));
346            double B = (uSquared / 1024.0) * // (4)
347                (256.0 + uSquared *
348                 (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
349            double C = (f / 16.0) *
350                cosSqAlpha *
351                (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
352            double cos2SMSq = cos2SM * cos2SM;
353            deltaSigma = B * sinSigma * // (6)
354                (cos2SM + (B / 4.0) *
355                 (cosSigma * (-1.0 + 2.0 * cos2SMSq) -
356                  (B / 6.0) * cos2SM *
357                  (-3.0 + 4.0 * sinSigma * sinSigma) *
358                  (-3.0 + 4.0 * cos2SMSq)));
359
360            lambda = L +
361                (1.0 - C) * f * sinAlpha *
362                (sigma + C * sinSigma *
363                 (cos2SM + C * cosSigma *
364                  (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
365
366            double delta = (lambda - lambdaOrig) / lambda;
367            if (Math.abs(delta) < 1.0e-12) {
368                break;
369            }
370        }
371
372        float distance = (float) (b * A * (sigma - deltaSigma));
373        results[0] = distance;
374        if (results.length > 1) {
375            float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
376                cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
377            initialBearing *= 180.0 / Math.PI;
378            results[1] = initialBearing;
379            if (results.length > 2) {
380                float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
381                    -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
382                finalBearing *= 180.0 / Math.PI;
383                results[2] = finalBearing;
384            }
385        }
386    }
387
388    /**
389     * Computes the approximate distance in meters between two
390     * locations, and optionally the initial and final bearings of the
391     * shortest path between them.  Distance and bearing are defined using the
392     * WGS84 ellipsoid.
393     *
394     * <p> The computed distance is stored in results[0].  If results has length
395     * 2 or greater, the initial bearing is stored in results[1]. If results has
396     * length 3 or greater, the final bearing is stored in results[2].
397     *
398     * @param startLatitude the starting latitude
399     * @param startLongitude the starting longitude
400     * @param endLatitude the ending latitude
401     * @param endLongitude the ending longitude
402     * @param results an array of floats to hold the results
403     *
404     * @throws IllegalArgumentException if results is null or has length < 1
405     */
406    public static void distanceBetween(double startLatitude, double startLongitude,
407        double endLatitude, double endLongitude, float[] results) {
408        if (results == null || results.length < 1) {
409            throw new IllegalArgumentException("results is null or has length < 1");
410        }
411        computeDistanceAndBearing(startLatitude, startLongitude,
412            endLatitude, endLongitude, results);
413    }
414
415    /**
416     * Returns the approximate distance in meters between this
417     * location and the given location.  Distance is defined using
418     * the WGS84 ellipsoid.
419     *
420     * @param dest the destination location
421     * @return the approximate distance in meters
422     */
423    public float distanceTo(Location dest) {
424        // See if we already have the result
425        synchronized (mResults) {
426            if (mLatitude != mLat1 || mLongitude != mLon1 ||
427                dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
428                computeDistanceAndBearing(mLatitude, mLongitude,
429                    dest.mLatitude, dest.mLongitude, mResults);
430                mLat1 = mLatitude;
431                mLon1 = mLongitude;
432                mLat2 = dest.mLatitude;
433                mLon2 = dest.mLongitude;
434                mDistance = mResults[0];
435                mInitialBearing = mResults[1];
436            }
437            return mDistance;
438        }
439    }
440
441    /**
442     * Returns the approximate initial bearing in degrees East of true
443     * North when traveling along the shortest path between this
444     * location and the given location.  The shortest path is defined
445     * using the WGS84 ellipsoid.  Locations that are (nearly)
446     * antipodal may produce meaningless results.
447     *
448     * @param dest the destination location
449     * @return the initial bearing in degrees
450     */
451    public float bearingTo(Location dest) {
452        synchronized (mResults) {
453            // See if we already have the result
454            if (mLatitude != mLat1 || mLongitude != mLon1 ||
455                            dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
456                computeDistanceAndBearing(mLatitude, mLongitude,
457                    dest.mLatitude, dest.mLongitude, mResults);
458                mLat1 = mLatitude;
459                mLon1 = mLongitude;
460                mLat2 = dest.mLatitude;
461                mLon2 = dest.mLongitude;
462                mDistance = mResults[0];
463                mInitialBearing = mResults[1];
464            }
465            return mInitialBearing;
466        }
467    }
468
469    /**
470     * Returns the name of the provider that generated this fix.
471     *
472     * @return the provider, or null if it has not been set
473     */
474    public String getProvider() {
475        return mProvider;
476    }
477
478    /**
479     * Sets the name of the provider that generated this fix.
480     */
481    public void setProvider(String provider) {
482        mProvider = provider;
483    }
484
485    /**
486     * Return the UTC time of this fix, in milliseconds since January 1, 1970.
487     *
488     * <p>Note that the UTC time on a device is not monotonic: it
489     * can jump forwards or backwards unpredictably. So always use
490     * {@link #getElapsedRealtimeNanos} when calculating time deltas.
491     *
492     * <p>On the other hand, {@link #getTime} is useful for presenting
493     * a human readable time to the user, or for carefully comparing
494     * location fixes across reboot or across devices.
495     *
496     * <p>All locations generated by the {@link LocationManager}
497     * are guaranteed to have a valid UTC time, however remember that
498     * the system time may have changed since the location was generated.
499     *
500     * @return time of fix, in milliseconds since January 1, 1970.
501     */
502    public long getTime() {
503        return mTime;
504    }
505
506    /**
507     * Set the UTC time of this fix, in milliseconds since January 1,
508     * 1970.
509     *
510     * @param time UTC time of this fix, in milliseconds since January 1, 1970
511     */
512    public void setTime(long time) {
513        mTime = time;
514    }
515
516    /**
517     * Return the time of this fix, in elapsed real-time since system boot.
518     *
519     * <p>This value can be reliably compared to
520     * {@link android.os.SystemClock#elapsedRealtimeNanos},
521     * to calculate the age of a fix and to compare Location fixes. This
522     * is reliable because elapsed real-time is guaranteed monotonic for
523     * each system boot and continues to increment even when the system
524     * is in deep sleep (unlike {@link #getTime}.
525     *
526     * <p>All locations generated by the {@link LocationManager}
527     * are guaranteed to have a valid elapsed real-time.
528     *
529     * @return elapsed real-time of fix, in nanoseconds since system boot.
530     */
531    public long getElapsedRealtimeNanos() {
532        return mElapsedRealtimeNanos;
533    }
534
535    /**
536     * Set the time of this fix, in elapsed real-time since system boot.
537     *
538     * @param time elapsed real-time of fix, in nanoseconds since system boot.
539     */
540    public void setElapsedRealtimeNanos(long time) {
541        mElapsedRealtimeNanos = time;
542    }
543
544    /**
545     * Get the latitude, in degrees.
546     *
547     * <p>All locations generated by the {@link LocationManager}
548     * will have a valid latitude.
549     */
550    public double getLatitude() {
551        return mLatitude;
552    }
553
554    /**
555     * Set the latitude, in degrees.
556     */
557    public void setLatitude(double latitude) {
558        mLatitude = latitude;
559    }
560
561    /**
562     * Get the longitude, in degrees.
563     *
564     * <p>All locations generated by the {@link LocationManager}
565     * will have a valid longitude.
566     */
567    public double getLongitude() {
568        return mLongitude;
569    }
570
571    /**
572     * Set the longitude, in degrees.
573     */
574    public void setLongitude(double longitude) {
575        mLongitude = longitude;
576    }
577
578    /**
579     * True if this location has an altitude.
580     */
581    public boolean hasAltitude() {
582        return mHasAltitude;
583    }
584
585    /**
586     * Get the altitude if available, in meters above sea level.
587     *
588     * <p>If this location does not have an altitude then 0.0 is returned.
589     */
590    public double getAltitude() {
591        return mAltitude;
592    }
593
594    /**
595     * Set the altitude, in meters above sea level.
596     *
597     * <p>Following this call {@link #hasAltitude} will return true.
598     */
599    public void setAltitude(double altitude) {
600        mAltitude = altitude;
601        mHasAltitude = true;
602    }
603
604    /**
605     * Remove the altitude from this location.
606     *
607     * <p>Following this call {@link #hasAltitude} will return false,
608     * and {@link #getAltitude} will return 0.0.
609     */
610    public void removeAltitude() {
611        mAltitude = 0.0f;
612        mHasAltitude = false;
613    }
614
615    /**
616     * True if this location has a speed.
617     */
618    public boolean hasSpeed() {
619        return mHasSpeed;
620    }
621
622    /**
623     * Get the speed if it is available, in meters/second over ground.
624     *
625     * <p>If this location does not have a speed then 0.0 is returned.
626     */
627    public float getSpeed() {
628        return mSpeed;
629    }
630
631    /**
632     * Set the speed, in meters/second over ground.
633     *
634     * <p>Following this call {@link #hasSpeed} will return true.
635     */
636    public void setSpeed(float speed) {
637        mSpeed = speed;
638        mHasSpeed = true;
639    }
640
641    /**
642     * Remove the speed from this location.
643     *
644     * <p>Following this call {@link #hasSpeed} will return false,
645     * and {@link #getSpeed} will return 0.0.
646     */
647    public void removeSpeed() {
648        mSpeed = 0.0f;
649        mHasSpeed = false;
650    }
651
652    /**
653     * True if this location has a bearing.
654     */
655    public boolean hasBearing() {
656        return mHasBearing;
657    }
658
659    /**
660     * Get the bearing, in degrees.
661     *
662     * <p>Bearing is the horizontal direction of travel of this device,
663     * and is not related to the device orientation. It is guaranteed to
664     * be in the range (0.0, 360.0] if the device has a bearing.
665     *
666     * <p>If this location does not have a bearing then 0.0 is returned.
667     */
668    public float getBearing() {
669        return mBearing;
670    }
671
672    /**
673     * Set the bearing, in degrees.
674     *
675     * <p>Bearing is the horizontal direction of travel of this device,
676     * and is not related to the device orientation.
677     *
678     * <p>The input will be wrapped into the range (0.0, 360.0].
679     */
680    public void setBearing(float bearing) {
681        while (bearing < 0.0f) {
682            bearing += 360.0f;
683        }
684        while (bearing >= 360.0f) {
685            bearing -= 360.0f;
686        }
687        mBearing = bearing;
688        mHasBearing = true;
689    }
690
691    /**
692     * Remove the bearing from this location.
693     *
694     * <p>Following this call {@link #hasBearing} will return false,
695     * and {@link #getBearing} will return 0.0.
696     */
697    public void removeBearing() {
698        mBearing = 0.0f;
699        mHasBearing = false;
700    }
701
702    /**
703     * True if this location has an accuracy.
704     *
705     * <p>All locations generated by the {@link LocationManager} have an
706     * accuracy.
707     */
708    public boolean hasAccuracy() {
709        return mHasAccuracy;
710    }
711
712    /**
713     * Get the estimated accuracy of this location, in meters.
714     *
715     * <p>We define accuracy as the radius of 68% confidence. In other
716     * words, if you draw a circle centered at this location's
717     * latitude and longitude, and with a radius equal to the accuracy,
718     * then there is a 68% probability that the true location is inside
719     * the circle.
720     *
721     * <p>In statistical terms, it is assumed that location errors
722     * are random with a normal distribution, so the 68% confidence circle
723     * represents one standard deviation. Note that in practice, location
724     * errors do not always follow such a simple distribution.
725     *
726     * <p>This accuracy estimation is only concerned with horizontal
727     * accuracy, and does not indicate the accuracy of bearing,
728     * velocity or altitude if those are included in this Location.
729     *
730     * <p>If this location does not have an accuracy, then 0.0 is returned.
731     * All locations generated by the {@link LocationManager} include
732     * an accuracy.
733     */
734    public float getAccuracy() {
735        return mAccuracy;
736    }
737
738    /**
739     * Set the estimated accuracy of this location, meters.
740     *
741     * <p>See {@link #getAccuracy} for the definition of accuracy.
742     *
743     * <p>Following this call {@link #hasAccuracy} will return true.
744     */
745    public void setAccuracy(float accuracy) {
746        mAccuracy = accuracy;
747        mHasAccuracy = true;
748    }
749
750    /**
751     * Remove the accuracy from this location.
752     *
753     * <p>Following this call {@link #hasAccuracy} will return false, and
754     * {@link #getAccuracy} will return 0.0.
755     */
756    public void removeAccuracy() {
757        mAccuracy = 0.0f;
758        mHasAccuracy = false;
759    }
760
761    /**
762     * Return true if this Location object is complete.
763     *
764     * <p>A location object is currently considered complete if it has
765     * a valid provider, accuracy, wall-clock time and elapsed real-time.
766     *
767     * <p>All locations supplied by the {@link LocationManager} to
768     * applications must be complete.
769     *
770     * @see #makeComplete
771     * @hide
772     */
773    public boolean isComplete() {
774        if (mProvider == null) return false;
775        if (!mHasAccuracy) return false;
776        if (mTime == 0) return false;
777        if (mElapsedRealtimeNanos == 0) return false;
778        return true;
779    }
780
781    /**
782     * Helper to fill incomplete fields.
783     *
784     * <p>Used to assist in backwards compatibility with
785     * Location objects received from applications.
786     *
787     * @see #isComplete
788     * @hide
789     */
790    public void makeComplete() {
791        if (mProvider == null) mProvider = "?";
792        if (!mHasAccuracy) {
793            mHasAccuracy = true;
794            mAccuracy = 100.0f;
795        }
796        if (mTime == 0) mTime = System.currentTimeMillis();
797        if (mElapsedRealtimeNanos == 0) mElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
798    }
799
800    /**
801     * Returns additional provider-specific information about the
802     * location fix as a Bundle.  The keys and values are determined
803     * by the provider.  If no additional information is available,
804     * null is returned.
805     *
806     * <p> A number of common key/value pairs are listed
807     * below. Providers that use any of the keys on this list must
808     * provide the corresponding value as described below.
809     *
810     * <ul>
811     * <li> satellites - the number of satellites used to derive the fix
812     * </ul>
813     */
814    public Bundle getExtras() {
815        return mExtras;
816    }
817
818    /**
819     * Sets the extra information associated with this fix to the
820     * given Bundle.
821     */
822    public void setExtras(Bundle extras) {
823        mExtras = (extras == null) ? null : new Bundle(extras);
824    }
825
826    @Override
827    public String toString() {
828        StringBuilder s = new StringBuilder();
829        s.append("Location[");
830        s.append(mProvider);
831        s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
832        if (mHasAccuracy) s.append(String.format(" acc=%.0f", mAccuracy));
833        else s.append(" acc=???");
834        if (mTime == 0) {
835            s.append(" t=?!?");
836        }
837        if (mElapsedRealtimeNanos == 0) {
838            s.append(" et=?!?");
839        } else {
840            s.append(" et=");
841            TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
842        }
843        if (mHasAltitude) s.append(" alt=").append(mAltitude);
844        if (mHasSpeed) s.append(" vel=").append(mSpeed);
845        if (mHasBearing) s.append(" bear=").append(mBearing);
846        if (mIsFromMockProvider) s.append(" mock");
847
848        if (mExtras != null) {
849            s.append(" {").append(mExtras).append('}');
850        }
851        s.append(']');
852        return s.toString();
853    }
854
855    public void dump(Printer pw, String prefix) {
856        pw.println(prefix + toString());
857    }
858
859    public static final Parcelable.Creator<Location> CREATOR =
860        new Parcelable.Creator<Location>() {
861        @Override
862        public Location createFromParcel(Parcel in) {
863            String provider = in.readString();
864            Location l = new Location(provider);
865            l.mTime = in.readLong();
866            l.mElapsedRealtimeNanos = in.readLong();
867            l.mLatitude = in.readDouble();
868            l.mLongitude = in.readDouble();
869            l.mHasAltitude = in.readInt() != 0;
870            l.mAltitude = in.readDouble();
871            l.mHasSpeed = in.readInt() != 0;
872            l.mSpeed = in.readFloat();
873            l.mHasBearing = in.readInt() != 0;
874            l.mBearing = in.readFloat();
875            l.mHasAccuracy = in.readInt() != 0;
876            l.mAccuracy = in.readFloat();
877            l.mExtras = in.readBundle();
878            l.mIsFromMockProvider = in.readInt() != 0;
879            return l;
880        }
881
882        @Override
883        public Location[] newArray(int size) {
884            return new Location[size];
885        }
886    };
887
888    @Override
889    public int describeContents() {
890        return 0;
891    }
892
893    @Override
894    public void writeToParcel(Parcel parcel, int flags) {
895        parcel.writeString(mProvider);
896        parcel.writeLong(mTime);
897        parcel.writeLong(mElapsedRealtimeNanos);
898        parcel.writeDouble(mLatitude);
899        parcel.writeDouble(mLongitude);
900        parcel.writeInt(mHasAltitude ? 1 : 0);
901        parcel.writeDouble(mAltitude);
902        parcel.writeInt(mHasSpeed ? 1 : 0);
903        parcel.writeFloat(mSpeed);
904        parcel.writeInt(mHasBearing ? 1 : 0);
905        parcel.writeFloat(mBearing);
906        parcel.writeInt(mHasAccuracy ? 1 : 0);
907        parcel.writeFloat(mAccuracy);
908        parcel.writeBundle(mExtras);
909        parcel.writeInt(mIsFromMockProvider? 1 : 0);
910    }
911
912    /**
913     * Returns one of the optional extra {@link Location}s that can be attached
914     * to this Location.
915     *
916     * @param key the key associated with the desired extra Location
917     * @return the extra Location, or null if unavailable
918     * @hide
919     */
920    public Location getExtraLocation(String key) {
921        if (mExtras != null) {
922            Parcelable value = mExtras.getParcelable(key);
923            if (value instanceof Location) {
924                return (Location) value;
925            }
926        }
927        return null;
928    }
929
930    /**
931     * Attaches an extra {@link Location} to this Location.
932     *
933     * @param key the key associated with the Location extra
934     * @param location the Location to attach
935     * @hide
936     */
937    public void setExtraLocation(String key, Location value) {
938        if (mExtras == null) {
939            mExtras = new Bundle();
940        }
941        mExtras.putParcelable(key, value);
942    }
943
944    /**
945     * Returns true if the Location came from a mock provider.
946     *
947     * @return true if this Location came from a mock provider, false otherwise
948     */
949    public boolean isFromMockProvider() {
950        return mIsFromMockProvider;
951    }
952
953    /**
954     * Flag this Location as having come from a mock provider or not.
955     *
956     * @param isFromMockProvider true if this Location came from a mock provider, false otherwise
957     * @hide
958     */
959    public void setIsFromMockProvider(boolean isFromMockProvider) {
960        mIsFromMockProvider = isFromMockProvider;
961    }
962}
963