LocationManager.java revision 8761e143c987fc48d854818988cde44700c9f602
1/* 2 * Copyright (C) 2007 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.app.PendingIntent; 20import android.content.Context; 21import android.content.Intent; 22import android.os.Build; 23import android.os.Bundle; 24import android.os.Looper; 25import android.os.RemoteException; 26import android.os.Handler; 27import android.os.Message; 28import android.util.Log; 29 30 31import java.util.ArrayList; 32import java.util.HashMap; 33import java.util.List; 34 35import com.android.internal.location.ProviderProperties; 36 37/** 38 * This class provides access to the system location services. These 39 * services allow applications to obtain periodic updates of the 40 * device's geographical location, or to fire an application-specified 41 * {@link Intent} when the device enters the proximity of a given 42 * geographical location. 43 * 44 * <p>You do not 45 * instantiate this class directly; instead, retrieve it through 46 * {@link android.content.Context#getSystemService 47 * Context.getSystemService(Context.LOCATION_SERVICE)}. 48 * 49 * <p>At API version 17 the Location API's were simplified. 50 * Previously applications would need to explicitly enumerate, select, and 51 * track Location Providers (such as GPS or Network). 52 * This has been replaced by the concept of 53 * <em>Fused Location</em>. Now applications just specify the quality of service 54 * required for location updates (using the new {@link LocationRequest} class), 55 * and the system will fuse results from individual location providers 56 * as necessary before returning the result to the application. 57 * 58 * <p>As a result of this change, the {@link LocationProvider} and 59 * {@link Criteria} classes have been deprecated, in favor of 60 * {@link LocationRequest}. Furthermore, all Location Manager 61 * methods involving Criteria or explicitly named Providers have 62 * been deprecated, in favor of new variants that use 63 * {@link LocationRequest}. 64 * 65 * <p>A single {@link LocationRequest} object can trigger the use 66 * of all providers (including GPS, Network, and the passive) provider 67 * as necessary. This should result in a lot less work for your application. You 68 * no longer need to track the status and availability of each 69 * location provider. Just set the quality of locations required 70 * in {@link LocationRequest}, and let the system manage the rest. 71 * 72 * <p class="note">Unless noted, all Location API methods require 73 * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or 74 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. 75 * If your application only has the coarse permission then it will not have 76 * access to the GPS or passive location providers. Other providers will still 77 * return location results, but the update rate will be throttled and the exact 78 * location will be obfuscated to a coarse level of accuracy. 79 */ 80public class LocationManager { 81 private static final String TAG = "LocationManager"; 82 83 private final Context mContext; 84 private final ILocationManager mService; 85 private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners = 86 new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>(); 87 private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners = 88 new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>(); 89 private final GpsStatus mGpsStatus = new GpsStatus(); 90 91 /** 92 * Name of the network location provider. 93 * <p>This provider determines location based on 94 * availability of cell tower and WiFi access points. Results are retrieved 95 * by means of a network lookup. 96 * 97 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 98 */ 99 @Deprecated 100 public static final String NETWORK_PROVIDER = "network"; 101 102 /** 103 * Name of the GPS location provider. 104 * 105 * <p>This provider determines location using 106 * satellites. Depending on conditions, this provider may take a while to return 107 * a location fix. Requires the permission 108 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. 109 * 110 * <p> The extras Bundle for the GPS location provider can contain the 111 * following key/value pairs: 112 * <ul> 113 * <li> satellites - the number of satellites used to derive the fix 114 * </ul> 115 * 116 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 117 */ 118 @Deprecated 119 public static final String GPS_PROVIDER = "gps"; 120 121 /** 122 * A special location provider for receiving locations without actually initiating 123 * a location fix. 124 * 125 * <p>This provider can be used to passively receive location updates 126 * when other applications or services request them without actually requesting 127 * the locations yourself. This provider will return locations generated by other 128 * providers. You can query the {@link Location#getProvider()} method to determine 129 * the origin of the location update. Requires the permission 130 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is 131 * not enabled this provider might only return coarse fixes. 132 * 133 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 134 */ 135 @Deprecated 136 public static final String PASSIVE_PROVIDER = "passive"; 137 138 /** 139 * Name of the Fused location provider. 140 * 141 * <p>This provider combines inputs for all possible location sources 142 * to provide the best possible Location fix. It is implicitly 143 * used for all API's that involve the {@link LocationRequest} 144 * object. 145 * 146 * @hide 147 */ 148 public static final String FUSED_PROVIDER = "fused"; 149 150 /** 151 * Key used for the Bundle extra holding a boolean indicating whether 152 * a proximity alert is entering (true) or exiting (false).. 153 */ 154 public static final String KEY_PROXIMITY_ENTERING = "entering"; 155 156 /** 157 * Key used for a Bundle extra holding an Integer status value 158 * when a status change is broadcast using a PendingIntent. 159 * 160 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 161 */ 162 @Deprecated 163 public static final String KEY_STATUS_CHANGED = "status"; 164 165 /** 166 * Key used for a Bundle extra holding an Boolean status value 167 * when a provider enabled/disabled event is broadcast using a PendingIntent. 168 * 169 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 170 */ 171 @Deprecated 172 public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; 173 174 /** 175 * Key used for a Bundle extra holding a Location value 176 * when a location change is broadcast using a PendingIntent. 177 */ 178 public static final String KEY_LOCATION_CHANGED = "location"; 179 180 /** 181 * Broadcast intent action indicating that the GPS has either been 182 * enabled or disabled. An intent extra provides this state as a boolean, 183 * where {@code true} means enabled. 184 * @see #EXTRA_GPS_ENABLED 185 * 186 * @hide 187 */ 188 public static final String GPS_ENABLED_CHANGE_ACTION = 189 "android.location.GPS_ENABLED_CHANGE"; 190 191 /** 192 * Broadcast intent action when the configured location providers 193 * change. 194 * 195 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 196 */ 197 @Deprecated 198 public static final String PROVIDERS_CHANGED_ACTION = 199 "android.location.PROVIDERS_CHANGED"; 200 201 /** 202 * Broadcast intent action indicating that the GPS has either started or 203 * stopped receiving GPS fixes. An intent extra provides this state as a 204 * boolean, where {@code true} means that the GPS is actively receiving fixes. 205 * @see #EXTRA_GPS_ENABLED 206 * 207 * @hide 208 */ 209 public static final String GPS_FIX_CHANGE_ACTION = 210 "android.location.GPS_FIX_CHANGE"; 211 212 /** 213 * The lookup key for a boolean that indicates whether GPS is enabled or 214 * disabled. {@code true} means GPS is enabled. Retrieve it with 215 * {@link android.content.Intent#getBooleanExtra(String,boolean)}. 216 * 217 * @hide 218 */ 219 public static final String EXTRA_GPS_ENABLED = "enabled"; 220 221 // Map from LocationListeners to their associated ListenerTransport objects 222 private HashMap<LocationListener,ListenerTransport> mListeners = 223 new HashMap<LocationListener,ListenerTransport>(); 224 225 private class ListenerTransport extends ILocationListener.Stub { 226 private static final int TYPE_LOCATION_CHANGED = 1; 227 private static final int TYPE_STATUS_CHANGED = 2; 228 private static final int TYPE_PROVIDER_ENABLED = 3; 229 private static final int TYPE_PROVIDER_DISABLED = 4; 230 231 private LocationListener mListener; 232 private final Handler mListenerHandler; 233 234 ListenerTransport(LocationListener listener, Looper looper) { 235 mListener = listener; 236 237 if (looper == null) { 238 mListenerHandler = new Handler() { 239 @Override 240 public void handleMessage(Message msg) { 241 _handleMessage(msg); 242 } 243 }; 244 } else { 245 mListenerHandler = new Handler(looper) { 246 @Override 247 public void handleMessage(Message msg) { 248 _handleMessage(msg); 249 } 250 }; 251 } 252 } 253 254 @Override 255 public void onLocationChanged(Location location) { 256 Message msg = Message.obtain(); 257 msg.what = TYPE_LOCATION_CHANGED; 258 msg.obj = location; 259 mListenerHandler.sendMessage(msg); 260 } 261 262 @Override 263 public void onStatusChanged(String provider, int status, Bundle extras) { 264 Message msg = Message.obtain(); 265 msg.what = TYPE_STATUS_CHANGED; 266 Bundle b = new Bundle(); 267 b.putString("provider", provider); 268 b.putInt("status", status); 269 if (extras != null) { 270 b.putBundle("extras", extras); 271 } 272 msg.obj = b; 273 mListenerHandler.sendMessage(msg); 274 } 275 276 @Override 277 public void onProviderEnabled(String provider) { 278 Message msg = Message.obtain(); 279 msg.what = TYPE_PROVIDER_ENABLED; 280 msg.obj = provider; 281 mListenerHandler.sendMessage(msg); 282 } 283 284 @Override 285 public void onProviderDisabled(String provider) { 286 Message msg = Message.obtain(); 287 msg.what = TYPE_PROVIDER_DISABLED; 288 msg.obj = provider; 289 mListenerHandler.sendMessage(msg); 290 } 291 292 private void _handleMessage(Message msg) { 293 switch (msg.what) { 294 case TYPE_LOCATION_CHANGED: 295 Location location = new Location((Location) msg.obj); 296 mListener.onLocationChanged(location); 297 break; 298 case TYPE_STATUS_CHANGED: 299 Bundle b = (Bundle) msg.obj; 300 String provider = b.getString("provider"); 301 int status = b.getInt("status"); 302 Bundle extras = b.getBundle("extras"); 303 mListener.onStatusChanged(provider, status, extras); 304 break; 305 case TYPE_PROVIDER_ENABLED: 306 mListener.onProviderEnabled((String) msg.obj); 307 break; 308 case TYPE_PROVIDER_DISABLED: 309 mListener.onProviderDisabled((String) msg.obj); 310 break; 311 } 312 try { 313 mService.locationCallbackFinished(this); 314 } catch (RemoteException e) { 315 Log.e(TAG, "locationCallbackFinished: RemoteException", e); 316 } 317 } 318 } 319 320 /** 321 * @hide - hide this constructor because it has a parameter 322 * of type ILocationManager, which is a system private class. The 323 * right way to create an instance of this class is using the 324 * factory Context.getSystemService. 325 */ 326 public LocationManager(Context context, ILocationManager service) { 327 mService = service; 328 mContext = context; 329 } 330 331 private LocationProvider createProvider(String name, ProviderProperties properties) { 332 return new LocationProvider(name, properties); 333 } 334 335 /** 336 * Returns a list of the names of all known location providers. 337 * <p>All providers are returned, including ones that are not permitted to 338 * be accessed by the calling activity or are currently disabled. 339 * 340 * @return list of Strings containing names of the provider 341 * 342 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 343 */ 344 @Deprecated 345 public List<String> getAllProviders() { 346 try { 347 return mService.getAllProviders(); 348 } catch (RemoteException e) { 349 Log.e(TAG, "RemoteException", e); 350 } 351 return null; 352 } 353 354 /** 355 * Returns a list of the names of location providers. 356 * 357 * @param enabledOnly if true then only the providers which are currently 358 * enabled are returned. 359 * @return list of Strings containing names of the providers 360 * 361 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 362 */ 363 @Deprecated 364 public List<String> getProviders(boolean enabledOnly) { 365 try { 366 return mService.getProviders(null, enabledOnly); 367 } catch (RemoteException e) { 368 Log.e(TAG, "RemoteException", e); 369 } 370 return null; 371 } 372 373 /** 374 * Returns the information associated with the location provider of the 375 * given name, or null if no provider exists by that name. 376 * 377 * @param name the provider name 378 * @return a LocationProvider, or null 379 * 380 * @throws IllegalArgumentException if name is null or does not exist 381 * @throws SecurityException if the caller is not permitted to access the 382 * given provider. 383 * 384 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 385 */ 386 @Deprecated 387 public LocationProvider getProvider(String name) { 388 checkProvider(name); 389 try { 390 ProviderProperties properties = mService.getProviderProperties(name); 391 if (properties == null) { 392 return null; 393 } 394 return createProvider(name, properties); 395 } catch (RemoteException e) { 396 Log.e(TAG, "RemoteException", e); 397 } 398 return null; 399 } 400 401 /** 402 * Returns a list of the names of LocationProviders that satisfy the given 403 * criteria, or null if none do. Only providers that are permitted to be 404 * accessed by the calling activity will be returned. 405 * 406 * @param criteria the criteria that the returned providers must match 407 * @param enabledOnly if true then only the providers which are currently 408 * enabled are returned. 409 * @return list of Strings containing names of the providers 410 * 411 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 412 */ 413 @Deprecated 414 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 415 checkCriteria(criteria); 416 try { 417 return mService.getProviders(criteria, enabledOnly); 418 } catch (RemoteException e) { 419 Log.e(TAG, "RemoteException", e); 420 } 421 return null; 422 } 423 424 /** 425 * Returns the name of the provider that best meets the given criteria. Only providers 426 * that are permitted to be accessed by the calling activity will be 427 * returned. If several providers meet the criteria, the one with the best 428 * accuracy is returned. If no provider meets the criteria, 429 * the criteria are loosened in the following sequence: 430 * 431 * <ul> 432 * <li> power requirement 433 * <li> accuracy 434 * <li> bearing 435 * <li> speed 436 * <li> altitude 437 * </ul> 438 * 439 * <p> Note that the requirement on monetary cost is not removed 440 * in this process. 441 * 442 * @param criteria the criteria that need to be matched 443 * @param enabledOnly if true then only a provider that is currently enabled is returned 444 * @return name of the provider that best matches the requirements 445 * 446 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 447 */ 448 @Deprecated 449 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 450 checkCriteria(criteria); 451 try { 452 return mService.getBestProvider(criteria, enabledOnly); 453 } catch (RemoteException e) { 454 Log.e(TAG, "RemoteException", e); 455 } 456 return null; 457 } 458 459 /** 460 * Register for location updates using the named provider, and a 461 * pending intent. 462 * 463 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 464 * for more detail on how to use this (deprecated) method. 465 * 466 * @param provider the name of the provider with which to register 467 * @param minTime minimum time interval between location updates, in milliseconds 468 * @param minDistance minimum distance between location updates, in meters 469 * @param listener a {@link LocationListener} whose 470 * {@link LocationListener#onLocationChanged} method will be called for 471 * each location update 472 * 473 * @throws IllegalArgumentException if provider is null or doesn't exist 474 * on this device 475 * @throws IllegalArgumentException if listener is null 476 * @throws RuntimeException if the calling thread has no Looper 477 * @throws SecurityException if no suitable permission is present 478 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 479 */ 480 @Deprecated 481 public void requestLocationUpdates(String provider, long minTime, float minDistance, 482 LocationListener listener) { 483 checkProvider(provider); 484 checkListener(listener); 485 486 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 487 provider, minTime, minDistance, false); 488 requestLocationUpdates(request, listener, null, null); 489 } 490 491 /** 492 * Register for location updates using the named provider, and a callback on 493 * the specified looper thread. 494 * 495 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 496 * for more detail on how to use this (deprecated) method. 497 * 498 * @param provider the name of the provider with which to register 499 * @param minTime minimum time interval between location updates, in milliseconds 500 * @param minDistance minimum distance between location updates, in meters 501 * @param listener a {@link LocationListener} whose 502 * {@link LocationListener#onLocationChanged} method will be called for 503 * each location update 504 * @param looper a Looper object whose message queue will be used to 505 * implement the callback mechanism, or null to make callbacks on the calling 506 * thread 507 * 508 * @throws IllegalArgumentException if provider is null or doesn't exist 509 * @throws IllegalArgumentException if listener is null 510 * @throws SecurityException if no suitable permission is present 511 * 512 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 513 */ 514 @Deprecated 515 public void requestLocationUpdates(String provider, long minTime, float minDistance, 516 LocationListener listener, Looper looper) { 517 checkProvider(provider); 518 checkListener(listener); 519 520 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 521 provider, minTime, minDistance, false); 522 requestLocationUpdates(request, listener, looper, null); 523 } 524 525 /** 526 * Register for location updates using a Criteria, and a callback 527 * on the specified looper thread. 528 * 529 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 530 * for more detail on how to use this (deprecated) method. 531 * 532 * @param minTime minimum time interval between location updates, in milliseconds 533 * @param minDistance minimum distance between location updates, in meters 534 * @param criteria contains parameters for the location manager to choose the 535 * appropriate provider and parameters to compute the location 536 * @param listener a {@link LocationListener} whose 537 * {@link LocationListener#onLocationChanged} method will be called for 538 * each location update 539 * @param looper a Looper object whose message queue will be used to 540 * implement the callback mechanism, or null to make callbacks on the calling 541 * thread 542 * 543 * @throws IllegalArgumentException if criteria is null 544 * @throws IllegalArgumentException if listener is null 545 * @throws SecurityException if no suitable permission is present 546 * 547 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 548 */ 549 @Deprecated 550 public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, 551 LocationListener listener, Looper looper) { 552 checkCriteria(criteria); 553 checkListener(listener); 554 555 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 556 criteria, minTime, minDistance, false); 557 requestLocationUpdates(request, listener, looper, null); 558 } 559 560 /** 561 * Register for location updates using the named provider, and a 562 * pending intent. 563 * 564 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 565 * for more detail on how to use this (deprecated) method. 566 * 567 * @param provider the name of the provider with which to register 568 * @param minTime minimum time interval between location updates, in milliseconds 569 * @param minDistance minimum distance between location updates, in meters 570 * @param intent a {@link PendingIntent} to be sent for each location update 571 * 572 * @throws IllegalArgumentException if provider is null or doesn't exist 573 * on this device 574 * @throws IllegalArgumentException if intent is null 575 * @throws SecurityException if no suitable permission is present 576 * 577 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 578 */ 579 @Deprecated 580 public void requestLocationUpdates(String provider, long minTime, float minDistance, 581 PendingIntent intent) { 582 checkProvider(provider); 583 checkPendingIntent(intent); 584 585 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 586 provider, minTime, minDistance, false); 587 requestLocationUpdates(request, null, null, intent); 588 } 589 590 /** 591 * Register for location updates using a Criteria and pending intent. 592 * 593 * <p>The <code>requestLocationUpdates()</code> and 594 * <code>requestSingleUpdate()</code> methods involving 595 * an explicit String provider or {@link Criteria} are deprecated. 596 * 597 * <p>They register the current activity to be updated 598 * periodically by the named provider, or by the provider matching 599 * the specified {@link Criteria}, with location and status updates. 600 * 601 * <p> It may take a while to receive the first location update. If 602 * an immediate location is required, applications may use the 603 * {@link #getLastKnownLocation(String)} method. 604 * 605 * <p> Location updates are received either by {@link LocationListener} 606 * callbacks, or by broadcast intents to a supplied {@link PendingIntent}. 607 * 608 * <p> If the caller supplied a pending intent, then location updates 609 * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a 610 * {@link android.location.Location} value. 611 * 612 * <p> The location update interval can be controlled using the minTime parameter. 613 * The elapsed time between location updates will never be less than 614 * minTime, although it can be more depending on the Location Provider 615 * implementation and the update interval requested by other applications. 616 * 617 * <p> Choosing a sensible value for minTime is important to conserve 618 * battery life. Each location update requires power from 619 * GPS, WIFI, Cell and other radios. Select a minTime value as high as 620 * possible while still providing a reasonable user experience. 621 * If your application is not in the foreground and showing 622 * location to the user then your application should avoid using an active 623 * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}), 624 * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes) 625 * or greater. If your application is in the foreground and showing 626 * location to the user then it is appropriate to select a faster 627 * update interval. 628 * 629 * <p> The minDistance parameter can also be used to control the 630 * frequency of location updates. If it is greater than 0 then the 631 * location provider will only send your application an update when 632 * the location has changed by at least minDistance meters, AND 633 * at least minTime milliseconds have passed. However it is more 634 * difficult for location providers to save power using the minDistance 635 * parameter, so minTime should be the primary tool to conserving battery 636 * life. 637 * 638 * <p> If your application wants to passively observe location 639 * updates triggered by other applications, but not consume 640 * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER} 641 * This provider does not actively turn on or modify active location 642 * providers, so you do not need to be as careful about minTime and 643 * minDistance. However if your application performs heavy work 644 * on a location update (such as network activity) then you should 645 * select non-zero values for minTime and/or minDistance to rate-limit 646 * your update frequency in the case another application enables a 647 * location provider with extremely fast updates. 648 * 649 * <p>In case the provider is disabled by the user, updates will stop, 650 * and a provider availability update will be sent. 651 * As soon as the provider is enabled again, 652 * location updates will immediately resume and a provider availability 653 * update sent. Providers can also send status updates, at any time, 654 * with extra's specific to the provider. If a callback was supplied 655 * then status and availability updates are via 656 * {@link LocationListener#onProviderDisabled}, 657 * {@link LocationListener#onProviderEnabled} or 658 * {@link LocationListener#onStatusChanged}. Alternately, if a 659 * pending intent was supplied then status and availability updates 660 * are broadcast intents with extra keys of 661 * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}. 662 * 663 * <p> If a {@link LocationListener} is used but with no Looper specified 664 * then the calling thread must already 665 * be a {@link android.os.Looper} thread such as the main thread of the 666 * calling Activity. If a Looper is specified with a {@link LocationListener} 667 * then callbacks are made on the supplied Looper thread. 668 * 669 * <p class="note"> Prior to Jellybean, the minTime parameter was 670 * only a hint, and some location provider implementations ignored it. 671 * From Jellybean and onwards it is mandatory for Android compatible 672 * devices to observe both the minTime and minDistance parameters. 673 * 674 * @param minTime minimum time interval between location updates, in milliseconds 675 * @param minDistance minimum distance between location updates, in meters 676 * @param criteria contains parameters for the location manager to choose the 677 * appropriate provider and parameters to compute the location 678 * @param intent a {@link PendingIntent} to be sent for each location update 679 * 680 * @throws IllegalArgumentException if criteria is null 681 * @throws IllegalArgumentException if intent is null 682 * @throws SecurityException if no suitable permission is present 683 * 684 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 685 */ 686 @Deprecated 687 public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, 688 PendingIntent intent) { 689 checkCriteria(criteria); 690 checkPendingIntent(intent); 691 692 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 693 criteria, minTime, minDistance, false); 694 requestLocationUpdates(request, null, null, intent); 695 } 696 697 /** 698 * Register for a single location update using the named provider and 699 * a callback. 700 * 701 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 702 * for more detail on how to use this (deprecated) method. 703 * 704 * @param provider the name of the provider with which to register 705 * @param listener a {@link LocationListener} whose 706 * {@link LocationListener#onLocationChanged} method will be called when 707 * the location update is available 708 * @param looper a Looper object whose message queue will be used to 709 * implement the callback mechanism, or null to make callbacks on the calling 710 * thread 711 * 712 * @throws IllegalArgumentException if provider is null or doesn't exist 713 * @throws IllegalArgumentException if listener is null 714 * @throws SecurityException if no suitable permission is present 715 * 716 * @deprecated Use {@link LocationRequest#setNumUpdates} instead 717 */ 718 @Deprecated 719 public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) { 720 checkProvider(provider); 721 checkListener(listener); 722 723 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 724 provider, 0, 0, true); 725 requestLocationUpdates(request, listener, looper, null); 726 } 727 728 /** 729 * Register for a single location update using a Criteria and 730 * a callback. 731 * 732 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 733 * for more detail on how to use this (deprecated) method. 734 * 735 * @param criteria contains parameters for the location manager to choose the 736 * appropriate provider and parameters to compute the location 737 * @param listener a {@link LocationListener} whose 738 * {@link LocationListener#onLocationChanged} method will be called when 739 * the location update is available 740 * @param looper a Looper object whose message queue will be used to 741 * implement the callback mechanism, or null to make callbacks on the calling 742 * thread 743 * 744 * @throws IllegalArgumentException if criteria is null 745 * @throws IllegalArgumentException if listener is null 746 * @throws SecurityException if no suitable permission is present 747 * 748 * @deprecated Use {@link LocationRequest#setNumUpdates} instead 749 */ 750 @Deprecated 751 public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) { 752 checkCriteria(criteria); 753 checkListener(listener); 754 755 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 756 criteria, 0, 0, true); 757 requestLocationUpdates(request, listener, looper, null); 758 } 759 760 /** 761 * Register for a single location update using a named provider and pending intent. 762 * 763 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 764 * for more detail on how to use this (deprecated) method. 765 * 766 * @param provider the name of the provider with which to register 767 * @param intent a {@link PendingIntent} to be sent for the location update 768 * 769 * @throws IllegalArgumentException if provider is null or doesn't exist 770 * @throws IllegalArgumentException if intent is null 771 * @throws SecurityException if no suitable permission is present 772 * 773 * @deprecated Use {@link LocationRequest#setNumUpdates} instead 774 */ 775 @Deprecated 776 public void requestSingleUpdate(String provider, PendingIntent intent) { 777 checkProvider(provider); 778 checkPendingIntent(intent); 779 780 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 781 provider, 0, 0, true); 782 requestLocationUpdates(request, null, null, intent); 783 } 784 785 /** 786 * Register for a single location update using a Criteria and pending intent. 787 * 788 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 789 * for more detail on how to use this (deprecated) method. 790 * 791 * @param criteria contains parameters for the location manager to choose the 792 * appropriate provider and parameters to compute the location 793 * @param intent a {@link PendingIntent} to be sent for the location update 794 * 795 * @throws IllegalArgumentException if provider is null or doesn't exist 796 * @throws IllegalArgumentException if intent is null 797 * @throws SecurityException if no suitable permission is present 798 * 799 * @deprecated Use {@link LocationRequest#setNumUpdates} instead 800 */ 801 @Deprecated 802 public void requestSingleUpdate(Criteria criteria, PendingIntent intent) { 803 checkCriteria(criteria); 804 checkPendingIntent(intent); 805 806 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 807 criteria, 0, 0, true); 808 requestLocationUpdates(request, null, null, intent); 809 } 810 811 /** 812 * Register for fused location updates using a LocationRequest and callback. 813 * 814 * <p>Upon a location update, the system delivers the new {@link Location} to the 815 * provided {@link LocationListener}, by calling its {@link 816 * LocationListener#onLocationChanged} method.</p> 817 * 818 * <p>The system will automatically select and enable the best providers 819 * to compute a location for your application. It may use only passive 820 * locations, or just a single location source, or it may fuse together 821 * multiple location sources in order to produce the best possible 822 * result, depending on the quality of service requested in the 823 * {@link LocationRequest}. 824 * 825 * <p>LocationRequest can be null, in which case the system will choose 826 * default, low power parameters for location updates. You will occasionally 827 * receive location updates as available, without a major power impact on the 828 * system. If your application just needs an occasional location update 829 * without any strict demands, then pass a null LocationRequest. 830 * 831 * <p>Only one LocationRequest can be registered for each unique callback 832 * or pending intent. So a subsequent request with the same callback or 833 * pending intent will over-write the previous LocationRequest. 834 * 835 * <p> If a pending intent is supplied then location updates 836 * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a 837 * {@link android.location.Location} value. If a callback is supplied 838 * then location updates are made using the 839 * {@link LocationListener#onLocationChanged} callback, on the specified 840 * Looper thread. If a {@link LocationListener} is used 841 * but with a null Looper then the calling thread must already 842 * be a {@link android.os.Looper} thread (such as the main thread) and 843 * callbacks will occur on this thread. 844 * 845 * <p> Provider status updates and availability updates are deprecated 846 * because the system is performing provider fusion on the applications 847 * behalf. So {@link LocationListener#onProviderDisabled}, 848 * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged} 849 * will not be called, and intents with extra keys of 850 * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not 851 * be received. 852 * 853 * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}. 854 * 855 * @param request quality of service required, null for default low power 856 * @param listener a {@link LocationListener} whose 857 * {@link LocationListener#onLocationChanged} method will be called when 858 * the location update is available 859 * @param looper a Looper object whose message queue will be used to 860 * implement the callback mechanism, or null to make callbacks on the calling 861 * thread 862 * 863 * @throws IllegalArgumentException if listener is null 864 * @throws SecurityException if no suitable permission is present 865 */ 866 public void requestLocationUpdates(LocationRequest request, LocationListener listener, 867 Looper looper) { 868 checkListener(listener); 869 requestLocationUpdates(request, listener, looper, null); 870 } 871 872 873 /** 874 * Register for fused location updates using a LocationRequest and a pending intent. 875 * 876 * <p>Upon a location update, the system delivers the new {@link Location} with your provided 877 * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED} 878 * in the intent's extras.</p> 879 * 880 * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}. 881 * 882 * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} 883 * for more detail. 884 * 885 * @param request quality of service required, null for default low power 886 * @param intent a {@link PendingIntent} to be sent for the location update 887 * 888 * @throws IllegalArgumentException if intent is null 889 * @throws SecurityException if no suitable permission is present 890 */ 891 public void requestLocationUpdates(LocationRequest request, PendingIntent intent) { 892 checkPendingIntent(intent); 893 requestLocationUpdates(request, null, null, intent); 894 } 895 896 private ListenerTransport wrapListener(LocationListener listener, Looper looper) { 897 if (listener == null) return null; 898 synchronized (mListeners) { 899 ListenerTransport transport = mListeners.get(listener); 900 if (transport == null) { 901 transport = new ListenerTransport(listener, looper); 902 } 903 mListeners.put(listener, transport); 904 return transport; 905 } 906 } 907 908 private void requestLocationUpdates(LocationRequest request, LocationListener listener, 909 Looper looper, PendingIntent intent) { 910 911 String packageName = mContext.getPackageName(); 912 913 // wrap the listener class 914 ListenerTransport transport = wrapListener(listener, looper); 915 916 try { 917 mService.requestLocationUpdates(request, transport, intent, packageName); 918 } catch (RemoteException e) { 919 Log.e(TAG, "RemoteException", e); 920 } 921 } 922 923 /** 924 * Removes all location updates for the specified LocationListener. 925 * 926 * <p>Following this call, updates will no longer 927 * occur for this listener. 928 * 929 * @param listener listener object that no longer needs location updates 930 * @throws IllegalArgumentException if listener is null 931 */ 932 public void removeUpdates(LocationListener listener) { 933 checkListener(listener); 934 String packageName = mContext.getPackageName(); 935 936 ListenerTransport transport; 937 synchronized (mListeners) { 938 transport = mListeners.remove(listener); 939 } 940 if (transport == null) return; 941 942 try { 943 mService.removeUpdates(transport, null, packageName); 944 } catch (RemoteException e) { 945 Log.e(TAG, "RemoteException", e); 946 } 947 } 948 949 /** 950 * Removes all location updates for the specified pending intent. 951 * 952 * <p>Following this call, updates will no longer for this pending intent. 953 * 954 * @param intent pending intent object that no longer needs location updates 955 * @throws IllegalArgumentException if intent is null 956 */ 957 public void removeUpdates(PendingIntent intent) { 958 checkPendingIntent(intent); 959 String packageName = mContext.getPackageName(); 960 961 try { 962 mService.removeUpdates(null, intent, packageName); 963 } catch (RemoteException e) { 964 Log.e(TAG, "RemoteException", e); 965 } 966 } 967 968 /** 969 * Set a proximity alert for the location given by the position 970 * (latitude, longitude) and the given radius. 971 * 972 * <p> When the device 973 * detects that it has entered or exited the area surrounding the 974 * location, the given PendingIntent will be used to create an Intent 975 * to be fired. 976 * 977 * <p> The fired Intent will have a boolean extra added with key 978 * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is 979 * entering the proximity region; if false, it is exiting. 980 * 981 * <p> Due to the approximate nature of position estimation, if the 982 * device passes through the given area briefly, it is possible 983 * that no Intent will be fired. Similarly, an Intent could be 984 * fired if the device passes very close to the given area but 985 * does not actually enter it. 986 * 987 * <p> After the number of milliseconds given by the expiration 988 * parameter, the location manager will delete this proximity 989 * alert and no longer monitor it. A value of -1 indicates that 990 * there should be no expiration time. 991 * 992 * <p> Internally, this method uses both {@link #NETWORK_PROVIDER} 993 * and {@link #GPS_PROVIDER}. 994 * 995 * <p>Before API version 17, this method could be used with 996 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or 997 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. 998 * From API version 17 and onwards, this method requires 999 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. 1000 * 1001 * @param latitude the latitude of the central point of the 1002 * alert region 1003 * @param longitude the longitude of the central point of the 1004 * alert region 1005 * @param radius the radius of the central point of the 1006 * alert region, in meters 1007 * @param expiration time for this proximity alert, in milliseconds, 1008 * or -1 to indicate no expiration 1009 * @param intent a PendingIntent that will be used to generate an Intent to 1010 * fire when entry to or exit from the alert region is detected 1011 * 1012 * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION} 1013 * permission is not present 1014 * 1015 * @deprecated Use {@link LocationRequest} and {@link Geofence} instead 1016 */ 1017 @Deprecated 1018 public void addProximityAlert(double latitude, double longitude, float radius, long expiration, 1019 PendingIntent intent) { 1020 checkPendingIntent(intent); 1021 if (expiration < 0) expiration = Long.MAX_VALUE; 1022 1023 Geofence fence = Geofence.createCircle(latitude, longitude, radius); 1024 LocationRequest request = new LocationRequest().setExpireIn(expiration); 1025 try { 1026 mService.requestGeofence(request, fence, intent, mContext.getPackageName()); 1027 } catch (RemoteException e) { 1028 Log.e(TAG, "RemoteException", e); 1029 } 1030 } 1031 1032 /** 1033 * Add a geofence with the specified LocationRequest quality of service. 1034 * 1035 * <p> When the device 1036 * detects that it has entered or exited the area surrounding the 1037 * location, the given PendingIntent will be used to create an Intent 1038 * to be fired. 1039 * 1040 * <p> The fired Intent will have a boolean extra added with key 1041 * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is 1042 * entering the proximity region; if false, it is exiting. 1043 * 1044 * <p> The geofence engine fuses results from all location providers to 1045 * provide the best balance between accuracy and power. Applications 1046 * can choose the quality of service required using the 1047 * {@link LocationRequest} object. If it is null then a default, 1048 * low power geo-fencing implementation is used. It is possible to cross 1049 * a geo-fence without notification, but the system will do its best 1050 * to detect, using {@link LocationRequest} as a hint to trade-off 1051 * accuracy and power. 1052 * 1053 * <p> The power required by the geofence engine can depend on many factors, 1054 * such as quality and interval requested in {@link LocationRequest}, 1055 * distance to nearest geofence and current device velocity. 1056 * 1057 * @param request quality of service required, null for default low power 1058 * @param fence a geographical description of the geofence area 1059 * @param intent pending intent to receive geofence updates 1060 * 1061 * @throws IllegalArgumentException if fence is null 1062 * @throws IllegalArgumentException if intent is null 1063 * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION} 1064 * permission is not present 1065 */ 1066 public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) { 1067 checkPendingIntent(intent); 1068 checkGeofence(fence); 1069 1070 try { 1071 mService.requestGeofence(request, fence, intent, mContext.getPackageName()); 1072 } catch (RemoteException e) { 1073 Log.e(TAG, "RemoteException", e); 1074 } 1075 } 1076 1077 /** 1078 * Removes the proximity alert with the given PendingIntent. 1079 * 1080 * <p>Before API version 17, this method could be used with 1081 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or 1082 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. 1083 * From API version 17 and onwards, this method requires 1084 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. 1085 * 1086 * @param intent the PendingIntent that no longer needs to be notified of 1087 * proximity alerts 1088 * 1089 * @throws IllegalArgumentException if intent is null 1090 * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION} 1091 * permission is not present 1092 * 1093 * @deprecated Use {@link LocationRequest} and {@link Geofence} instead 1094 */ 1095 @Deprecated 1096 public void removeProximityAlert(PendingIntent intent) { 1097 checkPendingIntent(intent); 1098 String packageName = mContext.getPackageName(); 1099 1100 try { 1101 mService.removeGeofence(null, intent, packageName); 1102 } catch (RemoteException e) { 1103 Log.e(TAG, "RemoteException", e); 1104 } 1105 } 1106 1107 /** 1108 * Remove a single geofence. 1109 * 1110 * <p>This removes only the specified geofence associated with the 1111 * specified pending intent. All other geofences remain unchanged. 1112 * 1113 * @param fence a geofence previously passed to {@link #addGeofence} 1114 * @param intent a pending intent previously passed to {@link #addGeofence} 1115 * 1116 * @throws IllegalArgumentException if fence is null 1117 * @throws IllegalArgumentException if intent is null 1118 * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION} 1119 * permission is not present 1120 */ 1121 public void removeGeofence(Geofence fence, PendingIntent intent) { 1122 checkPendingIntent(intent); 1123 checkGeofence(fence); 1124 String packageName = mContext.getPackageName(); 1125 1126 try { 1127 mService.removeGeofence(fence, intent, packageName); 1128 } catch (RemoteException e) { 1129 Log.e(TAG, "RemoteException", e); 1130 } 1131 } 1132 1133 /** 1134 * Remove all geofences registered to the specified pending intent. 1135 * 1136 * @param intent a pending intent previously passed to {@link #addGeofence} 1137 * 1138 * @throws IllegalArgumentException if intent is null 1139 * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION} 1140 * permission is not present 1141 */ 1142 public void removeAllGeofences(PendingIntent intent) { 1143 checkPendingIntent(intent); 1144 String packageName = mContext.getPackageName(); 1145 1146 try { 1147 mService.removeGeofence(null, intent, packageName); 1148 } catch (RemoteException e) { 1149 Log.e(TAG, "RemoteException", e); 1150 } 1151 } 1152 1153 /** 1154 * Returns the current enabled/disabled status of the given provider. 1155 * 1156 * <p>If the user has enabled this provider in the Settings menu, true 1157 * is returned otherwise false is returned 1158 * 1159 * @param provider the name of the provider 1160 * @return true if the provider is enabled 1161 * 1162 * @throws IllegalArgumentException if provider is null 1163 * @throws SecurityException if no suitable permission is present 1164 * 1165 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 1166 */ 1167 @Deprecated 1168 public boolean isProviderEnabled(String provider) { 1169 checkProvider(provider); 1170 1171 try { 1172 return mService.isProviderEnabled(provider); 1173 } catch (RemoteException e) { 1174 Log.e(TAG, "RemoteException", e); 1175 return false; 1176 } 1177 } 1178 1179 /** 1180 * Get the last known location. 1181 * 1182 * <p>This location could be very old so use 1183 * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can 1184 * also return null if no previous location is available. 1185 * 1186 * <p>Always returns immediately. 1187 * 1188 * @return The last known location, or null if not available 1189 * @throws SecurityException if no suitable permission is present 1190 */ 1191 public Location getLastLocation() { 1192 String packageName = mContext.getPackageName(); 1193 1194 try { 1195 return mService.getLastLocation(null, packageName); 1196 } catch (RemoteException e) { 1197 Log.e(TAG, "RemoteException", e); 1198 return null; 1199 } 1200 } 1201 1202 /** 1203 * Returns a Location indicating the data from the last known 1204 * location fix obtained from the given provider. 1205 * 1206 * <p> This can be done 1207 * without starting the provider. Note that this location could 1208 * be out-of-date, for example if the device was turned off and 1209 * moved to another location. 1210 * 1211 * <p> If the provider is currently disabled, null is returned. 1212 * 1213 * @param provider the name of the provider 1214 * @return the last known location for the provider, or null 1215 * 1216 * @throws SecurityException if no suitable permission is present 1217 * @throws IllegalArgumentException if provider is null or doesn't exist 1218 * 1219 * @deprecated Use {@link #getLastLocation} instead 1220 */ 1221 @Deprecated 1222 public Location getLastKnownLocation(String provider) { 1223 checkProvider(provider); 1224 String packageName = mContext.getPackageName(); 1225 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 1226 provider, 0, 0, true); 1227 1228 try { 1229 return mService.getLastLocation(request, packageName); 1230 } catch (RemoteException e) { 1231 Log.e(TAG, "RemoteException", e); 1232 return null; 1233 } 1234 } 1235 1236 // --- Mock provider support --- 1237 // TODO: It would be fantastic to deprecate mock providers entirely, and replace 1238 // with something closer to LocationProviderBase.java 1239 1240 /** 1241 * Creates a mock location provider and adds it to the set of active providers. 1242 * 1243 * @param name the provider name 1244 * 1245 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1246 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1247 * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled 1248 * @throws IllegalArgumentException if a provider with the given name already exists 1249 * 1250 * @deprecated requesting location providers by name is deprecated 1251 */ 1252 @Deprecated 1253 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 1254 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 1255 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 1256 ProviderProperties properties = new ProviderProperties(requiresNetwork, 1257 requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed, 1258 supportsBearing, powerRequirement, accuracy); 1259 if (name.matches(LocationProvider.BAD_CHARS_REGEX)) { 1260 throw new IllegalArgumentException("provider name contains illegal character: " + name); 1261 } 1262 1263 try { 1264 mService.addTestProvider(name, properties); 1265 } catch (RemoteException e) { 1266 Log.e(TAG, "RemoteException", e); 1267 } 1268 } 1269 1270 /** 1271 * Removes the mock location provider with the given name. 1272 * 1273 * @param provider the provider name 1274 * 1275 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1276 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1277 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1278 * @throws IllegalArgumentException if no provider with the given name exists 1279 * 1280 * @deprecated requesting location providers by name is deprecated 1281 */ 1282 @Deprecated 1283 public void removeTestProvider(String provider) { 1284 try { 1285 mService.removeTestProvider(provider); 1286 } catch (RemoteException e) { 1287 Log.e(TAG, "RemoteException", e); 1288 } 1289 } 1290 1291 /** 1292 * Sets a mock location for the given provider. 1293 * <p>This location will be used in place of any actual location from the provider. 1294 * The location object must have a minimum number of fields set to be 1295 * considered a valid LocationProvider Location, as per documentation 1296 * on {@link Location} class. 1297 * 1298 * @param provider the provider name 1299 * @param loc the mock location 1300 * 1301 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1302 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1303 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1304 * @throws IllegalArgumentException if no provider with the given name exists 1305 * @throws IllegalArgumentException if the location is incomplete 1306 * 1307 * @deprecated requesting location providers by name is deprecated 1308 */ 1309 @Deprecated 1310 public void setTestProviderLocation(String provider, Location loc) { 1311 if (!loc.isComplete()) { 1312 IllegalArgumentException e = new IllegalArgumentException( 1313 "Incomplete location object, missing timestamp or accuracy? " + loc); 1314 if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) { 1315 // just log on old platform (for backwards compatibility) 1316 Log.w(TAG, e); 1317 loc.makeComplete(); 1318 } else { 1319 // really throw it! 1320 throw e; 1321 } 1322 } 1323 1324 try { 1325 mService.setTestProviderLocation(provider, loc); 1326 } catch (RemoteException e) { 1327 Log.e(TAG, "RemoteException", e); 1328 } 1329 } 1330 1331 /** 1332 * Removes any mock location associated with the given provider. 1333 * 1334 * @param provider the provider name 1335 * 1336 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1337 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1338 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1339 * @throws IllegalArgumentException if no provider with the given name exists 1340 * 1341 * @deprecated requesting location providers by name is deprecated 1342 */ 1343 @Deprecated 1344 public void clearTestProviderLocation(String provider) { 1345 try { 1346 mService.clearTestProviderLocation(provider); 1347 } catch (RemoteException e) { 1348 Log.e(TAG, "RemoteException", e); 1349 } 1350 } 1351 1352 /** 1353 * Sets a mock enabled value for the given provider. This value will be used in place 1354 * of any actual value from the provider. 1355 * 1356 * @param provider the provider name 1357 * @param enabled the mock enabled value 1358 * 1359 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1360 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1361 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1362 * @throws IllegalArgumentException if no provider with the given name exists 1363 * 1364 * @deprecated requesting location providers by name is deprecated 1365 */ 1366 @Deprecated 1367 public void setTestProviderEnabled(String provider, boolean enabled) { 1368 try { 1369 mService.setTestProviderEnabled(provider, enabled); 1370 } catch (RemoteException e) { 1371 Log.e(TAG, "RemoteException", e); 1372 } 1373 } 1374 1375 /** 1376 * Removes any mock enabled value associated with the given provider. 1377 * 1378 * @param provider the provider name 1379 * 1380 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1381 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1382 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1383 * @throws IllegalArgumentException if no provider with the given name exists 1384 * 1385 * @deprecated requesting location providers by name is deprecated 1386 */ 1387 @Deprecated 1388 public void clearTestProviderEnabled(String provider) { 1389 try { 1390 mService.clearTestProviderEnabled(provider); 1391 } catch (RemoteException e) { 1392 Log.e(TAG, "RemoteException", e); 1393 } 1394 } 1395 1396 /** 1397 * Sets mock status values for the given provider. These values will be used in place 1398 * of any actual values from the provider. 1399 * 1400 * @param provider the provider name 1401 * @param status the mock status 1402 * @param extras a Bundle containing mock extras 1403 * @param updateTime the mock update time 1404 * 1405 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1406 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1407 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1408 * @throws IllegalArgumentException if no provider with the given name exists 1409 * 1410 * @deprecated requesting location providers by name is deprecated 1411 */ 1412 @Deprecated 1413 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1414 try { 1415 mService.setTestProviderStatus(provider, status, extras, updateTime); 1416 } catch (RemoteException e) { 1417 Log.e(TAG, "RemoteException", e); 1418 } 1419 } 1420 1421 /** 1422 * Removes any mock status values associated with the given provider. 1423 * 1424 * @param provider the provider name 1425 * 1426 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1427 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1428 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1429 * @throws IllegalArgumentException if no provider with the given name exists 1430 * 1431 * @deprecated requesting location providers by name is deprecated 1432 */ 1433 @Deprecated 1434 public void clearTestProviderStatus(String provider) { 1435 try { 1436 mService.clearTestProviderStatus(provider); 1437 } catch (RemoteException e) { 1438 Log.e(TAG, "RemoteException", e); 1439 } 1440 } 1441 1442 // --- GPS-specific support --- 1443 1444 // This class is used to send GPS status events to the client's main thread. 1445 private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { 1446 1447 private final GpsStatus.Listener mListener; 1448 private final GpsStatus.NmeaListener mNmeaListener; 1449 1450 // This must not equal any of the GpsStatus event IDs 1451 private static final int NMEA_RECEIVED = 1000; 1452 1453 private class Nmea { 1454 long mTimestamp; 1455 String mNmea; 1456 1457 Nmea(long timestamp, String nmea) { 1458 mTimestamp = timestamp; 1459 mNmea = nmea; 1460 } 1461 } 1462 private ArrayList<Nmea> mNmeaBuffer; 1463 1464 GpsStatusListenerTransport(GpsStatus.Listener listener) { 1465 mListener = listener; 1466 mNmeaListener = null; 1467 } 1468 1469 GpsStatusListenerTransport(GpsStatus.NmeaListener listener) { 1470 mNmeaListener = listener; 1471 mListener = null; 1472 mNmeaBuffer = new ArrayList<Nmea>(); 1473 } 1474 1475 @Override 1476 public void onGpsStarted() { 1477 if (mListener != null) { 1478 Message msg = Message.obtain(); 1479 msg.what = GpsStatus.GPS_EVENT_STARTED; 1480 mGpsHandler.sendMessage(msg); 1481 } 1482 } 1483 1484 @Override 1485 public void onGpsStopped() { 1486 if (mListener != null) { 1487 Message msg = Message.obtain(); 1488 msg.what = GpsStatus.GPS_EVENT_STOPPED; 1489 mGpsHandler.sendMessage(msg); 1490 } 1491 } 1492 1493 @Override 1494 public void onFirstFix(int ttff) { 1495 if (mListener != null) { 1496 mGpsStatus.setTimeToFirstFix(ttff); 1497 Message msg = Message.obtain(); 1498 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; 1499 mGpsHandler.sendMessage(msg); 1500 } 1501 } 1502 1503 @Override 1504 public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, 1505 float[] elevations, float[] azimuths, int ephemerisMask, 1506 int almanacMask, int usedInFixMask) { 1507 if (mListener != null) { 1508 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, 1509 ephemerisMask, almanacMask, usedInFixMask); 1510 1511 Message msg = Message.obtain(); 1512 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; 1513 // remove any SV status messages already in the queue 1514 mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); 1515 mGpsHandler.sendMessage(msg); 1516 } 1517 } 1518 1519 @Override 1520 public void onNmeaReceived(long timestamp, String nmea) { 1521 if (mNmeaListener != null) { 1522 synchronized (mNmeaBuffer) { 1523 mNmeaBuffer.add(new Nmea(timestamp, nmea)); 1524 } 1525 Message msg = Message.obtain(); 1526 msg.what = NMEA_RECEIVED; 1527 // remove any NMEA_RECEIVED messages already in the queue 1528 mGpsHandler.removeMessages(NMEA_RECEIVED); 1529 mGpsHandler.sendMessage(msg); 1530 } 1531 } 1532 1533 private final Handler mGpsHandler = new Handler() { 1534 @Override 1535 public void handleMessage(Message msg) { 1536 if (msg.what == NMEA_RECEIVED) { 1537 synchronized (mNmeaBuffer) { 1538 int length = mNmeaBuffer.size(); 1539 for (int i = 0; i < length; i++) { 1540 Nmea nmea = mNmeaBuffer.get(i); 1541 mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea); 1542 } 1543 mNmeaBuffer.clear(); 1544 } 1545 } else { 1546 // synchronize on mGpsStatus to ensure the data is copied atomically. 1547 synchronized(mGpsStatus) { 1548 mListener.onGpsStatusChanged(msg.what); 1549 } 1550 } 1551 } 1552 }; 1553 } 1554 1555 /** 1556 * Adds a GPS status listener. 1557 * 1558 * @param listener GPS status listener object to register 1559 * 1560 * @return true if the listener was successfully added 1561 * 1562 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1563 */ 1564 public boolean addGpsStatusListener(GpsStatus.Listener listener) { 1565 boolean result; 1566 1567 if (mGpsStatusListeners.get(listener) != null) { 1568 // listener is already registered 1569 return true; 1570 } 1571 try { 1572 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1573 result = mService.addGpsStatusListener(transport); 1574 if (result) { 1575 mGpsStatusListeners.put(listener, transport); 1576 } 1577 } catch (RemoteException e) { 1578 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1579 result = false; 1580 } 1581 1582 return result; 1583 } 1584 1585 /** 1586 * Removes a GPS status listener. 1587 * 1588 * @param listener GPS status listener object to remove 1589 */ 1590 public void removeGpsStatusListener(GpsStatus.Listener listener) { 1591 try { 1592 GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener); 1593 if (transport != null) { 1594 mService.removeGpsStatusListener(transport); 1595 } 1596 } catch (RemoteException e) { 1597 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1598 } 1599 } 1600 1601 /** 1602 * Adds an NMEA listener. 1603 * 1604 * @param listener a {@link GpsStatus.NmeaListener} object to register 1605 * 1606 * @return true if the listener was successfully added 1607 * 1608 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1609 */ 1610 public boolean addNmeaListener(GpsStatus.NmeaListener listener) { 1611 boolean result; 1612 1613 if (mNmeaListeners.get(listener) != null) { 1614 // listener is already registered 1615 return true; 1616 } 1617 try { 1618 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1619 result = mService.addGpsStatusListener(transport); 1620 if (result) { 1621 mNmeaListeners.put(listener, transport); 1622 } 1623 } catch (RemoteException e) { 1624 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1625 result = false; 1626 } 1627 1628 return result; 1629 } 1630 1631 /** 1632 * Removes an NMEA listener. 1633 * 1634 * @param listener a {@link GpsStatus.NmeaListener} object to remove 1635 */ 1636 public void removeNmeaListener(GpsStatus.NmeaListener listener) { 1637 try { 1638 GpsStatusListenerTransport transport = mNmeaListeners.remove(listener); 1639 if (transport != null) { 1640 mService.removeGpsStatusListener(transport); 1641 } 1642 } catch (RemoteException e) { 1643 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1644 } 1645 } 1646 1647 /** 1648 * Retrieves information about the current status of the GPS engine. 1649 * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} 1650 * callback to ensure that the data is copied atomically. 1651 * 1652 * The caller may either pass in a {@link GpsStatus} object to set with the latest 1653 * status information, or pass null to create a new {@link GpsStatus} object. 1654 * 1655 * @param status object containing GPS status details, or null. 1656 * @return status object containing updated GPS status. 1657 */ 1658 public GpsStatus getGpsStatus(GpsStatus status) { 1659 if (status == null) { 1660 status = new GpsStatus(); 1661 } 1662 status.setStatus(mGpsStatus); 1663 return status; 1664 } 1665 1666 /** 1667 * Sends additional commands to a location provider. 1668 * Can be used to support provider specific extensions to the Location Manager API 1669 * 1670 * @param provider name of the location provider. 1671 * @param command name of the command to send to the provider. 1672 * @param extras optional arguments for the command (or null). 1673 * The provider may optionally fill the extras Bundle with results from the command. 1674 * 1675 * @return true if the command succeeds. 1676 * 1677 * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager} 1678 */ 1679 @Deprecated 1680 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1681 try { 1682 return mService.sendExtraCommand(provider, command, extras); 1683 } catch (RemoteException e) { 1684 Log.e(TAG, "RemoteException in sendExtraCommand: ", e); 1685 return false; 1686 } 1687 } 1688 1689 /** 1690 * Used by NetInitiatedActivity to report user response 1691 * for network initiated GPS fix requests. 1692 * 1693 * @hide 1694 */ 1695 public boolean sendNiResponse(int notifId, int userResponse) { 1696 try { 1697 return mService.sendNiResponse(notifId, userResponse); 1698 } catch (RemoteException e) { 1699 Log.e(TAG, "RemoteException in sendNiResponse: ", e); 1700 return false; 1701 } 1702 } 1703 1704 private static void checkProvider(String provider) { 1705 if (provider == null) { 1706 throw new IllegalArgumentException("invalid provider: " + provider); 1707 } 1708 } 1709 1710 private static void checkCriteria(Criteria criteria) { 1711 if (criteria == null) { 1712 throw new IllegalArgumentException("invalid criteria: " + criteria); 1713 } 1714 } 1715 1716 private static void checkListener(LocationListener listener) { 1717 if (listener == null) { 1718 throw new IllegalArgumentException("invalid listener: " + listener); 1719 } 1720 } 1721 1722 private void checkPendingIntent(PendingIntent intent) { 1723 if (intent == null) { 1724 throw new IllegalArgumentException("invalid pending intent: " + intent); 1725 } 1726 if (!intent.isTargetedToPackage()) { 1727 IllegalArgumentException e = new IllegalArgumentException( 1728 "pending intent msut be targeted to package"); 1729 if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) { 1730 throw e; 1731 } else { 1732 Log.w(TAG, e); 1733 } 1734 } 1735 } 1736 1737 private static void checkGeofence(Geofence fence) { 1738 if (fence == null) { 1739 throw new IllegalArgumentException("invalid geofence: " + fence); 1740 } 1741 } 1742} 1743