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