Home | History | Annotate | Download | only in location
      1 /*
      2  * Copyright (C) 2012 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.Parcel;
     21 import android.os.Parcelable;
     22 import android.os.SystemClock;
     23 import android.os.WorkSource;
     24 import android.util.TimeUtils;
     25 
     26 
     27 /**
     28  * A data object that contains quality of service parameters for requests
     29  * to the {@link LocationManager}.
     30  *
     31  * <p>LocationRequest objects are used to request a quality of service
     32  * for location updates from the Location Manager.
     33  *
     34  * <p>For example, if your application wants high accuracy location
     35  * it should create a location request with {@link #setQuality} set to
     36  * {@link #ACCURACY_FINE} or {@link #POWER_HIGH}, and it should set
     37  * {@link #setInterval} to less than one second. This would be
     38  * appropriate for mapping applications that are showing your location
     39  * in real-time.
     40  *
     41  * <p>At the other extreme, if you want negligible power
     42  * impact, but to still receive location updates when available, then use
     43  * {@link #setQuality} with {@link #POWER_NONE}. With this request your
     44  * application will not trigger (and therefore will not receive any
     45  * power blame) any location updates, but will receive locations
     46  * triggered by other applications. This would be appropriate for
     47  * applications that have no firm requirement for location, but can
     48  * take advantage when available.
     49  *
     50  * <p>In between these two extremes is a very common use-case, where
     51  * applications definitely want to receive
     52  * updates at a specified interval, and can receive them faster when
     53  * available, but still want a low power impact. These applications
     54  * should consider {@link #POWER_LOW} combined with a faster
     55  * {@link #setFastestInterval} (such as 1 minute) and a slower
     56  * {@link #setInterval} (such as 60 minutes). They will only be assigned
     57  * power blame for the interval set by {@link #setInterval}, but can
     58  * still receive locations triggered by other applications at a rate up
     59  * to {@link #setFastestInterval}. This style of request is appropriate for
     60  * many location aware applications, including background usage. Do be
     61  * careful to also throttle {@link #setFastestInterval} if you perform
     62  * heavy-weight work after receiving an update - such as using the network.
     63  *
     64  * <p>Activities should strongly consider removing all location
     65  * request when entering the background
     66  * (for example at {@link android.app.Activity#onPause}), or
     67  * at least swap the request to a larger interval and lower quality.
     68  * Future version of the location manager may automatically perform background
     69  * throttling on behalf of applications.
     70  *
     71  * <p>Applications cannot specify the exact location sources that are
     72  * used by Android's <em>Fusion Engine</em>. In fact, the system
     73  * may have multiple location sources (providers) running and may
     74  * fuse the results from several sources into a single Location object.
     75  *
     76  * <p>Location requests from applications with
     77  * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not
     78  * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will
     79  * be automatically throttled to a slower interval, and the location
     80  * object will be obfuscated to only show a coarse level of accuracy.
     81  *
     82  * <p>All location requests are considered hints, and you may receive
     83  * locations that are more accurate, less accurate, and slower
     84  * than requested.
     85  *
     86  * @hide
     87  */
     88 @SystemApi
     89 public final class LocationRequest implements Parcelable {
     90     /**
     91      * Used with {@link #setQuality} to request the most accurate locations available.
     92      *
     93      * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
     94      */
     95     public static final int ACCURACY_FINE = 100;
     96 
     97     /**
     98      * Used with {@link #setQuality} to request "block" level accuracy.
     99      *
    100      * <p>Block level accuracy is considered to be about 100 meter accuracy,
    101      * although this is implementation dependent. Using a coarse accuracy
    102      * such as this often consumes less power.
    103      */
    104     public static final int ACCURACY_BLOCK = 102;
    105 
    106     /**
    107      * Used with {@link #setQuality} to request "city" level accuracy.
    108      *
    109      * <p>City level accuracy is considered to be about 10km accuracy,
    110      * although this is implementation dependent. Using a coarse accuracy
    111      * such as this often consumes less power.
    112      */
    113     public static final int ACCURACY_CITY = 104;
    114 
    115     /**
    116      * Used with {@link #setQuality} to require no direct power impact (passive locations).
    117      *
    118      * <p>This location request will not trigger any active location requests,
    119      * but will receive locations triggered by other applications. Your application
    120      * will not receive any direct power blame for location work.
    121      */
    122     public static final int POWER_NONE = 200;
    123 
    124     /**
    125      * Used with {@link #setQuality} to request low power impact.
    126      *
    127      * <p>This location request will avoid high power location work where
    128      * possible.
    129      */
    130     public static final int POWER_LOW = 201;
    131 
    132     /**
    133      * Used with {@link #setQuality} to allow high power consumption for location.
    134      *
    135      * <p>This location request will allow high power location work.
    136      */
    137     public static final int POWER_HIGH = 203;
    138 
    139     /**
    140      * By default, mFastestInterval = FASTEST_INTERVAL_MULTIPLE * mInterval
    141      */
    142     private static final double FASTEST_INTERVAL_FACTOR = 6.0;  // 6x
    143 
    144     private int mQuality = POWER_LOW;
    145     private long mInterval = 60 * 60 * 1000;   // 60 minutes
    146     private long mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);  // 10 minutes
    147     private boolean mExplicitFastestInterval = false;
    148     private long mExpireAt = Long.MAX_VALUE;  // no expiry
    149     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
    150     private float mSmallestDisplacement = 0.0f;    // meters
    151     private WorkSource mWorkSource = null;
    152     private boolean mHideFromAppOps = false; // True if this request shouldn't be counted by AppOps
    153 
    154     private String mProvider = LocationManager.FUSED_PROVIDER;
    155             // for deprecated APIs that explicitly request a provider
    156 
    157     /** If true, GNSS chipset will make strong tradeoffs to substantially restrict power use */
    158     private boolean mLowPowerMode = false;
    159 
    160     /**
    161      * Create a location request with default parameters.
    162      *
    163      * <p>Default parameters are for a low power, slowly updated location.
    164      * It can then be adjusted as required by the applications before passing
    165      * to the {@link LocationManager}
    166      *
    167      * @return a new location request
    168      */
    169     public static LocationRequest create() {
    170         LocationRequest request = new LocationRequest();
    171         return request;
    172     }
    173 
    174     /** @hide */
    175     @SystemApi
    176     public static LocationRequest createFromDeprecatedProvider(String provider, long minTime,
    177             float minDistance, boolean singleShot) {
    178         if (minTime < 0) minTime = 0;
    179         if (minDistance < 0) minDistance = 0;
    180 
    181         int quality;
    182         if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
    183             quality = POWER_NONE;
    184         } else if (LocationManager.GPS_PROVIDER.equals(provider)) {
    185             quality = ACCURACY_FINE;
    186         } else {
    187             quality = POWER_LOW;
    188         }
    189 
    190         LocationRequest request = new LocationRequest()
    191                 .setProvider(provider)
    192                 .setQuality(quality)
    193                 .setInterval(minTime)
    194                 .setFastestInterval(minTime)
    195                 .setSmallestDisplacement(minDistance);
    196         if (singleShot) request.setNumUpdates(1);
    197         return request;
    198     }
    199 
    200     /** @hide */
    201     @SystemApi
    202     public static LocationRequest createFromDeprecatedCriteria(Criteria criteria, long minTime,
    203             float minDistance, boolean singleShot) {
    204         if (minTime < 0) minTime = 0;
    205         if (minDistance < 0) minDistance = 0;
    206 
    207         int quality;
    208         switch (criteria.getAccuracy()) {
    209             case Criteria.ACCURACY_COARSE:
    210                 quality = ACCURACY_BLOCK;
    211                 break;
    212             case Criteria.ACCURACY_FINE:
    213                 quality = ACCURACY_FINE;
    214                 break;
    215             default: {
    216                 switch (criteria.getPowerRequirement()) {
    217                     case Criteria.POWER_HIGH:
    218                         quality = POWER_HIGH;
    219                         break;
    220                     default:
    221                         quality = POWER_LOW;
    222                 }
    223             }
    224         }
    225 
    226         LocationRequest request = new LocationRequest()
    227                 .setQuality(quality)
    228                 .setInterval(minTime)
    229                 .setFastestInterval(minTime)
    230                 .setSmallestDisplacement(minDistance);
    231         if (singleShot) request.setNumUpdates(1);
    232         return request;
    233     }
    234 
    235     /** @hide */
    236     public LocationRequest() {
    237     }
    238 
    239     /** @hide */
    240     public LocationRequest(LocationRequest src) {
    241         mQuality = src.mQuality;
    242         mInterval = src.mInterval;
    243         mFastestInterval = src.mFastestInterval;
    244         mExplicitFastestInterval = src.mExplicitFastestInterval;
    245         mExpireAt = src.mExpireAt;
    246         mNumUpdates = src.mNumUpdates;
    247         mSmallestDisplacement = src.mSmallestDisplacement;
    248         mProvider = src.mProvider;
    249         mWorkSource = src.mWorkSource;
    250         mHideFromAppOps = src.mHideFromAppOps;
    251         mLowPowerMode = src.mLowPowerMode;
    252     }
    253 
    254     /**
    255      * Set the quality of the request.
    256      *
    257      * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
    258      * constant such as {@link #POWER_LOW}. You cannot request both and accuracy and
    259      * power, only one or the other can be specified. The system will then
    260      * maximize accuracy or minimize power as appropriate.
    261      *
    262      * <p>The quality of the request is a strong hint to the system for which
    263      * location sources to use. For example, {@link #ACCURACY_FINE} is more likely
    264      * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower
    265      * positioning, but it also depends on many other factors (such as which sources
    266      * are available) and is implementation dependent.
    267      *
    268      * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
    269      * on a location request.
    270      *
    271      * @param quality an accuracy or power constant
    272      * @return the same object, so that setters can be chained
    273      * @throws InvalidArgumentException if the quality constant is not valid
    274      */
    275     public LocationRequest setQuality(int quality) {
    276         checkQuality(quality);
    277         mQuality = quality;
    278         return this;
    279     }
    280 
    281     /**
    282      * Get the quality of the request.
    283      *
    284      * @return an accuracy or power constant
    285      */
    286     public int getQuality() {
    287         return mQuality;
    288     }
    289 
    290     /**
    291      * Set the desired interval for active location updates, in milliseconds.
    292      *
    293      * <p>The location manager will actively try to obtain location updates
    294      * for your application at this interval, so it has a
    295      * direct influence on the amount of power used by your application.
    296      * Choose your interval wisely.
    297      *
    298      * <p>This interval is inexact. You may not receive updates at all (if
    299      * no location sources are available), or you may receive them
    300      * slower than requested. You may also receive them faster than
    301      * requested (if other applications are requesting location at a
    302      * faster interval). The fastest rate that you will receive
    303      * updates can be controlled with {@link #setFastestInterval}.
    304      *
    305      * <p>Applications with only the coarse location permission may have their
    306      * interval silently throttled.
    307      *
    308      * <p>An interval of 0 is allowed, but not recommended, since
    309      * location updates may be extremely fast on future implementations.
    310      *
    311      * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
    312      * on a location request.
    313      *
    314      * @param millis desired interval in millisecond, inexact
    315      * @return the same object, so that setters can be chained
    316      * @throws InvalidArgumentException if the interval is less than zero
    317      */
    318     public LocationRequest setInterval(long millis) {
    319         checkInterval(millis);
    320         mInterval = millis;
    321         if (!mExplicitFastestInterval) {
    322             mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
    323         }
    324         return this;
    325     }
    326 
    327     /**
    328      * Get the desired interval of this request, in milliseconds.
    329      *
    330      * @return desired interval in milliseconds, inexact
    331      */
    332     public long getInterval() {
    333         return mInterval;
    334     }
    335 
    336 
    337     /**
    338      * Requests the GNSS chipset to run in a low power mode and make strong tradeoffs to
    339      * substantially restrict power.
    340      *
    341      * <p>In this mode, the GNSS chipset will not, on average, run power hungry operations like RF &
    342      * signal searches for more than one second per interval (specified by
    343      * {@link #setInterval(long)}).
    344      *
    345      * @param enabled Enable or disable low power mode
    346      * @return the same object, so that setters can be chained
    347      * @hide
    348      */
    349     @SystemApi
    350     public LocationRequest setLowPowerMode(boolean enabled) {
    351         mLowPowerMode = enabled;
    352         return this;
    353     }
    354 
    355     /**
    356      * Returns true if low power mode is enabled.
    357      *
    358      * @hide
    359      */
    360     @SystemApi
    361     public boolean isLowPowerMode() {
    362         return mLowPowerMode;
    363     }
    364 
    365     /**
    366      * Explicitly set the fastest interval for location updates, in
    367      * milliseconds.
    368      *
    369      * <p>This controls the fastest rate at which your application will
    370      * receive location updates, which might be faster than
    371      * {@link #setInterval} in some situations (for example, if other
    372      * applications are triggering location updates).
    373      *
    374      * <p>This allows your application to passively acquire locations
    375      * at a rate faster than it actively acquires locations, saving power.
    376      *
    377      * <p>Unlike {@link #setInterval}, this parameter is exact. Your
    378      * application will never receive updates faster than this value.
    379      *
    380      * <p>If you don't call this method, a fastest interval
    381      * will be selected for you. It will be a value faster than your
    382      * active interval ({@link #setInterval}).
    383      *
    384      * <p>An interval of 0 is allowed, but not recommended, since
    385      * location updates may be extremely fast on future implementations.
    386      *
    387      * <p>If {@link #setFastestInterval} is set slower than {@link #setInterval},
    388      * then your effective fastest interval is {@link #setInterval}.
    389      *
    390      * @param millis fastest interval for updates in milliseconds, exact
    391      * @return the same object, so that setters can be chained
    392      * @throws InvalidArgumentException if the interval is less than zero
    393      */
    394     public LocationRequest setFastestInterval(long millis) {
    395         checkInterval(millis);
    396         mExplicitFastestInterval = true;
    397         mFastestInterval = millis;
    398         return this;
    399     }
    400 
    401     /**
    402      * Get the fastest interval of this request, in milliseconds.
    403      *
    404      * <p>The system will never provide location updates faster
    405      * than the minimum of {@link #getFastestInterval} and
    406      * {@link #getInterval}.
    407      *
    408      * @return fastest interval in milliseconds, exact
    409      */
    410     public long getFastestInterval() {
    411         return mFastestInterval;
    412     }
    413 
    414     /**
    415      * Set the duration of this request, in milliseconds.
    416      *
    417      * <p>The duration begins immediately (and not when the request
    418      * is passed to the location manager), so call this method again
    419      * if the request is re-used at a later time.
    420      *
    421      * <p>The location manager will automatically stop updates after
    422      * the request expires.
    423      *
    424      * <p>The duration includes suspend time. Values less than 0
    425      * are allowed, but indicate that the request has already expired.
    426      *
    427      * @param millis duration of request in milliseconds
    428      * @return the same object, so that setters can be chained
    429      */
    430     public LocationRequest setExpireIn(long millis) {
    431         long elapsedRealtime = SystemClock.elapsedRealtime();
    432 
    433         // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
    434         if (millis > Long.MAX_VALUE - elapsedRealtime) {
    435             mExpireAt = Long.MAX_VALUE;
    436         } else {
    437             mExpireAt = millis + elapsedRealtime;
    438         }
    439 
    440         if (mExpireAt < 0) mExpireAt = 0;
    441         return this;
    442     }
    443 
    444     /**
    445      * Set the request expiration time, in millisecond since boot.
    446      *
    447      * <p>This expiration time uses the same time base as {@link SystemClock#elapsedRealtime}.
    448      *
    449      * <p>The location manager will automatically stop updates after
    450      * the request expires.
    451      *
    452      * <p>The duration includes suspend time. Values before {@link SystemClock#elapsedRealtime}
    453      * are allowed,  but indicate that the request has already expired.
    454      *
    455      * @param millis expiration time of request, in milliseconds since boot including suspend
    456      * @return the same object, so that setters can be chained
    457      */
    458     public LocationRequest setExpireAt(long millis) {
    459         mExpireAt = millis;
    460         if (mExpireAt < 0) mExpireAt = 0;
    461         return this;
    462     }
    463 
    464     /**
    465      * Get the request expiration time, in milliseconds since boot.
    466      *
    467      * <p>This value can be compared to {@link SystemClock#elapsedRealtime} to determine
    468      * the time until expiration.
    469      *
    470      * @return expiration time of request, in milliseconds since boot including suspend
    471      */
    472     public long getExpireAt() {
    473         return mExpireAt;
    474     }
    475 
    476     /**
    477      * Set the number of location updates.
    478      *
    479      * <p>By default locations are continuously updated until the request is explicitly
    480      * removed, however you can optionally request a set number of updates.
    481      * For example, if your application only needs a single fresh location,
    482      * then call this method with a value of 1 before passing the request
    483      * to the location manager.
    484      *
    485      * @param numUpdates the number of location updates requested
    486      * @return the same object, so that setters can be chained
    487      * @throws InvalidArgumentException if numUpdates is 0 or less
    488      */
    489     public LocationRequest setNumUpdates(int numUpdates) {
    490         if (numUpdates <= 0) {
    491             throw new IllegalArgumentException(
    492                     "invalid numUpdates: " + numUpdates);
    493         }
    494         mNumUpdates = numUpdates;
    495         return this;
    496     }
    497 
    498     /**
    499      * Get the number of updates requested.
    500      *
    501      * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
    502      * locations are updated until the request is explicitly removed.
    503      *
    504      * @return number of updates
    505      */
    506     public int getNumUpdates() {
    507         return mNumUpdates;
    508     }
    509 
    510     /** @hide */
    511     public void decrementNumUpdates() {
    512         if (mNumUpdates != Integer.MAX_VALUE) {
    513             mNumUpdates--;
    514         }
    515         if (mNumUpdates < 0) {
    516             mNumUpdates = 0;
    517         }
    518     }
    519 
    520 
    521     /** @hide */
    522     @SystemApi
    523     public LocationRequest setProvider(String provider) {
    524         checkProvider(provider);
    525         mProvider = provider;
    526         return this;
    527     }
    528 
    529     /** @hide */
    530     @SystemApi
    531     public String getProvider() {
    532         return mProvider;
    533     }
    534 
    535     /** @hide */
    536     @SystemApi
    537     public LocationRequest setSmallestDisplacement(float meters) {
    538         checkDisplacement(meters);
    539         mSmallestDisplacement = meters;
    540         return this;
    541     }
    542 
    543     /** @hide */
    544     @SystemApi
    545     public float getSmallestDisplacement() {
    546         return mSmallestDisplacement;
    547     }
    548 
    549     /**
    550      * Sets the WorkSource to use for power blaming of this location request.
    551      *
    552      * <p>No permissions are required to make this call, however the LocationManager
    553      * will throw a SecurityException when requesting location updates if the caller
    554      * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
    555      *
    556      * @param workSource WorkSource defining power blame for this location request.
    557      * @hide
    558      */
    559     @SystemApi
    560     public void setWorkSource(WorkSource workSource) {
    561         mWorkSource = workSource;
    562     }
    563 
    564     /** @hide */
    565     @SystemApi
    566     public WorkSource getWorkSource() {
    567         return mWorkSource;
    568     }
    569 
    570     /**
    571      * Sets whether or not this location request should be hidden from AppOps.
    572      *
    573      * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this
    574      * request's existence.  It does not affect power blaming in the Battery page.
    575      *
    576      * <p>No permissions are required to make this call, however the LocationManager
    577      * will throw a SecurityException when requesting location updates if the caller
    578      * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission.
    579      *
    580      * @param hideFromAppOps If true AppOps won't keep track of this location request.
    581      * @hide
    582      * @see android.app.AppOpsManager
    583      */
    584     @SystemApi
    585     public void setHideFromAppOps(boolean hideFromAppOps) {
    586         mHideFromAppOps = hideFromAppOps;
    587     }
    588 
    589     /** @hide */
    590     @SystemApi
    591     public boolean getHideFromAppOps() {
    592         return mHideFromAppOps;
    593     }
    594 
    595     private static void checkInterval(long millis) {
    596         if (millis < 0) {
    597             throw new IllegalArgumentException("invalid interval: " + millis);
    598         }
    599     }
    600 
    601     private static void checkQuality(int quality) {
    602         switch (quality) {
    603             case ACCURACY_FINE:
    604             case ACCURACY_BLOCK:
    605             case ACCURACY_CITY:
    606             case POWER_NONE:
    607             case POWER_LOW:
    608             case POWER_HIGH:
    609                 break;
    610             default:
    611                 throw new IllegalArgumentException("invalid quality: " + quality);
    612         }
    613     }
    614 
    615     private static void checkDisplacement(float meters) {
    616         if (meters < 0.0f) {
    617             throw new IllegalArgumentException("invalid displacement: " + meters);
    618         }
    619     }
    620 
    621     private static void checkProvider(String name) {
    622         if (name == null) {
    623             throw new IllegalArgumentException("invalid provider: " + name);
    624         }
    625     }
    626 
    627     public static final Parcelable.Creator<LocationRequest> CREATOR =
    628             new Parcelable.Creator<LocationRequest>() {
    629                 @Override
    630                 public LocationRequest createFromParcel(Parcel in) {
    631                     LocationRequest request = new LocationRequest();
    632                     request.setQuality(in.readInt());
    633                     request.setFastestInterval(in.readLong());
    634                     request.setInterval(in.readLong());
    635                     request.setExpireAt(in.readLong());
    636                     request.setNumUpdates(in.readInt());
    637                     request.setSmallestDisplacement(in.readFloat());
    638                     request.setHideFromAppOps(in.readInt() != 0);
    639                     request.setLowPowerMode(in.readInt() != 0);
    640                     String provider = in.readString();
    641                     if (provider != null) request.setProvider(provider);
    642                     WorkSource workSource = in.readParcelable(null);
    643                     if (workSource != null) request.setWorkSource(workSource);
    644                     return request;
    645                 }
    646 
    647                 @Override
    648                 public LocationRequest[] newArray(int size) {
    649                     return new LocationRequest[size];
    650                 }
    651             };
    652 
    653     @Override
    654     public int describeContents() {
    655         return 0;
    656     }
    657 
    658     @Override
    659     public void writeToParcel(Parcel parcel, int flags) {
    660         parcel.writeInt(mQuality);
    661         parcel.writeLong(mFastestInterval);
    662         parcel.writeLong(mInterval);
    663         parcel.writeLong(mExpireAt);
    664         parcel.writeInt(mNumUpdates);
    665         parcel.writeFloat(mSmallestDisplacement);
    666         parcel.writeInt(mHideFromAppOps ? 1 : 0);
    667         parcel.writeInt(mLowPowerMode ? 1 : 0);
    668         parcel.writeString(mProvider);
    669         parcel.writeParcelable(mWorkSource, 0);
    670     }
    671 
    672     /** @hide */
    673     public static String qualityToString(int quality) {
    674         switch (quality) {
    675             case ACCURACY_FINE:
    676                 return "ACCURACY_FINE";
    677             case ACCURACY_BLOCK:
    678                 return "ACCURACY_BLOCK";
    679             case ACCURACY_CITY:
    680                 return "ACCURACY_CITY";
    681             case POWER_NONE:
    682                 return "POWER_NONE";
    683             case POWER_LOW:
    684                 return "POWER_LOW";
    685             case POWER_HIGH:
    686                 return "POWER_HIGH";
    687             default:
    688                 return "???";
    689         }
    690     }
    691 
    692     @Override
    693     public String toString() {
    694         StringBuilder s = new StringBuilder();
    695         s.append("Request[").append(qualityToString(mQuality));
    696         if (mProvider != null) s.append(' ').append(mProvider);
    697         if (mQuality != POWER_NONE) {
    698             s.append(" requested=");
    699             TimeUtils.formatDuration(mInterval, s);
    700         }
    701         s.append(" fastest=");
    702         TimeUtils.formatDuration(mFastestInterval, s);
    703         if (mExpireAt != Long.MAX_VALUE) {
    704             long expireIn = mExpireAt - SystemClock.elapsedRealtime();
    705             s.append(" expireIn=");
    706             TimeUtils.formatDuration(expireIn, s);
    707         }
    708         if (mNumUpdates != Integer.MAX_VALUE) {
    709             s.append(" num=").append(mNumUpdates);
    710         }
    711         s.append(" lowPowerMode=").append(mLowPowerMode);
    712         s.append(']');
    713         return s.toString();
    714     }
    715 }
    716