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