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