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