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