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