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