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