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