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 static android.Manifest.permission.LOCATION_BYPASS;
20 
21 import static java.lang.Math.max;
22 import static java.lang.Math.min;
23 
24 import android.Manifest;
25 import android.annotation.FloatRange;
26 import android.annotation.IntDef;
27 import android.annotation.IntRange;
28 import android.annotation.NonNull;
29 import android.annotation.Nullable;
30 import android.annotation.RequiresFeature;
31 import android.annotation.RequiresPermission;
32 import android.annotation.SystemApi;
33 import android.compat.annotation.ChangeId;
34 import android.compat.annotation.EnabledAfter;
35 import android.content.pm.PackageManager;
36 import android.os.Build;
37 import android.os.Parcel;
38 import android.os.Parcelable;
39 import android.os.WorkSource;
40 import android.util.TimeUtils;
41 
42 import com.android.internal.util.Preconditions;
43 
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 import java.util.Objects;
47 
48 
49 /**
50  * An encapsulation of various parameters for requesting location via {@link LocationManager}.
51  */
52 public final class LocationRequest implements Parcelable {
53 
54     /**
55      * For apps targeting Android S and above, all LocationRequest objects marked as low power will
56      * throw exceptions if the caller does not have the LOCATION_HARDWARE permission, instead of
57      * silently dropping the low power part of the request.
58      *
59      * @hide
60      */
61     @ChangeId
62     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
63     public static final long LOW_POWER_EXCEPTIONS = 168936375L;
64 
65     /**
66      * Represents a passive only request. Such a request will not trigger any active locations or
67      * power usage itself, but may receive locations generated in response to other requests.
68      *
69      * @see LocationRequest#getIntervalMillis()
70      */
71     public static final long PASSIVE_INTERVAL = Long.MAX_VALUE;
72 
73     /** @hide */
74     @Retention(RetentionPolicy.SOURCE)
75     @IntDef({QUALITY_LOW_POWER, QUALITY_BALANCED_POWER_ACCURACY, QUALITY_HIGH_ACCURACY})
76     public @interface Quality {}
77 
78     /**
79      * A quality constant indicating a location provider may choose to satisfy this request by
80      * providing very accurate locations at the expense of potentially increased power usage. Each
81      * location provider may interpret this field differently, but as an example, the network
82      * provider may choose to return only wifi based locations rather than cell based locations in
83      * order to have greater accuracy when this flag is present.
84      */
85     public static final int QUALITY_HIGH_ACCURACY = 100;
86 
87     /**
88      * A quality constant indicating a location provider may choose to satisfy this request by
89      * equally balancing power and accuracy constraints. Each location provider may interpret this
90      * field differently, but location providers will generally use their default behavior when this
91      * flag is present.
92      */
93     public static final int QUALITY_BALANCED_POWER_ACCURACY = 102;
94 
95     /**
96      * A quality constant indicating a location provider may choose to satisfy this request by
97      * providing less accurate locations in order to save power. Each location provider may
98      * interpret this field differently, but as an example, the network provider may choose to
99      * return cell based locations rather than wifi based locations in order to save power when this
100      * flag is present.
101      */
102     public static final int QUALITY_LOW_POWER = 104;
103 
104     /**
105      * Used with {@link #setQuality} to request the most accurate locations available.
106      *
107      * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
108      *
109      * @hide
110      * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
111      */
112     @Deprecated
113     @SystemApi
114     public static final int ACCURACY_FINE = QUALITY_HIGH_ACCURACY;
115 
116     /**
117      * Used with {@link #setQuality} to request "block" level accuracy.
118      *
119      * <p>Block level accuracy is considered to be about 100 meter accuracy,
120      * although this is implementation dependent. Using a coarse accuracy
121      * such as this often consumes less power.
122      *
123      * @hide
124      * @deprecated Use {@link #QUALITY_BALANCED_POWER_ACCURACY} instead.
125      */
126     @Deprecated
127     @SystemApi
128     public static final int ACCURACY_BLOCK = QUALITY_BALANCED_POWER_ACCURACY;
129 
130     /**
131      * Used with {@link #setQuality} to request "city" level accuracy.
132      *
133      * <p>City level accuracy is considered to be about 10km accuracy,
134      * although this is implementation dependent. Using a coarse accuracy
135      * such as this often consumes less power.
136      *
137      * @hide
138      * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
139      */
140     @Deprecated
141     @SystemApi
142     public static final int ACCURACY_CITY = QUALITY_LOW_POWER;
143 
144     /**
145      * Used with {@link #setQuality} to require no direct power impact (passive locations).
146      *
147      * <p>This location request will not trigger any active location requests,
148      * but will receive locations triggered by other applications. Your application
149      * will not receive any direct power blame for location work.
150      *
151      * @hide
152      * @deprecated Use {@link #PASSIVE_INTERVAL} instead.
153      */
154     @SystemApi
155     @Deprecated
156     public static final int POWER_NONE = 200;
157 
158     /**
159      * Used with {@link #setQuality} to request low power impact.
160      *
161      * <p>This location request will avoid high power location work where
162      * possible.
163      *
164      * @hide
165      * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
166      */
167     @Deprecated
168     @SystemApi
169     public static final int POWER_LOW = 201;
170 
171     /**
172      * Used with {@link #setQuality} to allow high power consumption for location.
173      *
174      * <p>This location request will allow high power location work.
175      *
176      * @hide
177      * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
178      */
179     @Deprecated
180     @SystemApi
181     public static final int POWER_HIGH = 203;
182 
183     private static final long IMPLICIT_MIN_UPDATE_INTERVAL = -1;
184     private static final double IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR = 1D / 6D;
185 
186     private @Nullable String mProvider;
187     private @Quality int mQuality;
188     private long mIntervalMillis;
189     private long mMinUpdateIntervalMillis;
190     private long mExpireAtRealtimeMillis;
191     private long mDurationMillis;
192     private int mMaxUpdates;
193     private float mMinUpdateDistanceMeters;
194     private final long mMaxUpdateDelayMillis;
195     private boolean mHideFromAppOps;
196     private final boolean mAdasGnssBypass;
197     private boolean mBypass;
198     private boolean mLowPower;
199     private @Nullable WorkSource mWorkSource;
200 
201     /**
202      * @hide
203      * @deprecated Use the Builder to construct new LocationRequests.
204      */
205     @SystemApi
206     @Deprecated
207     @NonNull
create()208     public static LocationRequest create() {
209         // 60 minutes is the default legacy interval
210         return new LocationRequest.Builder(60 * 60 * 1000).build();
211     }
212 
213     /**
214      * @hide
215      * @deprecated Use the Builder to construct new LocationRequests.
216      */
217     @SystemApi
218     @Deprecated
219     @NonNull
createFromDeprecatedProvider(@onNull String provider, long intervalMillis, float minUpdateDistanceMeters, boolean singleShot)220     public static LocationRequest createFromDeprecatedProvider(@NonNull String provider,
221             long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
222         Preconditions.checkArgument(provider != null, "invalid null provider");
223 
224         if (intervalMillis < 0) {
225             intervalMillis = 0;
226         } else if (intervalMillis == PASSIVE_INTERVAL) {
227             intervalMillis = Long.MAX_VALUE - 1;
228         }
229         if (minUpdateDistanceMeters < 0) {
230             minUpdateDistanceMeters = 0;
231         }
232 
233         int quality;
234         if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
235             quality = POWER_NONE;
236         } else if (LocationManager.GPS_PROVIDER.equals(provider)) {
237             quality = QUALITY_HIGH_ACCURACY;
238         } else {
239             quality = QUALITY_BALANCED_POWER_ACCURACY;
240         }
241 
242         return new LocationRequest.Builder(intervalMillis)
243                 .setMinUpdateIntervalMillis(intervalMillis)
244                 .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
245                 .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
246                 .build()
247                 .setProvider(provider)
248                 .setQuality(quality);
249     }
250 
251     /**
252      * @hide
253      * @deprecated Use the Builder to construct new LocationRequests.
254      */
255     @SystemApi
256     @Deprecated
257     @NonNull
createFromDeprecatedCriteria(@onNull Criteria criteria, long intervalMillis, float minUpdateDistanceMeters, boolean singleShot)258     public static LocationRequest createFromDeprecatedCriteria(@NonNull Criteria criteria,
259             long intervalMillis, float minUpdateDistanceMeters, boolean singleShot) {
260         Preconditions.checkArgument(criteria != null, "invalid null criteria");
261 
262         if (intervalMillis < 0) {
263             intervalMillis = 0;
264         } else if (intervalMillis == PASSIVE_INTERVAL) {
265             intervalMillis = Long.MAX_VALUE - 1;
266         }
267         if (minUpdateDistanceMeters < 0) {
268             minUpdateDistanceMeters = 0;
269         }
270 
271         return new LocationRequest.Builder(intervalMillis)
272                 .setQuality(criteria)
273                 .setMinUpdateIntervalMillis(intervalMillis)
274                 .setMinUpdateDistanceMeters(minUpdateDistanceMeters)
275                 .setMaxUpdates(singleShot ? 1 : Integer.MAX_VALUE)
276                 .build();
277     }
278 
LocationRequest( @ullable String provider, long intervalMillis, @Quality int quality, long expireAtRealtimeMillis, long durationMillis, int maxUpdates, long minUpdateIntervalMillis, float minUpdateDistanceMeters, long maxUpdateDelayMillis, boolean hiddenFromAppOps, boolean adasGnssBypass, boolean bypass, boolean lowPower, WorkSource workSource)279     private LocationRequest(
280             @Nullable String provider,
281             long intervalMillis,
282             @Quality int quality,
283             long expireAtRealtimeMillis,
284             long durationMillis,
285             int maxUpdates,
286             long minUpdateIntervalMillis,
287             float minUpdateDistanceMeters,
288             long maxUpdateDelayMillis,
289             boolean hiddenFromAppOps,
290             boolean adasGnssBypass,
291             boolean bypass,
292             boolean lowPower,
293             WorkSource workSource) {
294         mProvider = provider;
295         mIntervalMillis = intervalMillis;
296         mQuality = quality;
297         mMinUpdateIntervalMillis = minUpdateIntervalMillis;
298         mExpireAtRealtimeMillis = expireAtRealtimeMillis;
299         mDurationMillis = durationMillis;
300         mMaxUpdates = maxUpdates;
301         mMinUpdateDistanceMeters = minUpdateDistanceMeters;
302         mMaxUpdateDelayMillis = maxUpdateDelayMillis;
303         mHideFromAppOps = hiddenFromAppOps;
304         mAdasGnssBypass = adasGnssBypass;
305         mBypass = bypass;
306         mLowPower = lowPower;
307         mWorkSource = Objects.requireNonNull(workSource);
308     }
309 
310     /**
311      * @hide
312      * @deprecated LocationRequests should be treated as immutable.
313      */
314     @SystemApi
315     @Deprecated
setProvider(@onNull String provider)316     public @NonNull LocationRequest setProvider(@NonNull String provider) {
317         Preconditions.checkArgument(provider != null);
318         mProvider = provider;
319         return this;
320     }
321 
322     /**
323      * @hide
324      * @deprecated Providers are no longer an explicit part of a location request.
325      */
326     @SystemApi
327     @Deprecated
getProvider()328     public @NonNull String getProvider() {
329         return mProvider != null ? mProvider : LocationManager.FUSED_PROVIDER;
330     }
331 
332     /**
333      * @hide
334      * @deprecated LocationRequests should be treated as immutable.
335      */
336     @SystemApi
337     @Deprecated
setQuality(int quality)338     public @NonNull LocationRequest setQuality(int quality) {
339         switch (quality) {
340             case POWER_HIGH:
341                 // fall through
342             case QUALITY_HIGH_ACCURACY:
343                 mQuality = QUALITY_HIGH_ACCURACY;
344                 break;
345             case QUALITY_BALANCED_POWER_ACCURACY:
346                 mQuality = QUALITY_BALANCED_POWER_ACCURACY;
347                 break;
348             case POWER_LOW:
349                 // fall through
350             case QUALITY_LOW_POWER:
351                 mQuality = QUALITY_LOW_POWER;
352                 break;
353             case POWER_NONE:
354                 mIntervalMillis = PASSIVE_INTERVAL;
355                 break;
356             default:
357                 throw new IllegalArgumentException("invalid quality: " + quality);
358         }
359 
360         return this;
361     }
362 
363     /**
364      * Returns the quality hint for this location request. The quality hint informs the provider how
365      * it should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
366      * location request.
367      *
368      * @return the desired quality tradeoffs between accuracy and power
369      */
getQuality()370     public @Quality int getQuality() {
371         return mQuality;
372     }
373 
374     /**
375      * @hide
376      * @deprecated LocationRequests should be treated as immutable.
377      */
378     @SystemApi
379     @Deprecated
setInterval(long millis)380     public @NonNull LocationRequest setInterval(long millis) {
381         Preconditions.checkArgument(millis >= 0);
382 
383         // legacy clients don't know about the passive interval
384         if (millis == PASSIVE_INTERVAL) {
385             millis = Long.MAX_VALUE - 1;
386         }
387 
388         mIntervalMillis = millis;
389         if (mMinUpdateIntervalMillis > mIntervalMillis) {
390             mMinUpdateIntervalMillis = mIntervalMillis;
391         }
392         return this;
393     }
394 
395     /**
396      * @hide
397      * @deprecated Use {@link #getIntervalMillis()} instead.
398      */
399     @SystemApi
400     @Deprecated
getInterval()401     public long getInterval() {
402         return getIntervalMillis();
403     }
404 
405     /**
406      * Returns the desired interval of location updates, or {@link #PASSIVE_INTERVAL} if this is a
407      * passive, no power request. A passive request will not actively generate location updates
408      * (and thus will not be power blamed for location), but may receive location updates generated
409      * as a result of other location requests. A passive request must always have an explicit
410      * minimum update interval set.
411      *
412      * <p>Locations may be available at a faster interval than specified here, see
413      * {@link #getMinUpdateIntervalMillis()} for the behavior in that case.
414      *
415      * @return the desired interval of location updates
416      */
getIntervalMillis()417     public @IntRange(from = 0) long getIntervalMillis() {
418         return mIntervalMillis;
419     }
420 
421     /**
422      * @hide
423      * @deprecated LocationRequests should be treated as immutable.
424      */
425     @SystemApi
426     @Deprecated
setFastestInterval(long millis)427     public @NonNull LocationRequest setFastestInterval(long millis) {
428         Preconditions.checkArgument(millis >= 0);
429         mMinUpdateIntervalMillis = millis;
430         return this;
431     }
432 
433     /**
434      * @hide
435      * @deprecated Use {@link #getMinUpdateIntervalMillis()} instead.
436      */
437     @SystemApi
438     @Deprecated
getFastestInterval()439     public long getFastestInterval() {
440         return getMinUpdateIntervalMillis();
441     }
442 
443     /**
444      * @hide
445      * @deprecated LocationRequests should be treated as immutable.
446      */
447     @SystemApi
448     @Deprecated
setExpireAt(long millis)449     public @NonNull LocationRequest setExpireAt(long millis) {
450         mExpireAtRealtimeMillis = max(millis, 0);
451         return this;
452     }
453 
454     /**
455      * @hide
456      * @deprecated Prefer {@link #getDurationMillis()} where possible.
457      */
458     @SystemApi
459     @Deprecated
getExpireAt()460     public long getExpireAt() {
461         return mExpireAtRealtimeMillis;
462     }
463 
464     /**
465      * @hide
466      * @deprecated LocationRequests should be treated as immutable.
467      */
468     @SystemApi
469     @Deprecated
setExpireIn(long millis)470     public @NonNull LocationRequest setExpireIn(long millis) {
471         mDurationMillis = millis;
472         return this;
473     }
474 
475     /**
476      * @hide
477      * @deprecated Use {@link #getDurationMillis()} instead.
478      */
479     @SystemApi
480     @Deprecated
getExpireIn()481     public long getExpireIn() {
482         return getDurationMillis();
483     }
484 
485     /**
486      * Returns the duration for which location will be provided before the request is automatically
487      * removed. A duration of <code>Long.MAX_VALUE</code> represents an unlimited duration.
488      *
489      * @return the duration for which location will be provided
490      */
getDurationMillis()491     public @IntRange(from = 1) long getDurationMillis() {
492         return mDurationMillis;
493     }
494 
495     /**
496      * @hide
497      */
getExpirationRealtimeMs(long startRealtimeMs)498     public long getExpirationRealtimeMs(long startRealtimeMs) {
499         long expirationRealtimeMs;
500         // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
501         if (mDurationMillis > Long.MAX_VALUE - startRealtimeMs) {
502             expirationRealtimeMs = Long.MAX_VALUE;
503         } else {
504             expirationRealtimeMs = startRealtimeMs + mDurationMillis;
505         }
506         return min(expirationRealtimeMs, mExpireAtRealtimeMillis);
507     }
508 
509     /**
510      * @hide
511      * @deprecated LocationRequests should be treated as immutable.
512      */
513     @SystemApi
514     @Deprecated
setNumUpdates(int numUpdates)515     public @NonNull LocationRequest setNumUpdates(int numUpdates) {
516         if (numUpdates <= 0) {
517             throw new IllegalArgumentException(
518                     "invalid numUpdates: " + numUpdates);
519         }
520         mMaxUpdates = numUpdates;
521         return this;
522     }
523 
524     /**
525      * @hide
526      * @deprecated Use {@link #getMaxUpdates()} instead.
527      */
528     @SystemApi
529     @Deprecated
getNumUpdates()530     public int getNumUpdates() {
531         return getMaxUpdates();
532     }
533 
534     /**
535      * Returns the maximum number of location updates for this request before the request is
536      * automatically removed. A max updates value of <code>Integer.MAX_VALUE</code> represents an
537      * unlimited number of updates.
538      */
getMaxUpdates()539     public @IntRange(from = 1, to = Integer.MAX_VALUE) int getMaxUpdates() {
540         return mMaxUpdates;
541     }
542 
543     /**
544      * Returns the minimum update interval. If location updates are available faster than the
545      * request interval then locations will only be updated if the minimum update interval has
546      * expired since the last location update.
547      *
548      * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
549      * minimum update interval, so you need not worry about updates blocked simply because they
550      * arrived a fraction of a second earlier than expected.
551      *
552      * @return the minimum update interval
553      */
getMinUpdateIntervalMillis()554     public @IntRange(from = 0) long getMinUpdateIntervalMillis() {
555         if (mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
556             return (long) (mIntervalMillis * IMPLICIT_MIN_UPDATE_INTERVAL_FACTOR);
557         } else {
558             // the min is only necessary in case someone use a deprecated function to mess with the
559             // interval or min update interval
560             return min(mMinUpdateIntervalMillis, mIntervalMillis);
561         }
562     }
563 
564     /**
565      * @hide
566      * @deprecated LocationRequests should be treated as immutable.
567      */
568     @SystemApi
569     @Deprecated
setSmallestDisplacement(float minDisplacementMeters)570     public @NonNull LocationRequest setSmallestDisplacement(float minDisplacementMeters) {
571         mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minDisplacementMeters, 0,
572                 Float.MAX_VALUE, "minDisplacementMeters");
573         return this;
574     }
575 
576     /**
577      * @hide
578      * @deprecated Use {@link #getMinUpdateDistanceMeters()} instead.
579      */
580     @SystemApi
581     @Deprecated
getSmallestDisplacement()582     public float getSmallestDisplacement() {
583         return getMinUpdateDistanceMeters();
584     }
585 
586     /**
587      * Returns the minimum distance between location updates. If a potential location update is
588      * closer to the last location update than the minimum update distance, then the potential
589      * location update will not occur. A value of 0 meters implies that no location update will ever
590      * be rejected due to failing this constraint.
591      *
592      * @return the minimum distance between location updates
593      */
getMinUpdateDistanceMeters()594     public @FloatRange(from = 0, to = Float.MAX_VALUE) float getMinUpdateDistanceMeters() {
595         return mMinUpdateDistanceMeters;
596     }
597 
598     /**
599      * Returns the maximum time any location update may be delayed, and thus grouped with following
600      * updates to enable location batching. If the maximum update delay is equal to or greater than
601      * twice the interval, then location providers may provide batched results. The maximum batch
602      * size is the maximum update delay divided by the interval. Not all devices or location
603      * providers support batching, and use of this parameter does not guarantee that the client will
604      * see batched results, or that batched results will always be of the maximum size.
605      *
606      * When available, batching can provide substantial power savings to the device, and clients are
607      * encouraged to take advantage where appropriate for the use case.
608      *
609      * @see LocationListener#onLocationChanged(java.util.List)
610      * @return the maximum time by which a location update may be delayed
611      */
getMaxUpdateDelayMillis()612     public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
613         return mMaxUpdateDelayMillis;
614     }
615 
616     /**
617      * @hide
618      * @deprecated LocationRequests should be treated as immutable.
619      */
620     @SystemApi
621     @Deprecated
setHideFromAppOps(boolean hiddenFromAppOps)622     public void setHideFromAppOps(boolean hiddenFromAppOps) {
623         mHideFromAppOps = hiddenFromAppOps;
624     }
625 
626     /**
627      * @hide
628      * @deprecated Use {@link #isHiddenFromAppOps()} instead.
629      */
630     @SystemApi
631     @Deprecated
getHideFromAppOps()632     public boolean getHideFromAppOps() {
633         return isHiddenFromAppOps();
634     }
635 
636     /**
637      * Returns true if this request should be ignored while updating app ops with location usage.
638      * This implies that someone else (usually the creator of the location request) is responsible
639      * for updating app ops.
640      *
641      * @return true if this request should be ignored while updating app ops with location usage
642      *
643      * @hide
644      */
645     @SystemApi
isHiddenFromAppOps()646     public boolean isHiddenFromAppOps() {
647         return mHideFromAppOps;
648     }
649 
650     /**
651      * Returns true if this request may access GNSS even if location settings would normally deny
652      * this, in order to enable automotive safety features. This field is only respected on
653      * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
654      * Driving Assistance Systems) application.
655      *
656      * @return true if all limiting factors will be ignored to satisfy GNSS request
657      *
658      * @hide
659      */
660     @SystemApi
isAdasGnssBypass()661     public boolean isAdasGnssBypass() {
662         return mAdasGnssBypass;
663     }
664 
665     /**
666      * @hide
667      * @deprecated LocationRequests should be treated as immutable.
668      */
669     @SystemApi
670     @Deprecated
671     @RequiresPermission(LOCATION_BYPASS)
setLocationSettingsIgnored(boolean locationSettingsIgnored)672     public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) {
673         mBypass = locationSettingsIgnored;
674         return this;
675     }
676 
677     /**
678      * Returns true if location settings, throttling, background location limits, and any other
679      * possible limiting factors will be ignored in order to satisfy this request.
680      *
681      * @return true if all limiting factors will be ignored to satisfy this request
682      *
683      * @hide
684      */
685     @SystemApi
isLocationSettingsIgnored()686     public boolean isLocationSettingsIgnored() {
687         return mBypass;
688     }
689 
690     /**
691      * Returns true if any bypass flag is set on this request. For internal use only.
692      *
693      * @hide
694      */
isBypass()695     public boolean isBypass() {
696         return mAdasGnssBypass || mBypass;
697     }
698 
699     /**
700      * @hide
701      * @deprecated LocationRequests should be treated as immutable.
702      */
703     @SystemApi
704     @Deprecated
setLowPowerMode(boolean enabled)705     public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
706         mLowPower = enabled;
707         return this;
708     }
709 
710     /**
711      * @hide
712      * @deprecated Use {@link #isLowPower()} instead.
713      */
714     @Deprecated
715     @SystemApi
isLowPowerMode()716     public boolean isLowPowerMode() {
717         return isLowPower();
718     }
719 
720     /**
721      * Returns true if extreme trade-offs should be made to save power for this request. This
722      * usually involves specialized hardware modes which can greatly affect the quality of
723      * locations.
724      *
725      * @return true if extreme trade-offs should be made to save power for this request
726      *
727      * @hide
728      */
729     @SystemApi
isLowPower()730     public boolean isLowPower() {
731         return mLowPower;
732     }
733 
734     /**
735      * @hide
736      * @deprecated LocationRequests should be treated as immutable.
737      */
738     @SystemApi
739     @Deprecated
setWorkSource(@ullable WorkSource workSource)740     public void setWorkSource(@Nullable WorkSource workSource) {
741         if (workSource == null) {
742             workSource = new WorkSource();
743         }
744         mWorkSource = workSource;
745     }
746 
747     /**
748      * Returns the work source used for power blame for this request. If empty, the system is free
749      * to assign power blame as it deems most appropriate.
750      *
751      * @return the work source used for power blame for this request
752      *
753      * @hide
754      */
755     @SystemApi
getWorkSource()756     public @NonNull WorkSource getWorkSource() {
757         return mWorkSource;
758     }
759 
760 
761     public static final @NonNull Parcelable.Creator<LocationRequest> CREATOR =
762             new Parcelable.Creator<LocationRequest>() {
763                 @Override
764                 public LocationRequest createFromParcel(Parcel in) {
765                     return new LocationRequest(
766                             /* provider= */ in.readString(),
767                             /* intervalMillis= */ in.readLong(),
768                             /* quality= */ in.readInt(),
769                             /* expireAtRealtimeMillis= */ in.readLong(),
770                             /* durationMillis= */ in.readLong(),
771                             /* maxUpdates= */ in.readInt(),
772                             /* minUpdateIntervalMillis= */ in.readLong(),
773                             /* minUpdateDistanceMeters= */ in.readFloat(),
774                             /* maxUpdateDelayMillis= */ in.readLong(),
775                             /* hiddenFromAppOps= */ in.readBoolean(),
776                             /* adasGnssBypass= */ in.readBoolean(),
777                             /* locationSettingsIgnored= */ in.readBoolean(),
778                             /* lowPower= */ in.readBoolean(),
779                             /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
780                 }
781 
782                 @Override
783                 public LocationRequest[] newArray(int size) {
784                     return new LocationRequest[size];
785                 }
786             };
787 
788     @Override
describeContents()789     public int describeContents() {
790         return 0;
791     }
792 
793     @Override
writeToParcel(@onNull Parcel parcel, int flags)794     public void writeToParcel(@NonNull Parcel parcel, int flags) {
795         parcel.writeString(mProvider);
796         parcel.writeLong(mIntervalMillis);
797         parcel.writeInt(mQuality);
798         parcel.writeLong(mExpireAtRealtimeMillis);
799         parcel.writeLong(mDurationMillis);
800         parcel.writeInt(mMaxUpdates);
801         parcel.writeLong(mMinUpdateIntervalMillis);
802         parcel.writeFloat(mMinUpdateDistanceMeters);
803         parcel.writeLong(mMaxUpdateDelayMillis);
804         parcel.writeBoolean(mHideFromAppOps);
805         parcel.writeBoolean(mAdasGnssBypass);
806         parcel.writeBoolean(mBypass);
807         parcel.writeBoolean(mLowPower);
808         parcel.writeTypedObject(mWorkSource, 0);
809     }
810 
811     @Override
equals(Object o)812     public boolean equals(Object o) {
813         if (this == o) {
814             return true;
815         }
816         if (o == null || getClass() != o.getClass()) {
817             return false;
818         }
819 
820         LocationRequest that = (LocationRequest) o;
821         return mIntervalMillis == that.mIntervalMillis
822                 && mQuality == that.mQuality
823                 && mExpireAtRealtimeMillis == that.mExpireAtRealtimeMillis
824                 && mDurationMillis == that.mDurationMillis
825                 && mMaxUpdates == that.mMaxUpdates
826                 && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
827                 && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
828                 && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
829                 && mHideFromAppOps == that.mHideFromAppOps
830                 && mAdasGnssBypass == that.mAdasGnssBypass
831                 && mBypass == that.mBypass
832                 && mLowPower == that.mLowPower
833                 && Objects.equals(mProvider, that.mProvider)
834                 && Objects.equals(mWorkSource, that.mWorkSource);
835     }
836 
837     @Override
hashCode()838     public int hashCode() {
839         return Objects.hash(mProvider, mIntervalMillis, mWorkSource);
840     }
841 
842     @NonNull
843     @Override
toString()844     public String toString() {
845         StringBuilder s = new StringBuilder();
846         s.append("Request[");
847         if (mProvider != null) {
848             s.append(mProvider).append(" ");
849         }
850         if (mIntervalMillis != PASSIVE_INTERVAL) {
851             s.append("@");
852             TimeUtils.formatDuration(mIntervalMillis, s);
853 
854             switch (mQuality) {
855                 case QUALITY_HIGH_ACCURACY:
856                     s.append(" HIGH_ACCURACY");
857                     break;
858                 case QUALITY_BALANCED_POWER_ACCURACY:
859                     s.append(" BALANCED");
860                     break;
861                 case QUALITY_LOW_POWER:
862                     s.append(" LOW_POWER");
863                     break;
864             }
865         } else {
866             s.append("PASSIVE");
867         }
868         if (mExpireAtRealtimeMillis != Long.MAX_VALUE) {
869             s.append(", expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
870         }
871         if (mDurationMillis != Long.MAX_VALUE) {
872             s.append(", duration=");
873             TimeUtils.formatDuration(mDurationMillis, s);
874         }
875         if (mMaxUpdates != Integer.MAX_VALUE) {
876             s.append(", maxUpdates=").append(mMaxUpdates);
877         }
878         if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL
879                 && mMinUpdateIntervalMillis < mIntervalMillis) {
880             s.append(", minUpdateInterval=");
881             TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
882         }
883         if (mMinUpdateDistanceMeters > 0.0) {
884             s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
885         }
886         if (mMaxUpdateDelayMillis / 2 > mIntervalMillis) {
887             s.append(", maxUpdateDelay=");
888             TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
889         }
890         if (mLowPower) {
891             s.append(", lowPower");
892         }
893         if (mHideFromAppOps) {
894             s.append(", hiddenFromAppOps");
895         }
896         if (mAdasGnssBypass) {
897             s.append(", adasGnssBypass");
898         }
899         if (mBypass) {
900             s.append(", bypass");
901         }
902         if (mWorkSource != null && !mWorkSource.isEmpty()) {
903             s.append(", ").append(mWorkSource);
904         }
905         s.append(']');
906         return s.toString();
907     }
908 
909     /**
910      * A builder class for {@link LocationRequest}.
911      */
912     public static final class Builder {
913 
914         private long mIntervalMillis;
915         private @Quality int mQuality;
916         private long mDurationMillis;
917         private int mMaxUpdates;
918         private long mMinUpdateIntervalMillis;
919         private float mMinUpdateDistanceMeters;
920         private long mMaxUpdateDelayMillis;
921         private boolean mHiddenFromAppOps;
922         private boolean mAdasGnssBypass;
923         private boolean mBypass;
924         private boolean mLowPower;
925         @Nullable private WorkSource mWorkSource;
926 
927         /**
928          * Creates a new Builder with the given interval. See {@link #setIntervalMillis(long)} for
929          * more information on the interval.
930          */
Builder(long intervalMillis)931         public Builder(long intervalMillis) {
932             // gives us a range check
933             setIntervalMillis(intervalMillis);
934 
935             mQuality = QUALITY_BALANCED_POWER_ACCURACY;
936             mDurationMillis = Long.MAX_VALUE;
937             mMaxUpdates = Integer.MAX_VALUE;
938             mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
939             mMinUpdateDistanceMeters = 0;
940             mMaxUpdateDelayMillis = 0;
941             mHiddenFromAppOps = false;
942             mAdasGnssBypass = false;
943             mBypass = false;
944             mLowPower = false;
945             mWorkSource = null;
946         }
947 
948         /**
949          * Creates a new Builder with all parameters copied from the given location request.
950          */
Builder(@onNull LocationRequest locationRequest)951         public Builder(@NonNull LocationRequest locationRequest) {
952             mIntervalMillis = locationRequest.mIntervalMillis;
953             mQuality = locationRequest.mQuality;
954             mDurationMillis = locationRequest.mDurationMillis;
955             mMaxUpdates = locationRequest.mMaxUpdates;
956             mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
957             mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
958             mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
959             mHiddenFromAppOps = locationRequest.mHideFromAppOps;
960             mAdasGnssBypass = locationRequest.mAdasGnssBypass;
961             mBypass = locationRequest.mBypass;
962             mLowPower = locationRequest.mLowPower;
963             mWorkSource = locationRequest.mWorkSource;
964 
965             // handle edge cases that can only happen with location request that has been modified
966             // by deprecated SystemApi methods
967             if (mIntervalMillis == PASSIVE_INTERVAL
968                     && mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
969                 // this is the legacy default minimum update interval, so if we're forced to
970                 // change the value, at least this should be unsuprising to legacy clients (which
971                 // should be the only clients capable of getting in this weird state).
972                 mMinUpdateIntervalMillis = 10 * 60 * 1000;
973             }
974         }
975 
976         /**
977          * Sets the request interval. The request interval may be set to {@link #PASSIVE_INTERVAL}
978          * which indicates this request will not actively generate location updates (and thus will
979          * not be power blamed for location), but may receive location updates generated as a result
980          * of other location requests. A passive request must always have an explicit minimum
981          * update interval set.
982          *
983          * <p>Locations may be available at a faster interval than specified here, see
984          * {@link #setMinUpdateIntervalMillis(long)} for the behavior in that case.
985          */
setIntervalMillis(@ntRangefrom = 0) long intervalMillis)986         public @NonNull Builder setIntervalMillis(@IntRange(from = 0) long intervalMillis) {
987             mIntervalMillis = Preconditions.checkArgumentInRange(intervalMillis, 0, Long.MAX_VALUE,
988                     "intervalMillis");
989             return this;
990         }
991 
992         /**
993          * Sets the request quality. The quality is a hint to providers on how they should weigh
994          * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
995          * lower accuracy locations may cost less power to produce. Defaults to
996          * {@link #QUALITY_BALANCED_POWER_ACCURACY}.
997          */
setQuality(@uality int quality)998         public @NonNull Builder setQuality(@Quality int quality) {
999             Preconditions.checkArgument(
1000                     quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
1001                             || quality == QUALITY_HIGH_ACCURACY,
1002                     "quality must be a defined QUALITY constant, not %d", quality);
1003             mQuality = quality;
1004             return this;
1005         }
1006 
1007         /**
1008          * @hide
1009          */
setQuality(@onNull Criteria criteria)1010         public @NonNull Builder setQuality(@NonNull Criteria criteria) {
1011             switch (criteria.getAccuracy()) {
1012                 case Criteria.ACCURACY_COARSE:
1013                     mQuality = QUALITY_BALANCED_POWER_ACCURACY;
1014                     break;
1015                 case Criteria.ACCURACY_FINE:
1016                     mQuality = QUALITY_HIGH_ACCURACY;
1017                     break;
1018                 default: {
1019                     if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
1020                         mQuality = POWER_HIGH;
1021                     } else {
1022                         mQuality = POWER_LOW;
1023                     }
1024                 }
1025             }
1026             return this;
1027         }
1028 
1029         /**
1030          * Sets the duration this request will continue before being automatically removed. Defaults
1031          * to <code>Long.MAX_VALUE</code>, which represents an unlimited duration.
1032          */
setDurationMillis(@ntRangefrom = 1) long durationMillis)1033         public @NonNull Builder setDurationMillis(@IntRange(from = 1) long durationMillis) {
1034             mDurationMillis = Preconditions.checkArgumentInRange(durationMillis, 1, Long.MAX_VALUE,
1035                     "durationMillis");
1036             return this;
1037         }
1038 
1039         /**
1040          * Sets the maximum number of location updates for this request before this request is
1041          * automatically removed. Defaults to <code>Integer.MAX_VALUE</code>, which represents an
1042          * unlimited number of updates.
1043          */
setMaxUpdates( @ntRangefrom = 1, to = Integer.MAX_VALUE) int maxUpdates)1044         public @NonNull Builder setMaxUpdates(
1045                 @IntRange(from = 1, to = Integer.MAX_VALUE) int maxUpdates) {
1046             mMaxUpdates = Preconditions.checkArgumentInRange(maxUpdates, 1, Integer.MAX_VALUE,
1047                     "maxUpdates");
1048             return this;
1049         }
1050 
1051         /**
1052          * Sets an explicit minimum update interval. If location updates are available faster than
1053          * the request interval then an update will only occur if the minimum update interval has
1054          * expired since the last location update. Defaults to no explicit minimum update interval
1055          * set, which means some sensible default between 0 and the interval will be chosen. The
1056          * exact value is not specified at the moment. If an exact known value is required, clients
1057          * should set an explicit value themselves.
1058          *
1059          * <p class=note><strong>Note:</strong> Some allowance for jitter is already built into the
1060          * minimum update interval, so you need not worry about updates blocked simply because they
1061          * arrived a fraction of a second earlier than expected.
1062          *
1063          * <p class="note"><strong>Note:</strong> When {@link #build()} is invoked, the minimum of
1064          * the interval and the minimum update interval will be used as the minimum update interval
1065          * of the built request.
1066          */
setMinUpdateIntervalMillis( @ntRangefrom = 0) long minUpdateIntervalMillis)1067         public @NonNull Builder setMinUpdateIntervalMillis(
1068                 @IntRange(from = 0) long minUpdateIntervalMillis) {
1069             mMinUpdateIntervalMillis = Preconditions.checkArgumentInRange(minUpdateIntervalMillis,
1070                     0, Long.MAX_VALUE, "minUpdateIntervalMillis");
1071             return this;
1072         }
1073 
1074         /**
1075          * Clears an explicitly set minimum update interval and reverts to an implicit minimum
1076          * update interval (ie, the minimum update interval is some sensible default between 0 and
1077          * the interval).
1078          */
clearMinUpdateIntervalMillis()1079         public @NonNull Builder clearMinUpdateIntervalMillis() {
1080             mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
1081             return this;
1082         }
1083 
1084         /**
1085          * Sets the minimum update distance between location updates. If a potential location
1086          * update is closer to the last location update than the minimum update distance, then
1087          * the potential location update will not occur. Defaults to 0, which represents no minimum
1088          * update distance.
1089          */
setMinUpdateDistanceMeters( @loatRangefrom = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters)1090         public @NonNull Builder setMinUpdateDistanceMeters(
1091                 @FloatRange(from = 0, to = Float.MAX_VALUE) float minUpdateDistanceMeters) {
1092             mMinUpdateDistanceMeters = Preconditions.checkArgumentInRange(minUpdateDistanceMeters,
1093                     0, Float.MAX_VALUE, "minUpdateDistanceMeters");
1094             return this;
1095         }
1096 
1097         /**
1098          * Sets the maximum time any location update may be delayed, and thus grouped with following
1099          * updates to enable location batching. If the maximum update delay is equal to or greater
1100          * than twice the interval, then location providers may provide batched results. Defaults to
1101          * 0, which represents no batching allowed.
1102          */
setMaxUpdateDelayMillis( @ntRangefrom = 0) long maxUpdateDelayMillis)1103         public @NonNull Builder setMaxUpdateDelayMillis(
1104                 @IntRange(from = 0) long maxUpdateDelayMillis) {
1105             mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
1106                     Long.MAX_VALUE, "maxUpdateDelayMillis");
1107             return this;
1108         }
1109 
1110         /**
1111          * If set to true, indicates that app ops should not be updated with location usage due to
1112          * this request. This implies that someone else (usually the creator of the location
1113          * request) is responsible for updating app ops as appropriate. Defaults to false.
1114          *
1115          * <p>Permissions enforcement occurs when resulting location request is actually used, not
1116          * when this method is invoked.
1117          *
1118          * @hide
1119          */
1120         @SystemApi
1121         @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS)
setHiddenFromAppOps(boolean hiddenFromAppOps)1122         public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) {
1123             mHiddenFromAppOps = hiddenFromAppOps;
1124             return this;
1125         }
1126 
1127         /**
1128          * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
1129          * Systems) client, which requires access to GNSS even if location settings would normally
1130          * deny this, in order to enable auto safety features. This field is only respected on
1131          * automotive devices, and only if the client is recognized as a legitimate ADAS
1132          * application. Defaults to false.
1133          *
1134          * <p>Permissions enforcement occurs when resulting location request is actually used, not
1135          * when this method is invoked.
1136          *
1137          * @hide
1138          */
1139         @SystemApi
1140         @RequiresPermission(LOCATION_BYPASS)
1141         @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
setAdasGnssBypass(boolean adasGnssBypass)1142         public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
1143             mAdasGnssBypass = adasGnssBypass;
1144             return this;
1145         }
1146 
1147         /**
1148          * If set to true, indicates that location settings, throttling, background location limits,
1149          * and any other possible limiting factors should be ignored in order to satisfy this
1150          * request. This is only intended for use in user initiated emergency situations, and
1151          * should be used extremely cautiously. Defaults to false.
1152          *
1153          * <p>Permissions enforcement occurs when resulting location request is actually used, not
1154          * when this method is invoked.
1155          *
1156          * @hide
1157          */
1158         @SystemApi
1159         @RequiresPermission(LOCATION_BYPASS)
setLocationSettingsIgnored(boolean locationSettingsIgnored)1160         public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
1161             mBypass = locationSettingsIgnored;
1162             return this;
1163         }
1164 
1165         /**
1166          * It set to true, indicates that extreme trade-offs should be made if possible to save
1167          * power for this request. This usually involves specialized hardware modes which can
1168          * greatly affect the quality of locations. Not all devices may support this. Defaults to
1169          * false.
1170          *
1171          * <p>Permissions enforcement occurs when resulting location request is actually used, not
1172          * when this method is invoked.
1173          *
1174          * @hide
1175          */
1176         @SystemApi
1177         @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
setLowPower(boolean lowPower)1178         public @NonNull Builder setLowPower(boolean lowPower) {
1179             mLowPower = lowPower;
1180             return this;
1181         }
1182 
1183         /**
1184          * Sets the work source to use for power blame for this location request. Defaults to an
1185          * empty WorkSource, which implies the system is free to assign power blame as it determines
1186          * best for this request (which usually means blaming the owner of the location listener).
1187          *
1188          * <p>Permissions enforcement occurs when resulting location request is actually used, not
1189          * when this method is invoked.
1190          *
1191          * @hide
1192          */
1193         @SystemApi
1194         @RequiresPermission(Manifest.permission.UPDATE_DEVICE_STATS)
setWorkSource(@ullable WorkSource workSource)1195         public @NonNull Builder setWorkSource(@Nullable WorkSource workSource) {
1196             mWorkSource = workSource;
1197             return this;
1198         }
1199 
1200         /**
1201          * Builds a location request from this builder. If an explicit minimum update interval is
1202          * set, the minimum update interval of the location request will be the minimum of the
1203          * interval and minimum update interval.
1204          *
1205          * <p>If building a passive request then you must have set an explicit minimum update
1206          * interval.
1207          *
1208          * @throws IllegalStateException if building a passive request with no explicit minimum
1209          * update interval set
1210          * @return a new location request
1211          */
build()1212         public @NonNull LocationRequest build() {
1213             Preconditions.checkState(mIntervalMillis != PASSIVE_INTERVAL
1214                             || mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL,
1215                     "passive location requests must have an explicit minimum update interval");
1216 
1217             return new LocationRequest(
1218                     null,
1219                     mIntervalMillis,
1220                     mQuality,
1221                     Long.MAX_VALUE,
1222                     mDurationMillis,
1223                     mMaxUpdates,
1224                     min(mMinUpdateIntervalMillis, mIntervalMillis),
1225                     mMinUpdateDistanceMeters,
1226                     mMaxUpdateDelayMillis,
1227                     mHiddenFromAppOps,
1228                     mAdasGnssBypass,
1229                     mBypass,
1230                     mLowPower,
1231                     new WorkSource(mWorkSource));
1232         }
1233     }
1234 }
1235