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