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