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