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