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 static java.util.concurrent.TimeUnit.NANOSECONDS; 20 21 import android.annotation.FloatRange; 22 import android.annotation.IntDef; 23 import android.annotation.IntRange; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.SystemApi; 27 import android.os.Bundle; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 import android.os.SystemClock; 31 import android.util.Printer; 32 import android.util.TimeUtils; 33 34 import com.android.internal.util.Preconditions; 35 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.text.DecimalFormat; 39 import java.util.Locale; 40 import java.util.Objects; 41 import java.util.StringTokenizer; 42 43 /** 44 * A data class representing a geographic location. A location consists of a latitude, longitude, 45 * timestamp, accuracy, and other information such as bearing, altitude and velocity. 46 * 47 * <p>All locations generated through {@link LocationManager} are guaranteed to have a valid 48 * latitude, longitude, timestamp (both Unix epoch time and elapsed realtime since boot), and 49 * accuracy. All other parameters are optional. 50 */ 51 public class Location implements Parcelable { 52 53 /** 54 * Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD.DDDDD 55 * where D indicates degrees. 56 */ 57 public static final int FORMAT_DEGREES = 0; 58 59 /** 60 * Constant used to specify formatting of a latitude or longitude in the form "[+-]DDD:MM.MMMMM" 61 * where D indicates degrees and M indicates minutes of arc (1 minute = 1/60th of a degree). 62 */ 63 public static final int FORMAT_MINUTES = 1; 64 65 /** 66 * Constant used to specify formatting of a latitude or longitude in the form "DDD:MM:SS.SSSSS" 67 * where D indicates degrees, M indicates minutes of arc, and S indicates seconds of arc (1 68 * minute = 1/60th of a degree, 1 second = 1/3600th of a degree). 69 */ 70 public static final int FORMAT_SECONDS = 2; 71 72 /** @hide */ 73 @Retention(RetentionPolicy.SOURCE) 74 @IntDef({FORMAT_DEGREES, FORMAT_MINUTES, FORMAT_SECONDS}) 75 public @interface Format {} 76 77 /** 78 * Bundle key for a version of the location containing no GPS data. 79 * 80 * @hide 81 * @deprecated As of Android R, this extra is longer in use, since it is not necessary to keep 82 * gps locations separate from other locations for coarsening. Providers that do not need to 83 * support platforms below Android R should not use this constant. 84 */ 85 @SystemApi 86 @Deprecated 87 public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; 88 89 private static final int HAS_ALTITUDE_MASK = 1 << 0; 90 private static final int HAS_SPEED_MASK = 1 << 1; 91 private static final int HAS_BEARING_MASK = 1 << 2; 92 private static final int HAS_HORIZONTAL_ACCURACY_MASK = 1 << 3; 93 private static final int HAS_MOCK_PROVIDER_MASK = 1 << 4; 94 private static final int HAS_ALTITUDE_ACCURACY_MASK = 1 << 5; 95 private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6; 96 private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7; 97 private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8; 98 99 // Cached data to make bearing/distance computations more efficient for the case 100 // where distanceTo and bearingTo are called in sequence. Assume this typically happens 101 // on the same thread for caching purposes. 102 private static final ThreadLocal<BearingDistanceCache> sBearingDistanceCache = 103 ThreadLocal.withInitial(BearingDistanceCache::new); 104 105 // A bitmask of fields present in this object (see HAS_* constants defined above). 106 private int mFieldsMask = 0; 107 108 private @Nullable String mProvider; 109 private long mTimeMs; 110 private long mElapsedRealtimeNs; 111 private double mElapsedRealtimeUncertaintyNs; 112 private double mLatitudeDegrees; 113 private double mLongitudeDegrees; 114 private float mHorizontalAccuracyMeters; 115 private double mAltitudeMeters; 116 private float mAltitudeAccuracyMeters; 117 private float mSpeedMetersPerSecond; 118 private float mSpeedAccuracyMetersPerSecond; 119 private float mBearingDegrees; 120 private float mBearingAccuracyDegrees; 121 122 private Bundle mExtras = null; 123 124 /** 125 * Constructs a new location with a named provider. By default all values are zero, and no 126 * optional values are present. 127 * 128 * @param provider the location provider name associated with this location 129 */ Location(@ullable String provider)130 public Location(@Nullable String provider) { 131 mProvider = provider; 132 } 133 134 /** 135 * Constructs a new location copied from the given location. 136 */ Location(@onNull Location location)137 public Location(@NonNull Location location) { 138 set(location); 139 } 140 141 /** 142 * Turns this location into a copy of the given location. 143 */ set(@onNull Location location)144 public void set(@NonNull Location location) { 145 mFieldsMask = location.mFieldsMask; 146 mProvider = location.mProvider; 147 mTimeMs = location.mTimeMs; 148 mElapsedRealtimeNs = location.mElapsedRealtimeNs; 149 mElapsedRealtimeUncertaintyNs = location.mElapsedRealtimeUncertaintyNs; 150 mLatitudeDegrees = location.mLatitudeDegrees; 151 mLongitudeDegrees = location.mLongitudeDegrees; 152 mHorizontalAccuracyMeters = location.mHorizontalAccuracyMeters; 153 mAltitudeMeters = location.mAltitudeMeters; 154 mAltitudeAccuracyMeters = location.mAltitudeAccuracyMeters; 155 mSpeedMetersPerSecond = location.mSpeedMetersPerSecond; 156 mSpeedAccuracyMetersPerSecond = location.mSpeedAccuracyMetersPerSecond; 157 mBearingDegrees = location.mBearingDegrees; 158 mBearingAccuracyDegrees = location.mBearingAccuracyDegrees; 159 mExtras = (location.mExtras == null) ? null : new Bundle(location.mExtras); 160 } 161 162 /** 163 * Sets the provider to null, removes all optional fields, and sets the values of all other 164 * fields to zero. 165 */ reset()166 public void reset() { 167 mProvider = null; 168 mTimeMs = 0; 169 mElapsedRealtimeNs = 0; 170 mElapsedRealtimeUncertaintyNs = 0.0; 171 mFieldsMask = 0; 172 mLatitudeDegrees = 0; 173 mLongitudeDegrees = 0; 174 mAltitudeMeters = 0; 175 mSpeedMetersPerSecond = 0; 176 mBearingDegrees = 0; 177 mHorizontalAccuracyMeters = 0; 178 mAltitudeAccuracyMeters = 0; 179 mSpeedAccuracyMetersPerSecond = 0; 180 mBearingAccuracyDegrees = 0; 181 mExtras = null; 182 } 183 184 /** 185 * Returns the approximate distance in meters between this location and the given location. 186 * Distance is defined using the WGS84 ellipsoid. 187 * 188 * @param dest the destination location 189 * @return the approximate distance in meters 190 */ distanceTo(@onNull Location dest)191 public @FloatRange(from = 0.0) float distanceTo(@NonNull Location dest) { 192 BearingDistanceCache cache = sBearingDistanceCache.get(); 193 // See if we already have the result 194 if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1 195 || dest.mLatitudeDegrees != cache.mLat2 || dest.mLongitudeDegrees != cache.mLon2) { 196 computeDistanceAndBearing(mLatitudeDegrees, mLongitudeDegrees, 197 dest.mLatitudeDegrees, dest.mLongitudeDegrees, cache); 198 } 199 return cache.mDistance; 200 } 201 202 /** 203 * Returns the approximate initial bearing in degrees east of true north when traveling along 204 * the shortest path between this location and the given location. The shortest path is defined 205 * using the WGS84 ellipsoid. Locations that are (nearly) antipodal may produce meaningless 206 * results. 207 * 208 * @param dest the destination location 209 * @return the initial bearing in degrees 210 */ bearingTo(@onNull Location dest)211 public float bearingTo(@NonNull Location dest) { 212 BearingDistanceCache cache = sBearingDistanceCache.get(); 213 // See if we already have the result 214 if (mLatitudeDegrees != cache.mLat1 || mLongitudeDegrees != cache.mLon1 215 || dest.mLatitudeDegrees != cache.mLat2 || dest.mLongitudeDegrees != cache.mLon2) { 216 computeDistanceAndBearing(mLatitudeDegrees, mLongitudeDegrees, 217 dest.mLatitudeDegrees, dest.mLongitudeDegrees, cache); 218 } 219 return cache.mInitialBearing; 220 } 221 222 /** 223 * Returns the name of the provider associated with this location. 224 * 225 * @return the name of the provider 226 */ getProvider()227 public @Nullable String getProvider() { 228 return mProvider; 229 } 230 231 /** 232 * Sets the name of the provider associated with this location 233 * 234 * @param provider the name of the provider 235 */ setProvider(@ullable String provider)236 public void setProvider(@Nullable String provider) { 237 mProvider = provider; 238 } 239 240 /** 241 * Returns the Unix epoch time of this location fix, in milliseconds since the start of the Unix 242 * epoch (00:00:00 January 1, 1970 UTC). 243 * 244 * <p>There is no guarantee that different locations have times set from the same clock. 245 * Locations derived from the {@link LocationManager#GPS_PROVIDER} are guaranteed to have their 246 * time originate from the clock in use by the satellite constellation that provided the fix. 247 * Locations derived from other providers may use any clock to set their time, though it is most 248 * common to use the device's Unix epoch time system clock (which may be incorrect). 249 * 250 * <p>Note that the device's Unix epoch time system clock is not monotonic; it can jump forwards 251 * or backwards unpredictably and may be changed at any time by the user, so this time should 252 * not be used to order or compare locations. Prefer {@link #getElapsedRealtimeNanos} for that 253 * purpose, as the elapsed realtime clock is guaranteed to be monotonic. 254 * 255 * <p>On the other hand, this method may be useful for presenting a human-readable time to the 256 * user, or as a heuristic for comparing location fixes across reboot or across devices. 257 * 258 * <p>All locations generated by the {@link LocationManager} are guaranteed to have this time 259 * set, however remember that the device's system clock may have changed since the location was 260 * generated. 261 * 262 * @return the Unix epoch time of this location 263 */ getTime()264 public @IntRange(from = 0) long getTime() { 265 return mTimeMs; 266 } 267 268 /** 269 * Sets the Unix epoch time of this location fix, in milliseconds since the start of the Unix 270 * epoch (00:00:00 January 1 1970 UTC). 271 * 272 * @param timeMs the Unix epoch time of this location 273 */ setTime(@ntRangefrom = 0) long timeMs)274 public void setTime(@IntRange(from = 0) long timeMs) { 275 mTimeMs = timeMs; 276 } 277 278 /** 279 * Return the time of this fix in nanoseconds of elapsed realtime since system boot. 280 * 281 * <p>This value can be compared with {@link android.os.SystemClock#elapsedRealtimeNanos} to 282 * reliably order or compare locations. This is reliable because elapsed realtime is guaranteed 283 * to be monotonic and continues to increment even when the system is in deep sleep (unlike 284 * {@link #getTime}). However, since elapsed realtime is with reference to system boot, it does 285 * not make sense to use this value to order or compare locations across boot cycles or devices. 286 * 287 * <p>All locations generated by the {@link LocationManager} are guaranteed to have a valid 288 * elapsed realtime set. 289 * 290 * @return elapsed realtime of this location in nanoseconds 291 */ getElapsedRealtimeNanos()292 public @IntRange(from = 0) long getElapsedRealtimeNanos() { 293 return mElapsedRealtimeNs; 294 } 295 296 /** 297 * Return the time of this fix in milliseconds of elapsed realtime since system boot. 298 * 299 * @return elapsed realtime of this location in milliseconds 300 * @see #getElapsedRealtimeNanos() 301 */ getElapsedRealtimeMillis()302 public @IntRange(from = 0) long getElapsedRealtimeMillis() { 303 return NANOSECONDS.toMillis(mElapsedRealtimeNs); 304 } 305 306 /** 307 * A convenience methods that returns the age of this location in milliseconds with respect to 308 * the current elapsed realtime. 309 * 310 * @return age of this location in milliseconds 311 */ getElapsedRealtimeAgeMillis()312 public @IntRange(from = 0) long getElapsedRealtimeAgeMillis() { 313 return getElapsedRealtimeAgeMillis(SystemClock.elapsedRealtime()); 314 } 315 316 /** 317 * A convenience method that returns the age of this location with respect to the given 318 * reference elapsed realtime. 319 * 320 * @param referenceRealtimeMs reference realtime in milliseconds 321 * @return age of this location in milliseconds 322 */ getElapsedRealtimeAgeMillis( @ntRangefrom = 0) long referenceRealtimeMs)323 public long getElapsedRealtimeAgeMillis( 324 @IntRange(from = 0) long referenceRealtimeMs) { 325 return referenceRealtimeMs - getElapsedRealtimeMillis(); 326 } 327 328 /** 329 * Set the time of this location in nanoseconds of elapsed realtime since system boot. 330 * 331 * @param elapsedRealtimeNs elapsed realtime in nanoseconds 332 */ setElapsedRealtimeNanos(@ntRangefrom = 0) long elapsedRealtimeNs)333 public void setElapsedRealtimeNanos(@IntRange(from = 0) long elapsedRealtimeNs) { 334 mElapsedRealtimeNs = elapsedRealtimeNs; 335 } 336 337 /** 338 * Get the uncertainty in nanoseconds of the precision of {@link #getElapsedRealtimeNanos()} at 339 * the 68th percentile confidence level. This means that there is 68% chance that the true 340 * elapsed realtime of this location is within {@link #getElapsedRealtimeNanos()} +/- this 341 * uncertainty. 342 * 343 * <p>This is only valid if {@link #hasElapsedRealtimeUncertaintyNanos()} is true. 344 * 345 * @return uncertainty in nanoseconds of the elapsed realtime of this location 346 */ getElapsedRealtimeUncertaintyNanos()347 public @FloatRange(from = 0.0) double getElapsedRealtimeUncertaintyNanos() { 348 return mElapsedRealtimeUncertaintyNs; 349 } 350 351 /** 352 * Sets the uncertainty in nanoseconds of the precision of the elapsed realtime timestamp at a 353 * 68% confidence level. 354 * 355 * @param elapsedRealtimeUncertaintyNs uncertainty in nanoseconds of the elapsed realtime of 356 * this location 357 */ setElapsedRealtimeUncertaintyNanos( @loatRangefrom = 0.0) double elapsedRealtimeUncertaintyNs)358 public void setElapsedRealtimeUncertaintyNanos( 359 @FloatRange(from = 0.0) double elapsedRealtimeUncertaintyNs) { 360 mElapsedRealtimeUncertaintyNs = elapsedRealtimeUncertaintyNs; 361 mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK; 362 } 363 364 /** 365 * True if this location has an elapsed realtime uncertainty, false otherwise. 366 */ hasElapsedRealtimeUncertaintyNanos()367 public boolean hasElapsedRealtimeUncertaintyNanos() { 368 return (mFieldsMask & HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK) != 0; 369 } 370 371 /** 372 * Removes the elapsed realtime uncertainty from this location. 373 */ removeElapsedRealtimeUncertaintyNanos()374 public void removeElapsedRealtimeUncertaintyNanos() { 375 mFieldsMask &= ~HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK; 376 } 377 378 /** 379 * Get the latitude in degrees. All locations generated by the {@link LocationManager} will have 380 * a valid latitude. 381 * 382 * @return latitude of this location 383 */ getLatitude()384 public @FloatRange(from = -90.0, to = 90.0) double getLatitude() { 385 return mLatitudeDegrees; 386 } 387 388 /** 389 * Set the latitude of this location. 390 * 391 * @param latitudeDegrees latitude in degrees 392 */ setLatitude(@loatRangefrom = -90.0, to = 90.0) double latitudeDegrees)393 public void setLatitude(@FloatRange(from = -90.0, to = 90.0) double latitudeDegrees) { 394 mLatitudeDegrees = latitudeDegrees; 395 } 396 397 /** 398 * Get the longitude in degrees. All locations generated by the {@link LocationManager} will 399 * have a valid longitude. 400 * 401 * @return longitude of this location 402 */ getLongitude()403 public @FloatRange(from = -180.0, to = 180.0) double getLongitude() { 404 return mLongitudeDegrees; 405 } 406 407 /** 408 * Set the longitude of this location. 409 * 410 * @param longitudeDegrees longitude in degrees 411 */ setLongitude(@loatRangefrom = -180.0, to = 180.0) double longitudeDegrees)412 public void setLongitude(@FloatRange(from = -180.0, to = 180.0) double longitudeDegrees) { 413 mLongitudeDegrees = longitudeDegrees; 414 } 415 416 /** 417 * Returns the estimated horizontal accuracy radius in meters of this location at the 68th 418 * percentile confidence level. This means that there is a 68% chance that the true location of 419 * the device is within a distance of this uncertainty of the reported location. Another way of 420 * putting this is that if a circle with a radius equal to this accuracy is drawn around the 421 * reported location, there is a 68% chance that the true location falls within this circle. 422 * This accuracy value is only valid for horizontal positioning, and not vertical positioning. 423 * 424 * <p>This is only valid if {@link #hasAccuracy()} is true. All locations generated by the 425 * {@link LocationManager} include horizontal accuracy. 426 * 427 * @return horizontal accuracy of this location 428 */ getAccuracy()429 public @FloatRange(from = 0.0) float getAccuracy() { 430 return mHorizontalAccuracyMeters; 431 } 432 433 /** 434 * Set the horizontal accuracy in meters of this location. 435 * 436 * @param horizontalAccuracyMeters horizontal altitude in meters 437 */ setAccuracy(@loatRangefrom = 0.0) float horizontalAccuracyMeters)438 public void setAccuracy(@FloatRange(from = 0.0) float horizontalAccuracyMeters) { 439 mHorizontalAccuracyMeters = horizontalAccuracyMeters; 440 mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK; 441 } 442 443 /** 444 * Returns true if this location has a horizontal accuracy, false otherwise. 445 */ hasAccuracy()446 public boolean hasAccuracy() { 447 return (mFieldsMask & HAS_HORIZONTAL_ACCURACY_MASK) != 0; 448 } 449 450 /** 451 * Remove the horizontal accuracy from this location. 452 */ removeAccuracy()453 public void removeAccuracy() { 454 mFieldsMask &= ~HAS_HORIZONTAL_ACCURACY_MASK; 455 } 456 457 /** 458 * The altitude of this location in meters above the WGS84 reference ellipsoid. 459 * 460 * <p>This is only valid if {@link #hasAltitude()} is true. 461 * 462 * @return altitude of this location 463 */ getAltitude()464 public @FloatRange double getAltitude() { 465 return mAltitudeMeters; 466 } 467 468 /** 469 * Set the altitude of this location in meters above the WGS84 reference ellipsoid. 470 * 471 * @param altitudeMeters altitude in meters 472 */ setAltitude(@loatRange double altitudeMeters)473 public void setAltitude(@FloatRange double altitudeMeters) { 474 mAltitudeMeters = altitudeMeters; 475 mFieldsMask |= HAS_ALTITUDE_MASK; 476 } 477 478 /** 479 * Returns true if this location has an altitude, false otherwise. 480 */ hasAltitude()481 public boolean hasAltitude() { 482 return (mFieldsMask & HAS_ALTITUDE_MASK) != 0; 483 } 484 485 /** 486 * Removes the altitude from this location. 487 */ removeAltitude()488 public void removeAltitude() { 489 mFieldsMask &= ~HAS_ALTITUDE_MASK; 490 } 491 492 /** 493 * Returns the estimated altitude accuracy in meters of this location at the 68th percentile 494 * confidence level. This means that there is 68% chance that the true altitude of this location 495 * falls within {@link #getAltitude()} ()} +/- this uncertainty. 496 * 497 * <p>This is only valid if {@link #hasVerticalAccuracy()} is true. 498 * 499 * @return vertical accuracy of this location 500 */ getVerticalAccuracyMeters()501 public @FloatRange(from = 0.0) float getVerticalAccuracyMeters() { 502 return mAltitudeAccuracyMeters; 503 } 504 505 /** 506 * Set the altitude accuracy of this location in meters. 507 * 508 * @param altitudeAccuracyMeters altitude accuracy in meters 509 */ setVerticalAccuracyMeters(@loatRangefrom = 0.0) float altitudeAccuracyMeters)510 public void setVerticalAccuracyMeters(@FloatRange(from = 0.0) float altitudeAccuracyMeters) { 511 mAltitudeAccuracyMeters = altitudeAccuracyMeters; 512 mFieldsMask |= HAS_ALTITUDE_ACCURACY_MASK; 513 } 514 515 /** 516 * Returns true if this location has a vertical accuracy, false otherwise. 517 */ hasVerticalAccuracy()518 public boolean hasVerticalAccuracy() { 519 return (mFieldsMask & HAS_ALTITUDE_ACCURACY_MASK) != 0; 520 } 521 522 /** 523 * Remove the vertical accuracy from this location. 524 */ removeVerticalAccuracy()525 public void removeVerticalAccuracy() { 526 mFieldsMask &= ~HAS_ALTITUDE_ACCURACY_MASK; 527 } 528 529 /** 530 * Returns the speed at the time of this location in meters per second. Note that the speed 531 * returned here may be more accurate than would be obtained simply by calculating 532 * {@code distance / time} for sequential positions, such as if the Doppler measurements from 533 * GNSS satellites are taken into account. 534 * 535 * <p>This is only valid if {@link #hasSpeed()} is true. 536 * 537 * @return speed at the time of this location 538 */ getSpeed()539 public @FloatRange(from = 0.0) float getSpeed() { 540 return mSpeedMetersPerSecond; 541 } 542 543 /** 544 * Set the speed at the time of this location, in meters per second. 545 * 546 * @param speedMetersPerSecond speed in meters per second 547 */ setSpeed(@loatRangefrom = 0.0) float speedMetersPerSecond)548 public void setSpeed(@FloatRange(from = 0.0) float speedMetersPerSecond) { 549 mSpeedMetersPerSecond = speedMetersPerSecond; 550 mFieldsMask |= HAS_SPEED_MASK; 551 } 552 553 /** 554 * True if this location has a speed, false otherwise. 555 */ hasSpeed()556 public boolean hasSpeed() { 557 return (mFieldsMask & HAS_SPEED_MASK) != 0; 558 } 559 560 /** 561 * Remove the speed from this location. 562 */ removeSpeed()563 public void removeSpeed() { 564 mFieldsMask &= ~HAS_SPEED_MASK; 565 } 566 567 /** 568 * Returns the estimated speed accuracy in meters per second of this location at the 68th 569 * percentile confidence level. This means that there is 68% chance that the true speed at the 570 * time of this location falls within {@link #getSpeed()} ()} +/- this uncertainty. 571 * 572 * <p>This is only valid if {@link #hasSpeedAccuracy()} is true. 573 * 574 * @return vertical accuracy of this location 575 */ getSpeedAccuracyMetersPerSecond()576 public @FloatRange(from = 0.0) float getSpeedAccuracyMetersPerSecond() { 577 return mSpeedAccuracyMetersPerSecond; 578 } 579 580 /** 581 * Set the speed accuracy of this location in meters per second. 582 * 583 * @param speedAccuracyMeterPerSecond speed accuracy in meters per second 584 */ setSpeedAccuracyMetersPerSecond( @loatRangefrom = 0.0) float speedAccuracyMeterPerSecond)585 public void setSpeedAccuracyMetersPerSecond( 586 @FloatRange(from = 0.0) float speedAccuracyMeterPerSecond) { 587 mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond; 588 mFieldsMask |= HAS_SPEED_ACCURACY_MASK; 589 } 590 591 /** 592 * Returns true if this location has a speed accuracy, false otherwise. 593 */ hasSpeedAccuracy()594 public boolean hasSpeedAccuracy() { 595 return (mFieldsMask & HAS_SPEED_ACCURACY_MASK) != 0; 596 } 597 598 /** 599 * Remove the speed accuracy from this location. 600 */ removeSpeedAccuracy()601 public void removeSpeedAccuracy() { 602 mFieldsMask &= ~HAS_SPEED_ACCURACY_MASK; 603 } 604 605 /** 606 * Returns the bearing at the time of this location in degrees. Bearing is the horizontal 607 * direction of travel of this device and is unrelated to the device orientation. The bearing 608 * is guaranteed to be in the range [0, 360). 609 * 610 * <p>This is only valid if {@link #hasBearing()} is true. 611 * 612 * @return bearing at the time of this location 613 */ getBearing()614 public @FloatRange(from = 0.0, to = 360.0, toInclusive = false) float getBearing() { 615 return mBearingDegrees; 616 } 617 618 /** 619 * Set the bearing at the time of this location, in degrees. The given bearing will be converted 620 * into the range [0, 360). 621 * 622 * <p class="note">Note: passing in extremely high or low floating point values to this function 623 * may produce strange results due to the intricacies of floating point math. 624 * 625 * @param bearingDegrees bearing in degrees 626 */ setBearing( @loatRangefromInclusive = false, toInclusive = false) float bearingDegrees)627 public void setBearing( 628 @FloatRange(fromInclusive = false, toInclusive = false) float bearingDegrees) { 629 Preconditions.checkArgument(Float.isFinite(bearingDegrees)); 630 631 // final addition of zero is to remove -0 results. while these are technically within the 632 // range [0, 360) according to IEEE semantics, this eliminates possible user confusion. 633 float modBearing = bearingDegrees % 360f + 0f; 634 if (modBearing < 0) { 635 modBearing += 360f; 636 } 637 mBearingDegrees = modBearing; 638 mFieldsMask |= HAS_BEARING_MASK; 639 } 640 641 /** 642 * True if this location has a bearing, false otherwise. 643 */ hasBearing()644 public boolean hasBearing() { 645 return (mFieldsMask & HAS_BEARING_MASK) != 0; 646 } 647 648 /** 649 * Remove the bearing from this location. 650 */ removeBearing()651 public void removeBearing() { 652 mFieldsMask &= ~HAS_BEARING_MASK; 653 } 654 655 /** 656 * Returns the estimated bearing accuracy in degrees of this location at the 68th percentile 657 * confidence level. This means that there is 68% chance that the true bearing at the 658 * time of this location falls within {@link #getBearing()} ()} +/- this uncertainty. 659 * 660 * <p>This is only valid if {@link #hasBearingAccuracy()} ()} is true. 661 * 662 * @return bearing accuracy in degrees of this location 663 */ getBearingAccuracyDegrees()664 public @FloatRange(from = 0.0) float getBearingAccuracyDegrees() { 665 return mBearingAccuracyDegrees; 666 } 667 668 /** 669 * Set the bearing accuracy in degrees of this location. 670 * 671 * @param bearingAccuracyDegrees bearing accuracy in degrees 672 */ setBearingAccuracyDegrees(@loatRangefrom = 0.0) float bearingAccuracyDegrees)673 public void setBearingAccuracyDegrees(@FloatRange(from = 0.0) float bearingAccuracyDegrees) { 674 mBearingAccuracyDegrees = bearingAccuracyDegrees; 675 mFieldsMask |= HAS_BEARING_ACCURACY_MASK; 676 } 677 678 /** 679 * Returns true if this location has a bearing accuracy, false otherwise. 680 */ hasBearingAccuracy()681 public boolean hasBearingAccuracy() { 682 return (mFieldsMask & HAS_BEARING_ACCURACY_MASK) != 0; 683 } 684 685 /** 686 * Remove the bearing accuracy from this location. 687 */ removeBearingAccuracy()688 public void removeBearingAccuracy() { 689 mFieldsMask &= ~HAS_BEARING_ACCURACY_MASK; 690 } 691 692 /** 693 * Returns true if this is a mock location. If this location comes from the Android framework, 694 * this indicates that the location was provided by a test location provider, and thus may not 695 * be related to the actual location of the device. 696 * 697 * @return true if this location came from a mock provider, false otherwise 698 * @deprecated Prefer {@link #isMock()} instead. 699 */ 700 @Deprecated isFromMockProvider()701 public boolean isFromMockProvider() { 702 return isMock(); 703 } 704 705 /** 706 * Flag this location as having come from a mock provider or not. 707 * 708 * @param isFromMockProvider true if this location came from a mock provider, false otherwise 709 * @deprecated Prefer {@link #setMock(boolean)} instead. 710 * @hide 711 */ 712 @Deprecated 713 @SystemApi setIsFromMockProvider(boolean isFromMockProvider)714 public void setIsFromMockProvider(boolean isFromMockProvider) { 715 setMock(isFromMockProvider); 716 } 717 718 /** 719 * Returns true if this location is marked as a mock location. If this location comes from the 720 * Android framework, this indicates that the location was provided by a test location provider, 721 * and thus may not be related to the actual location of the device. 722 * 723 * @see LocationManager#addTestProvider 724 */ isMock()725 public boolean isMock() { 726 return (mFieldsMask & HAS_MOCK_PROVIDER_MASK) != 0; 727 } 728 729 /** 730 * Sets whether this location is marked as a mock location. 731 */ setMock(boolean mock)732 public void setMock(boolean mock) { 733 if (mock) { 734 mFieldsMask |= HAS_MOCK_PROVIDER_MASK; 735 } else { 736 mFieldsMask &= ~HAS_MOCK_PROVIDER_MASK; 737 } 738 } 739 740 /** 741 * Returns an optional bundle of additional information associated with this location. The keys 742 * and values within the bundle are determined by the location provider. 743 * 744 * <p> Common key/value pairs are listed below. There is no guarantee that these key/value pairs 745 * will be present for any location. 746 * 747 * <ul> 748 * <li> satellites - the number of satellites used to derive a GNSS fix 749 * </ul> 750 */ getExtras()751 public @Nullable Bundle getExtras() { 752 return mExtras; 753 } 754 755 /** 756 * Sets the extra information associated with this fix to the given Bundle. 757 * 758 * <p>Note this stores a copy of the given extras, so any changes to extras after calling this 759 * method won't be reflected in the location bundle. 760 */ setExtras(@ullable Bundle extras)761 public void setExtras(@Nullable Bundle extras) { 762 mExtras = (extras == null) ? null : new Bundle(extras); 763 } 764 765 /** 766 * Return true if this location is considered complete. A location is considered complete if it 767 * has a non-null provider, accuracy, and non-zero time and elapsed realtime. The exact 768 * definition of completeness may change over time. 769 * 770 * <p>All locations supplied by the {@link LocationManager} are guaranteed to be complete. 771 */ isComplete()772 public boolean isComplete() { 773 return mProvider != null && hasAccuracy() && mTimeMs != 0 && mElapsedRealtimeNs != 0; 774 } 775 776 /** 777 * Helper to fill incomplete fields with valid (but likely nonsensical) values. 778 * 779 * @hide 780 */ 781 @SystemApi makeComplete()782 public void makeComplete() { 783 if (mProvider == null) { 784 mProvider = ""; 785 } 786 if (!hasAccuracy()) { 787 mFieldsMask |= HAS_HORIZONTAL_ACCURACY_MASK; 788 mHorizontalAccuracyMeters = 100.0f; 789 } 790 if (mTimeMs == 0) { 791 mTimeMs = System.currentTimeMillis(); 792 } 793 if (mElapsedRealtimeNs == 0) { 794 mElapsedRealtimeNs = SystemClock.elapsedRealtimeNanos(); 795 } 796 } 797 798 /** 799 * Location equality is provided primarily for test purposes. Comparing locations for equality 800 * in production may indicate incorrect assumptions, and should be avoided whenever possible. 801 * 802 * <p>{@inheritDoc} 803 */ 804 @Override equals(@ullable Object o)805 public boolean equals(@Nullable Object o) { 806 if (this == o) { 807 return true; 808 } 809 if (!(o instanceof Location)) { 810 return false; 811 } 812 813 Location location = (Location) o; 814 return mTimeMs == location.mTimeMs 815 && mElapsedRealtimeNs == location.mElapsedRealtimeNs 816 && hasElapsedRealtimeUncertaintyNanos() 817 == location.hasElapsedRealtimeUncertaintyNanos() 818 && (!hasElapsedRealtimeUncertaintyNanos() || Double.compare( 819 location.mElapsedRealtimeUncertaintyNs, mElapsedRealtimeUncertaintyNs) == 0) 820 && Double.compare(location.mLatitudeDegrees, mLatitudeDegrees) == 0 821 && Double.compare(location.mLongitudeDegrees, mLongitudeDegrees) == 0 822 && hasAltitude() == location.hasAltitude() 823 && (!hasAltitude() || Double.compare(location.mAltitudeMeters, mAltitudeMeters) 824 == 0) 825 && hasSpeed() == location.hasSpeed() 826 && (!hasSpeed() || Float.compare(location.mSpeedMetersPerSecond, 827 mSpeedMetersPerSecond) == 0) 828 && hasBearing() == location.hasBearing() 829 && (!hasBearing() || Float.compare(location.mBearingDegrees, mBearingDegrees) == 0) 830 && hasAccuracy() == location.hasAccuracy() 831 && (!hasAccuracy() || Float.compare(location.mHorizontalAccuracyMeters, 832 mHorizontalAccuracyMeters) == 0) 833 && hasVerticalAccuracy() == location.hasVerticalAccuracy() 834 && (!hasVerticalAccuracy() || Float.compare(location.mAltitudeAccuracyMeters, 835 mAltitudeAccuracyMeters) == 0) 836 && hasSpeedAccuracy() == location.hasSpeedAccuracy() 837 && (!hasSpeedAccuracy() || Float.compare(location.mSpeedAccuracyMetersPerSecond, 838 mSpeedAccuracyMetersPerSecond) == 0) 839 && hasBearingAccuracy() == location.hasBearingAccuracy() 840 && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees, 841 mBearingAccuracyDegrees) == 0) 842 && Objects.equals(mProvider, location.mProvider) 843 && areExtrasEqual(mExtras, location.mExtras); 844 } 845 areExtrasEqual(@ullable Bundle extras1, @Nullable Bundle extras2)846 private static boolean areExtrasEqual(@Nullable Bundle extras1, @Nullable Bundle extras2) { 847 if ((extras1 == null || extras1.isEmpty()) && (extras2 == null || extras2.isEmpty())) { 848 return true; 849 } else if (extras1 == null || extras2 == null) { 850 return false; 851 } else { 852 return extras1.kindofEquals(extras2); 853 } 854 } 855 856 @Override hashCode()857 public int hashCode() { 858 return Objects.hash(mProvider, mElapsedRealtimeNs, mLatitudeDegrees, mLongitudeDegrees); 859 } 860 861 @Override toString()862 public @NonNull String toString() { 863 StringBuilder s = new StringBuilder(); 864 s.append("Location["); 865 s.append(mProvider); 866 s.append(" ").append(String.format(Locale.ROOT, "%.6f,%.6f", mLatitudeDegrees, 867 mLongitudeDegrees)); 868 if (hasAccuracy()) { 869 s.append(" hAcc=").append(mHorizontalAccuracyMeters); 870 } 871 s.append(" et="); 872 TimeUtils.formatDuration(getElapsedRealtimeMillis(), s); 873 if (hasAltitude()) { 874 s.append(" alt=").append(mAltitudeMeters); 875 if (hasVerticalAccuracy()) { 876 s.append(" vAcc=").append(mAltitudeAccuracyMeters); 877 } 878 } 879 if (hasSpeed()) { 880 s.append(" vel=").append(mSpeedMetersPerSecond); 881 if (hasSpeedAccuracy()) { 882 s.append(" sAcc=").append(mSpeedAccuracyMetersPerSecond); 883 } 884 } 885 if (hasBearing()) { 886 s.append(" bear=").append(mBearingDegrees); 887 if (hasBearingAccuracy()) { 888 s.append(" bAcc=").append(mBearingAccuracyDegrees); 889 } 890 } 891 if (isMock()) { 892 s.append(" mock"); 893 } 894 895 if (mExtras != null && !mExtras.isEmpty()) { 896 s.append(" {").append(mExtras).append('}'); 897 } 898 s.append(']'); 899 return s.toString(); 900 } 901 902 /** 903 * Dumps location information to the given Printer. 904 * 905 * @deprecated Prefer to use {@link #toString()} along with whatever custom formatting is 906 * required instead of this method. It is not this class's job to manage print representations. 907 */ 908 @Deprecated dump(@onNull Printer pw, @Nullable String prefix)909 public void dump(@NonNull Printer pw, @Nullable String prefix) { 910 pw.println(prefix + this); 911 } 912 913 public static final @NonNull Parcelable.Creator<Location> CREATOR = 914 new Parcelable.Creator<Location>() { 915 @Override 916 public Location createFromParcel(Parcel in) { 917 Location l = new Location(in.readString8()); 918 l.mFieldsMask = in.readInt(); 919 l.mTimeMs = in.readLong(); 920 l.mElapsedRealtimeNs = in.readLong(); 921 if (l.hasElapsedRealtimeUncertaintyNanos()) { 922 l.mElapsedRealtimeUncertaintyNs = in.readDouble(); 923 } 924 l.mLatitudeDegrees = in.readDouble(); 925 l.mLongitudeDegrees = in.readDouble(); 926 if (l.hasAltitude()) { 927 l.mAltitudeMeters = in.readDouble(); 928 } 929 if (l.hasSpeed()) { 930 l.mSpeedMetersPerSecond = in.readFloat(); 931 } 932 if (l.hasBearing()) { 933 l.mBearingDegrees = in.readFloat(); 934 } 935 if (l.hasAccuracy()) { 936 l.mHorizontalAccuracyMeters = in.readFloat(); 937 } 938 if (l.hasVerticalAccuracy()) { 939 l.mAltitudeAccuracyMeters = in.readFloat(); 940 } 941 if (l.hasSpeedAccuracy()) { 942 l.mSpeedAccuracyMetersPerSecond = in.readFloat(); 943 } 944 if (l.hasBearingAccuracy()) { 945 l.mBearingAccuracyDegrees = in.readFloat(); 946 } 947 l.mExtras = Bundle.setDefusable(in.readBundle(), true); 948 return l; 949 } 950 951 @Override 952 public Location[] newArray(int size) { 953 return new Location[size]; 954 } 955 }; 956 957 @Override describeContents()958 public int describeContents() { 959 return 0; 960 } 961 962 @Override writeToParcel(@onNull Parcel parcel, int flags)963 public void writeToParcel(@NonNull Parcel parcel, int flags) { 964 parcel.writeString8(mProvider); 965 parcel.writeInt(mFieldsMask); 966 parcel.writeLong(mTimeMs); 967 parcel.writeLong(mElapsedRealtimeNs); 968 if (hasElapsedRealtimeUncertaintyNanos()) { 969 parcel.writeDouble(mElapsedRealtimeUncertaintyNs); 970 } 971 parcel.writeDouble(mLatitudeDegrees); 972 parcel.writeDouble(mLongitudeDegrees); 973 if (hasAltitude()) { 974 parcel.writeDouble(mAltitudeMeters); 975 } 976 if (hasSpeed()) { 977 parcel.writeFloat(mSpeedMetersPerSecond); 978 } 979 if (hasBearing()) { 980 parcel.writeFloat(mBearingDegrees); 981 } 982 if (hasAccuracy()) { 983 parcel.writeFloat(mHorizontalAccuracyMeters); 984 } 985 if (hasVerticalAccuracy()) { 986 parcel.writeFloat(mAltitudeAccuracyMeters); 987 } 988 if (hasSpeedAccuracy()) { 989 parcel.writeFloat(mSpeedAccuracyMetersPerSecond); 990 } 991 if (hasBearingAccuracy()) { 992 parcel.writeFloat(mBearingAccuracyDegrees); 993 } 994 parcel.writeBundle(mExtras); 995 } 996 997 /** 998 * Converts a latitude/longitude coordinate to a String representation. The outputType must be 999 * one of {@link #FORMAT_DEGREES}, {@link #FORMAT_MINUTES}, or {@link #FORMAT_SECONDS}. The 1000 * coordinate must be a number between -180.0 and 180.0, inclusive. This conversion is performed 1001 * in a method that is dependent on the default locale, and so is not guaranteed to round-trip 1002 * with {@link #convert(String)}. 1003 * 1004 * @throws IllegalArgumentException if coordinate is less than -180.0, greater than 180.0, or is 1005 * not a number. 1006 * @throws IllegalArgumentException if outputType is not a recognized value. 1007 */ convert(@loatRange double coordinate, @Format int outputType)1008 public static @NonNull String convert(@FloatRange double coordinate, @Format int outputType) { 1009 Preconditions.checkArgumentInRange(coordinate, -180D, 180D, "coordinate"); 1010 Preconditions.checkArgument(outputType == FORMAT_DEGREES || outputType == FORMAT_MINUTES 1011 || outputType == FORMAT_SECONDS, "%d is an unrecognized format", outputType); 1012 1013 StringBuilder sb = new StringBuilder(); 1014 1015 if (coordinate < 0) { 1016 sb.append('-'); 1017 coordinate = -coordinate; 1018 } 1019 1020 DecimalFormat df = new DecimalFormat("###.#####"); 1021 if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) { 1022 int degrees = (int) Math.floor(coordinate); 1023 sb.append(degrees); 1024 sb.append(':'); 1025 coordinate -= degrees; 1026 coordinate *= 60.0; 1027 if (outputType == FORMAT_SECONDS) { 1028 int minutes = (int) Math.floor(coordinate); 1029 sb.append(minutes); 1030 sb.append(':'); 1031 coordinate -= minutes; 1032 coordinate *= 60.0; 1033 } 1034 } 1035 sb.append(df.format(coordinate)); 1036 return sb.toString(); 1037 } 1038 1039 /** 1040 * Converts a String in one of the formats described by {@link #FORMAT_DEGREES}, 1041 * {@link #FORMAT_MINUTES}, or {@link #FORMAT_SECONDS} into a double. This conversion is 1042 * performed in a locale agnostic method, and so is not guaranteed to round-trip with 1043 * {@link #convert(double, int)}. 1044 * 1045 * @throws NullPointerException if coordinate is null 1046 * @throws IllegalArgumentException if the coordinate is not 1047 * in one of the valid formats. 1048 */ convert(@onNull String coordinate)1049 public static @FloatRange double convert(@NonNull String coordinate) { 1050 Objects.requireNonNull(coordinate); 1051 1052 boolean negative = false; 1053 if (coordinate.charAt(0) == '-') { 1054 coordinate = coordinate.substring(1); 1055 negative = true; 1056 } 1057 1058 StringTokenizer st = new StringTokenizer(coordinate, ":"); 1059 int tokens = st.countTokens(); 1060 if (tokens < 1) { 1061 throw new IllegalArgumentException("coordinate=" + coordinate); 1062 } 1063 try { 1064 String degrees = st.nextToken(); 1065 double val; 1066 if (tokens == 1) { 1067 val = Double.parseDouble(degrees); 1068 return negative ? -val : val; 1069 } 1070 1071 String minutes = st.nextToken(); 1072 int deg = Integer.parseInt(degrees); 1073 double min; 1074 double sec = 0.0; 1075 boolean secPresent = false; 1076 1077 if (st.hasMoreTokens()) { 1078 min = Integer.parseInt(minutes); 1079 String seconds = st.nextToken(); 1080 sec = Double.parseDouble(seconds); 1081 secPresent = true; 1082 } else { 1083 min = Double.parseDouble(minutes); 1084 } 1085 1086 boolean isNegative180 = negative && deg == 180 && min == 0 && sec == 0; 1087 1088 // deg must be in [0, 179] except for the case of -180 degrees 1089 if (deg < 0.0 || (deg > 179 && !isNegative180)) { 1090 throw new IllegalArgumentException("coordinate=" + coordinate); 1091 } 1092 1093 // min must be in [0, 59] if seconds are present, otherwise [0.0, 60.0) 1094 if (min < 0 || min >= 60 || (secPresent && min > 59)) { 1095 throw new IllegalArgumentException("coordinate=" + coordinate); 1096 } 1097 1098 // sec must be in [0.0, 60.0) 1099 if (sec < 0 || sec >= 60) { 1100 throw new IllegalArgumentException("coordinate=" + coordinate); 1101 } 1102 1103 val = deg * 3600.0 + min * 60.0 + sec; 1104 val /= 3600.0; 1105 return negative ? -val : val; 1106 } catch (NumberFormatException e) { 1107 throw new IllegalArgumentException("coordinate=" + coordinate, e); 1108 } 1109 } 1110 computeDistanceAndBearing(double lat1, double lon1, double lat2, double lon2, BearingDistanceCache results)1111 private static void computeDistanceAndBearing(double lat1, double lon1, 1112 double lat2, double lon2, BearingDistanceCache results) { 1113 // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf 1114 // using the "Inverse Formula" (section 4) 1115 1116 // Convert lat/long to radians 1117 lat1 *= Math.PI / 180.0; 1118 lat2 *= Math.PI / 180.0; 1119 lon1 *= Math.PI / 180.0; 1120 lon2 *= Math.PI / 180.0; 1121 1122 double a = 6378137.0; // WGS84 major axis 1123 double b = 6356752.3142; // WGS84 semi-major axis 1124 double f = (a - b) / a; 1125 double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b); 1126 1127 double l = lon2 - lon1; 1128 double aA = 0.0; 1129 double u1 = Math.atan((1.0 - f) * Math.tan(lat1)); 1130 double u2 = Math.atan((1.0 - f) * Math.tan(lat2)); 1131 1132 double cosU1 = Math.cos(u1); 1133 double cosU2 = Math.cos(u2); 1134 double sinU1 = Math.sin(u1); 1135 double sinU2 = Math.sin(u2); 1136 double cosU1cosU2 = cosU1 * cosU2; 1137 double sinU1sinU2 = sinU1 * sinU2; 1138 1139 double sigma = 0.0; 1140 double deltaSigma = 0.0; 1141 double cosSqAlpha; 1142 double cos2SM; 1143 double cosSigma; 1144 double sinSigma; 1145 double cosLambda = 0.0; 1146 double sinLambda = 0.0; 1147 1148 double lambda = l; // initial guess 1149 for (int iter = 0; iter < 20; iter++) { 1150 double lambdaOrig = lambda; 1151 cosLambda = Math.cos(lambda); 1152 sinLambda = Math.sin(lambda); 1153 double t1 = cosU2 * sinLambda; 1154 double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda; 1155 double sinSqSigma = t1 * t1 + t2 * t2; 1156 sinSigma = Math.sqrt(sinSqSigma); 1157 cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; 1158 sigma = Math.atan2(sinSigma, cosSigma); 1159 double sinAlpha = (sinSigma == 0) ? 0.0 : 1160 cosU1cosU2 * sinLambda / sinSigma; 1161 cosSqAlpha = 1.0 - sinAlpha * sinAlpha; 1162 cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; 1163 1164 double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; 1165 aA = 1 + (uSquared / 16384.0) * (4096.0 + uSquared * (-768 + uSquared * (320.0 1166 - 175.0 * uSquared))); 1167 double bB = (uSquared / 1024.0) * (256.0 + uSquared * (-128.0 + uSquared * (74.0 1168 - 47.0 * uSquared))); 1169 double cC = (f / 16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); 1170 double cos2SMSq = cos2SM * cos2SM; 1171 deltaSigma = bB * sinSigma * (cos2SM + (bB / 4.0) * (cosSigma * (-1.0 + 2.0 * cos2SMSq) 1172 - (bB / 6.0) * cos2SM * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 1173 + 4.0 * cos2SMSq))); 1174 1175 lambda = l + (1.0 - cC) * f * sinAlpha * (sigma + cC * sinSigma * (cos2SM 1176 + cC * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM))); 1177 1178 double delta = (lambda - lambdaOrig) / lambda; 1179 if (Math.abs(delta) < 1.0e-12) { 1180 break; 1181 } 1182 } 1183 1184 results.mDistance = (float) (b * aA * (sigma - deltaSigma)); 1185 float initialBearing = (float) Math.atan2(cosU2 * sinLambda, 1186 cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); 1187 initialBearing = (float) (initialBearing * (180.0 / Math.PI)); 1188 results.mInitialBearing = initialBearing; 1189 float finalBearing = (float) Math.atan2(cosU1 * sinLambda, 1190 -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); 1191 finalBearing = (float) (finalBearing * (180.0 / Math.PI)); 1192 results.mFinalBearing = finalBearing; 1193 results.mLat1 = lat1; 1194 results.mLat2 = lat2; 1195 results.mLon1 = lon1; 1196 results.mLon2 = lon2; 1197 } 1198 1199 /** 1200 * Computes the approximate distance in meters between two 1201 * locations, and optionally the initial and final bearings of the 1202 * shortest path between them. Distance and bearing are defined using the 1203 * WGS84 ellipsoid. 1204 * 1205 * <p> The computed distance is stored in results[0]. If results has length 1206 * 2 or greater, the initial bearing is stored in results[1]. If results has 1207 * length 3 or greater, the final bearing is stored in results[2]. 1208 * 1209 * @param startLatitude the starting latitude 1210 * @param startLongitude the starting longitude 1211 * @param endLatitude the ending latitude 1212 * @param endLongitude the ending longitude 1213 * @param results an array of floats to hold the results 1214 * 1215 * @throws IllegalArgumentException if results is null or has length < 1 1216 */ distanceBetween( @loatRangefrom = -90.0, to = 90.0) double startLatitude, @FloatRange(from = -180.0, to = 180.0) double startLongitude, @FloatRange(from = -90.0, to = 90.0) double endLatitude, @FloatRange(from = -180.0, to = 180.0) double endLongitude, float[] results)1217 public static void distanceBetween( 1218 @FloatRange(from = -90.0, to = 90.0) double startLatitude, 1219 @FloatRange(from = -180.0, to = 180.0) double startLongitude, 1220 @FloatRange(from = -90.0, to = 90.0) double endLatitude, 1221 @FloatRange(from = -180.0, to = 180.0) double endLongitude, 1222 float[] results) { 1223 if (results == null || results.length < 1) { 1224 throw new IllegalArgumentException("results is null or has length < 1"); 1225 } 1226 BearingDistanceCache cache = sBearingDistanceCache.get(); 1227 computeDistanceAndBearing(startLatitude, startLongitude, 1228 endLatitude, endLongitude, cache); 1229 results[0] = cache.mDistance; 1230 if (results.length > 1) { 1231 results[1] = cache.mInitialBearing; 1232 if (results.length > 2) { 1233 results[2] = cache.mFinalBearing; 1234 } 1235 } 1236 } 1237 1238 private static class BearingDistanceCache { 1239 double mLat1 = 0.0; 1240 double mLon1 = 0.0; 1241 double mLat2 = 0.0; 1242 double mLon2 = 0.0; 1243 float mDistance = 0.0f; 1244 float mInitialBearing = 0.0f; 1245 float mFinalBearing = 0.0f; 1246 } 1247 } 1248