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