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