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