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