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