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