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 break; 216 default: 217 quality = POWER_LOW; 218 } 219 } 220 } 221 222 LocationRequest request = new LocationRequest() 223 .setQuality(quality) 224 .setInterval(minTime) 225 .setFastestInterval(minTime) 226 .setSmallestDisplacement(minDistance); 227 if (singleShot) request.setNumUpdates(1); 228 return request; 229 } 230 231 /** @hide */ LocationRequest()232 public LocationRequest() { } 233 234 /** @hide */ LocationRequest(LocationRequest src)235 public LocationRequest(LocationRequest src) { 236 mQuality = src.mQuality; 237 mInterval = src.mInterval; 238 mFastestInterval = src.mFastestInterval; 239 mExplicitFastestInterval = src.mExplicitFastestInterval; 240 mExpireAt = src.mExpireAt; 241 mNumUpdates = src.mNumUpdates; 242 mSmallestDisplacement = src.mSmallestDisplacement; 243 mProvider = src.mProvider; 244 mWorkSource = src.mWorkSource; 245 mHideFromAppOps = src.mHideFromAppOps; 246 } 247 248 /** 249 * Set the quality of the request. 250 * 251 * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power 252 * constant such as {@link #POWER_LOW}. You cannot request both and accuracy and 253 * power, only one or the other can be specified. The system will then 254 * maximize accuracy or minimize power as appropriate. 255 * 256 * <p>The quality of the request is a strong hint to the system for which 257 * location sources to use. For example, {@link #ACCURACY_FINE} is more likely 258 * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower 259 * positioning, but it also depends on many other factors (such as which sources 260 * are available) and is implementation dependent. 261 * 262 * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters 263 * on a location request. 264 * 265 * @param quality an accuracy or power constant 266 * @throws InvalidArgumentException if the quality constant is not valid 267 * @return the same object, so that setters can be chained 268 */ setQuality(int quality)269 public LocationRequest setQuality(int quality) { 270 checkQuality(quality); 271 mQuality = quality; 272 return this; 273 } 274 275 /** 276 * Get the quality of the request. 277 * 278 * @return an accuracy or power constant 279 */ getQuality()280 public int getQuality() { 281 return mQuality; 282 } 283 284 /** 285 * Set the desired interval for active location updates, in milliseconds. 286 * 287 * <p>The location manager will actively try to obtain location updates 288 * for your application at this interval, so it has a 289 * direct influence on the amount of power used by your application. 290 * Choose your interval wisely. 291 * 292 * <p>This interval is inexact. You may not receive updates at all (if 293 * no location sources are available), or you may receive them 294 * slower than requested. You may also receive them faster than 295 * requested (if other applications are requesting location at a 296 * faster interval). The fastest rate that you will receive 297 * updates can be controlled with {@link #setFastestInterval}. 298 * 299 * <p>Applications with only the coarse location permission may have their 300 * interval silently throttled. 301 * 302 * <p>An interval of 0 is allowed, but not recommended, since 303 * location updates may be extremely fast on future implementations. 304 * 305 * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters 306 * on a location request. 307 * 308 * @param millis desired interval in millisecond, inexact 309 * @throws InvalidArgumentException if the interval is less than zero 310 * @return the same object, so that setters can be chained 311 */ setInterval(long millis)312 public LocationRequest setInterval(long millis) { 313 checkInterval(millis); 314 mInterval = millis; 315 if (!mExplicitFastestInterval) { 316 mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR); 317 } 318 return this; 319 } 320 321 /** 322 * Get the desired interval of this request, in milliseconds. 323 * 324 * @return desired interval in milliseconds, inexact 325 */ getInterval()326 public long getInterval() { 327 return mInterval; 328 } 329 330 /** 331 * Explicitly set the fastest interval for location updates, in 332 * milliseconds. 333 * 334 * <p>This controls the fastest rate at which your application will 335 * receive location updates, which might be faster than 336 * {@link #setInterval} in some situations (for example, if other 337 * applications are triggering location updates). 338 * 339 * <p>This allows your application to passively acquire locations 340 * at a rate faster than it actively acquires locations, saving power. 341 * 342 * <p>Unlike {@link #setInterval}, this parameter is exact. Your 343 * application will never receive updates faster than this value. 344 * 345 * <p>If you don't call this method, a fastest interval 346 * will be selected for you. It will be a value faster than your 347 * active interval ({@link #setInterval}). 348 * 349 * <p>An interval of 0 is allowed, but not recommended, since 350 * location updates may be extremely fast on future implementations. 351 * 352 * <p>If {@link #setFastestInterval} is set slower than {@link #setInterval}, 353 * then your effective fastest interval is {@link #setInterval}. 354 * 355 * @param millis fastest interval for updates in milliseconds, exact 356 * @throws InvalidArgumentException if the interval is less than zero 357 * @return the same object, so that setters can be chained 358 */ setFastestInterval(long millis)359 public LocationRequest setFastestInterval(long millis) { 360 checkInterval(millis); 361 mExplicitFastestInterval = true; 362 mFastestInterval = millis; 363 return this; 364 } 365 366 /** 367 * Get the fastest interval of this request, in milliseconds. 368 * 369 * <p>The system will never provide location updates faster 370 * than the minimum of {@link #getFastestInterval} and 371 * {@link #getInterval}. 372 * 373 * @return fastest interval in milliseconds, exact 374 */ getFastestInterval()375 public long getFastestInterval() { 376 return mFastestInterval; 377 } 378 379 /** 380 * Set the duration of this request, in milliseconds. 381 * 382 * <p>The duration begins immediately (and not when the request 383 * is passed to the location manager), so call this method again 384 * if the request is re-used at a later time. 385 * 386 * <p>The location manager will automatically stop updates after 387 * the request expires. 388 * 389 * <p>The duration includes suspend time. Values less than 0 390 * are allowed, but indicate that the request has already expired. 391 * 392 * @param millis duration of request in milliseconds 393 * @return the same object, so that setters can be chained 394 */ setExpireIn(long millis)395 public LocationRequest setExpireIn(long millis) { 396 long elapsedRealtime = SystemClock.elapsedRealtime(); 397 398 // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0): 399 if (millis > Long.MAX_VALUE - elapsedRealtime) { 400 mExpireAt = Long.MAX_VALUE; 401 } else { 402 mExpireAt = millis + elapsedRealtime; 403 } 404 405 if (mExpireAt < 0) mExpireAt = 0; 406 return this; 407 } 408 409 /** 410 * Set the request expiration time, in millisecond since boot. 411 * 412 * <p>This expiration time uses the same time base as {@link SystemClock#elapsedRealtime}. 413 * 414 * <p>The location manager will automatically stop updates after 415 * the request expires. 416 * 417 * <p>The duration includes suspend time. Values before {@link SystemClock#elapsedRealtime} 418 * are allowed, but indicate that the request has already expired. 419 * 420 * @param millis expiration time of request, in milliseconds since boot including suspend 421 * @return the same object, so that setters can be chained 422 */ setExpireAt(long millis)423 public LocationRequest setExpireAt(long millis) { 424 mExpireAt = millis; 425 if (mExpireAt < 0) mExpireAt = 0; 426 return this; 427 } 428 429 /** 430 * Get the request expiration time, in milliseconds since boot. 431 * 432 * <p>This value can be compared to {@link SystemClock#elapsedRealtime} to determine 433 * the time until expiration. 434 * 435 * @return expiration time of request, in milliseconds since boot including suspend 436 */ getExpireAt()437 public long getExpireAt() { 438 return mExpireAt; 439 } 440 441 /** 442 * Set the number of location updates. 443 * 444 * <p>By default locations are continuously updated until the request is explicitly 445 * removed, however you can optionally request a set number of updates. 446 * For example, if your application only needs a single fresh location, 447 * then call this method with a value of 1 before passing the request 448 * to the location manager. 449 * 450 * @param numUpdates the number of location updates requested 451 * @throws InvalidArgumentException if numUpdates is 0 or less 452 * @return the same object, so that setters can be chained 453 */ setNumUpdates(int numUpdates)454 public LocationRequest setNumUpdates(int numUpdates) { 455 if (numUpdates <= 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates); 456 mNumUpdates = numUpdates; 457 return this; 458 } 459 460 /** 461 * Get the number of updates requested. 462 * 463 * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that 464 * locations are updated until the request is explicitly removed. 465 * @return number of updates 466 */ getNumUpdates()467 public int getNumUpdates() { 468 return mNumUpdates; 469 } 470 471 /** @hide */ decrementNumUpdates()472 public void decrementNumUpdates() { 473 if (mNumUpdates != Integer.MAX_VALUE) { 474 mNumUpdates--; 475 } 476 if (mNumUpdates < 0) { 477 mNumUpdates = 0; 478 } 479 } 480 481 482 /** @hide */ 483 @SystemApi setProvider(String provider)484 public LocationRequest setProvider(String provider) { 485 checkProvider(provider); 486 mProvider = provider; 487 return this; 488 } 489 490 /** @hide */ 491 @SystemApi getProvider()492 public String getProvider() { 493 return mProvider; 494 } 495 496 /** @hide */ 497 @SystemApi setSmallestDisplacement(float meters)498 public LocationRequest setSmallestDisplacement(float meters) { 499 checkDisplacement(meters); 500 mSmallestDisplacement = meters; 501 return this; 502 } 503 504 /** @hide */ 505 @SystemApi getSmallestDisplacement()506 public float getSmallestDisplacement() { 507 return mSmallestDisplacement; 508 } 509 510 /** 511 * Sets the WorkSource to use for power blaming of this location request. 512 * 513 * <p>No permissions are required to make this call, however the LocationManager 514 * will throw a SecurityException when requesting location updates if the caller 515 * doesn't have the {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission. 516 * 517 * @param workSource WorkSource defining power blame for this location request. 518 * @hide 519 */ 520 @SystemApi setWorkSource(WorkSource workSource)521 public void setWorkSource(WorkSource workSource) { 522 mWorkSource = workSource; 523 } 524 525 /** @hide */ 526 @SystemApi getWorkSource()527 public WorkSource getWorkSource() { 528 return mWorkSource; 529 } 530 531 /** 532 * Sets whether or not this location request should be hidden from AppOps. 533 * 534 * <p>Hiding a location request from AppOps will remove user visibility in the UI as to this 535 * request's existence. It does not affect power blaming in the Battery page. 536 * 537 * <p>No permissions are required to make this call, however the LocationManager 538 * will throw a SecurityException when requesting location updates if the caller 539 * doesn't have the {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} permission. 540 * 541 * @param hideFromAppOps If true AppOps won't keep track of this location request. 542 * @see android.app.AppOpsManager 543 * @hide 544 */ 545 @SystemApi setHideFromAppOps(boolean hideFromAppOps)546 public void setHideFromAppOps(boolean hideFromAppOps) { 547 mHideFromAppOps = hideFromAppOps; 548 } 549 550 /** @hide */ 551 @SystemApi getHideFromAppOps()552 public boolean getHideFromAppOps() { 553 return mHideFromAppOps; 554 } 555 checkInterval(long millis)556 private static void checkInterval(long millis) { 557 if (millis < 0) { 558 throw new IllegalArgumentException("invalid interval: " + millis); 559 } 560 } 561 checkQuality(int quality)562 private static void checkQuality(int quality) { 563 switch (quality) { 564 case ACCURACY_FINE: 565 case ACCURACY_BLOCK: 566 case ACCURACY_CITY: 567 case POWER_NONE: 568 case POWER_LOW: 569 case POWER_HIGH: 570 break; 571 default: 572 throw new IllegalArgumentException("invalid quality: " + quality); 573 } 574 } 575 checkDisplacement(float meters)576 private static void checkDisplacement(float meters) { 577 if (meters < 0.0f) { 578 throw new IllegalArgumentException("invalid displacement: " + meters); 579 } 580 } 581 checkProvider(String name)582 private static void checkProvider(String name) { 583 if (name == null) { 584 throw new IllegalArgumentException("invalid provider: " + name); 585 } 586 } 587 588 public static final Parcelable.Creator<LocationRequest> CREATOR = 589 new Parcelable.Creator<LocationRequest>() { 590 @Override 591 public LocationRequest createFromParcel(Parcel in) { 592 LocationRequest request = new LocationRequest(); 593 request.setQuality(in.readInt()); 594 request.setFastestInterval(in.readLong()); 595 request.setInterval(in.readLong()); 596 request.setExpireAt(in.readLong()); 597 request.setNumUpdates(in.readInt()); 598 request.setSmallestDisplacement(in.readFloat()); 599 request.setHideFromAppOps(in.readInt() != 0); 600 String provider = in.readString(); 601 if (provider != null) request.setProvider(provider); 602 WorkSource workSource = in.readParcelable(null); 603 if (workSource != null) request.setWorkSource(workSource); 604 return request; 605 } 606 @Override 607 public LocationRequest[] newArray(int size) { 608 return new LocationRequest[size]; 609 } 610 }; 611 612 @Override describeContents()613 public int describeContents() { 614 return 0; 615 } 616 617 @Override writeToParcel(Parcel parcel, int flags)618 public void writeToParcel(Parcel parcel, int flags) { 619 parcel.writeInt(mQuality); 620 parcel.writeLong(mFastestInterval); 621 parcel.writeLong(mInterval); 622 parcel.writeLong(mExpireAt); 623 parcel.writeInt(mNumUpdates); 624 parcel.writeFloat(mSmallestDisplacement); 625 parcel.writeInt(mHideFromAppOps ? 1 : 0); 626 parcel.writeString(mProvider); 627 parcel.writeParcelable(mWorkSource, 0); 628 } 629 630 /** @hide */ qualityToString(int quality)631 public static String qualityToString(int quality) { 632 switch (quality) { 633 case ACCURACY_FINE: 634 return "ACCURACY_FINE"; 635 case ACCURACY_BLOCK: 636 return "ACCURACY_BLOCK"; 637 case ACCURACY_CITY: 638 return "ACCURACY_CITY"; 639 case POWER_NONE: 640 return "POWER_NONE"; 641 case POWER_LOW: 642 return "POWER_LOW"; 643 case POWER_HIGH: 644 return "POWER_HIGH"; 645 default: 646 return "???"; 647 } 648 } 649 650 @Override toString()651 public String toString() { 652 StringBuilder s = new StringBuilder(); 653 s.append("Request[").append(qualityToString(mQuality)); 654 if (mProvider != null) s.append(' ').append(mProvider); 655 if (mQuality != POWER_NONE) { 656 s.append(" requested="); 657 TimeUtils.formatDuration(mInterval, s); 658 } 659 s.append(" fastest="); 660 TimeUtils.formatDuration(mFastestInterval, s); 661 if (mExpireAt != Long.MAX_VALUE) { 662 long expireIn = mExpireAt - SystemClock.elapsedRealtime(); 663 s.append(" expireIn="); 664 TimeUtils.formatDuration(expireIn, s); 665 } 666 if (mNumUpdates != Integer.MAX_VALUE){ 667 s.append(" num=").append(mNumUpdates); 668 } 669 s.append(']'); 670 return s.toString(); 671 } 672 } 673