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