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