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