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