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