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