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