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