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