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.Intent; 21 import android.os.Bundle; 22 import android.os.Looper; 23 import android.os.RemoteException; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.util.Log; 27 28 import com.android.internal.location.DummyLocationProvider; 29 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 34 /** 35 * This class provides access to the system location services. These 36 * services allow applications to obtain periodic updates of the 37 * device's geographical location, or to fire an application-specified 38 * {@link Intent} when the device enters the proximity of a given 39 * geographical location. 40 * 41 * <p>You do not 42 * instantiate this class directly; instead, retrieve it through 43 * {@link android.content.Context#getSystemService 44 * Context.getSystemService(Context.LOCATION_SERVICE)}. 45 * 46 * <div class="special reference"> 47 * <h3>Developer Guides</h3> 48 * <p>For more information about using location services, read the 49 * <a href="{@docRoot}guide/topics/location/index.html">Location and Maps</a> 50 * developer guide.</p> 51 * </div> 52 */ 53 public class LocationManager { 54 private static final String TAG = "LocationManager"; 55 private ILocationManager mService; 56 private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners = 57 new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>(); 58 private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners = 59 new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>(); 60 private final GpsStatus mGpsStatus = new GpsStatus(); 61 62 /** 63 * Name of the network location provider. This provider determines location based on 64 * availability of cell tower and WiFi access points. Results are retrieved 65 * by means of a network lookup. 66 * 67 * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION 68 * or android.permission.ACCESS_FINE_LOCATION. 69 */ 70 public static final String NETWORK_PROVIDER = "network"; 71 72 /** 73 * Name of the GPS location provider. This provider determines location using 74 * satellites. Depending on conditions, this provider may take a while to return 75 * a location fix. 76 * 77 * Requires the permission android.permission.ACCESS_FINE_LOCATION. 78 * 79 * <p> The extras Bundle for the GPS location provider can contain the 80 * following key/value pairs: 81 * 82 * <ul> 83 * <li> satellites - the number of satellites used to derive the fix 84 * </ul> 85 */ 86 public static final String GPS_PROVIDER = "gps"; 87 88 /** 89 * A special location provider for receiving locations without actually initiating 90 * a location fix. This provider can be used to passively receive location updates 91 * when other applications or services request them without actually requesting 92 * the locations yourself. This provider will return locations generated by other 93 * providers. You can query the {@link Location#getProvider()} method to determine 94 * the origin of the location update. 95 * 96 * Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS 97 * is not enabled this provider might only return coarse fixes. 98 */ 99 public static final String PASSIVE_PROVIDER = "passive"; 100 101 /** 102 * Key used for the Bundle extra holding a boolean indicating whether 103 * a proximity alert is entering (true) or exiting (false).. 104 */ 105 public static final String KEY_PROXIMITY_ENTERING = "entering"; 106 107 /** 108 * Key used for a Bundle extra holding an Integer status value 109 * when a status change is broadcast using a PendingIntent. 110 */ 111 public static final String KEY_STATUS_CHANGED = "status"; 112 113 /** 114 * Key used for a Bundle extra holding an Boolean status value 115 * when a provider enabled/disabled event is broadcast using a PendingIntent. 116 */ 117 public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; 118 119 /** 120 * Key used for a Bundle extra holding a Location value 121 * when a location change is broadcast using a PendingIntent. 122 */ 123 public static final String KEY_LOCATION_CHANGED = "location"; 124 125 /** 126 * Broadcast intent action indicating that the GPS has either been 127 * enabled or disabled. An intent extra provides this state as a boolean, 128 * where {@code true} means enabled. 129 * @see #EXTRA_GPS_ENABLED 130 * 131 * {@hide} 132 */ 133 public static final String GPS_ENABLED_CHANGE_ACTION = 134 "android.location.GPS_ENABLED_CHANGE"; 135 136 /** 137 * Broadcast intent action when the configured location providers 138 * change. 139 */ 140 public static final String PROVIDERS_CHANGED_ACTION = 141 "android.location.PROVIDERS_CHANGED"; 142 143 /** 144 * Broadcast intent action indicating that the GPS has either started or 145 * stopped receiving GPS fixes. An intent extra provides this state as a 146 * boolean, where {@code true} means that the GPS is actively receiving fixes. 147 * @see #EXTRA_GPS_ENABLED 148 * 149 * {@hide} 150 */ 151 public static final String GPS_FIX_CHANGE_ACTION = 152 "android.location.GPS_FIX_CHANGE"; 153 154 /** 155 * The lookup key for a boolean that indicates whether GPS is enabled or 156 * disabled. {@code true} means GPS is enabled. Retrieve it with 157 * {@link android.content.Intent#getBooleanExtra(String,boolean)}. 158 * 159 * {@hide} 160 */ 161 public static final String EXTRA_GPS_ENABLED = "enabled"; 162 163 // Map from LocationListeners to their associated ListenerTransport objects 164 private HashMap<LocationListener,ListenerTransport> mListeners = 165 new HashMap<LocationListener,ListenerTransport>(); 166 167 private class ListenerTransport extends ILocationListener.Stub { 168 private static final int TYPE_LOCATION_CHANGED = 1; 169 private static final int TYPE_STATUS_CHANGED = 2; 170 private static final int TYPE_PROVIDER_ENABLED = 3; 171 private static final int TYPE_PROVIDER_DISABLED = 4; 172 173 private LocationListener mListener; 174 private final Handler mListenerHandler; 175 176 ListenerTransport(LocationListener listener, Looper looper) { 177 mListener = listener; 178 179 if (looper == null) { 180 mListenerHandler = new Handler() { 181 @Override 182 public void handleMessage(Message msg) { 183 _handleMessage(msg); 184 } 185 }; 186 } else { 187 mListenerHandler = new Handler(looper) { 188 @Override 189 public void handleMessage(Message msg) { 190 _handleMessage(msg); 191 } 192 }; 193 } 194 } 195 196 public void onLocationChanged(Location location) { 197 Message msg = Message.obtain(); 198 msg.what = TYPE_LOCATION_CHANGED; 199 msg.obj = location; 200 mListenerHandler.sendMessage(msg); 201 } 202 203 public void onStatusChanged(String provider, int status, Bundle extras) { 204 Message msg = Message.obtain(); 205 msg.what = TYPE_STATUS_CHANGED; 206 Bundle b = new Bundle(); 207 b.putString("provider", provider); 208 b.putInt("status", status); 209 if (extras != null) { 210 b.putBundle("extras", extras); 211 } 212 msg.obj = b; 213 mListenerHandler.sendMessage(msg); 214 } 215 216 public void onProviderEnabled(String provider) { 217 Message msg = Message.obtain(); 218 msg.what = TYPE_PROVIDER_ENABLED; 219 msg.obj = provider; 220 mListenerHandler.sendMessage(msg); 221 } 222 223 public void onProviderDisabled(String provider) { 224 Message msg = Message.obtain(); 225 msg.what = TYPE_PROVIDER_DISABLED; 226 msg.obj = provider; 227 mListenerHandler.sendMessage(msg); 228 } 229 230 private void _handleMessage(Message msg) { 231 switch (msg.what) { 232 case TYPE_LOCATION_CHANGED: 233 Location location = new Location((Location) msg.obj); 234 mListener.onLocationChanged(location); 235 break; 236 case TYPE_STATUS_CHANGED: 237 Bundle b = (Bundle) msg.obj; 238 String provider = b.getString("provider"); 239 int status = b.getInt("status"); 240 Bundle extras = b.getBundle("extras"); 241 mListener.onStatusChanged(provider, status, extras); 242 break; 243 case TYPE_PROVIDER_ENABLED: 244 mListener.onProviderEnabled((String) msg.obj); 245 break; 246 case TYPE_PROVIDER_DISABLED: 247 mListener.onProviderDisabled((String) msg.obj); 248 break; 249 } 250 try { 251 mService.locationCallbackFinished(this); 252 } catch (RemoteException e) { 253 Log.e(TAG, "locationCallbackFinished: RemoteException", e); 254 } 255 } 256 } 257 /** 258 * @hide - hide this constructor because it has a parameter 259 * of type ILocationManager, which is a system private class. The 260 * right way to create an instance of this class is using the 261 * factory Context.getSystemService. 262 */ 263 public LocationManager(ILocationManager service) { 264 mService = service; 265 } 266 267 private LocationProvider createProvider(String name, Bundle info) { 268 DummyLocationProvider provider = 269 new DummyLocationProvider(name, mService); 270 provider.setRequiresNetwork(info.getBoolean("network")); 271 provider.setRequiresSatellite(info.getBoolean("satellite")); 272 provider.setRequiresCell(info.getBoolean("cell")); 273 provider.setHasMonetaryCost(info.getBoolean("cost")); 274 provider.setSupportsAltitude(info.getBoolean("altitude")); 275 provider.setSupportsSpeed(info.getBoolean("speed")); 276 provider.setSupportsBearing(info.getBoolean("bearing")); 277 provider.setPowerRequirement(info.getInt("power")); 278 provider.setAccuracy(info.getInt("accuracy")); 279 return provider; 280 } 281 282 /** 283 * Returns a list of the names of all known location providers. All 284 * providers are returned, including ones that are not permitted to be 285 * accessed by the calling activity or are currently disabled. 286 * 287 * @return list of Strings containing names of the providers 288 */ 289 public List<String> getAllProviders() { 290 if (false) { 291 Log.d(TAG, "getAllProviders"); 292 } 293 try { 294 return mService.getAllProviders(); 295 } catch (RemoteException ex) { 296 Log.e(TAG, "getAllProviders: RemoteException", ex); 297 } 298 return null; 299 } 300 301 /** 302 * Returns a list of the names of location providers. Only providers that 303 * are permitted to be accessed by the calling activity will be returned. 304 * 305 * @param enabledOnly if true then only the providers which are currently 306 * enabled are returned. 307 * @return list of Strings containing names of the providers 308 */ 309 public List<String> getProviders(boolean enabledOnly) { 310 try { 311 return mService.getProviders(null, enabledOnly); 312 } catch (RemoteException ex) { 313 Log.e(TAG, "getProviders: RemoteException", ex); 314 } 315 return null; 316 } 317 318 /** 319 * Returns the information associated with the location provider of the 320 * given name, or null if no provider exists by that name. 321 * 322 * @param name the provider name 323 * @return a LocationProvider, or null 324 * 325 * @throws IllegalArgumentException if name is null 326 * @throws SecurityException if the caller is not permitted to access the 327 * given provider. 328 */ 329 public LocationProvider getProvider(String name) { 330 if (name == null) { 331 throw new IllegalArgumentException("name==null"); 332 } 333 try { 334 Bundle info = mService.getProviderInfo(name); 335 if (info == null) { 336 return null; 337 } 338 return createProvider(name, info); 339 } catch (RemoteException ex) { 340 Log.e(TAG, "getProvider: RemoteException", ex); 341 } 342 return null; 343 } 344 345 /** 346 * Returns a list of the names of LocationProviders that satisfy the given 347 * criteria, or null if none do. Only providers that are permitted to be 348 * accessed by the calling activity will be returned. 349 * 350 * @param criteria the criteria that the returned providers must match 351 * @param enabledOnly if true then only the providers which are currently 352 * enabled are returned. 353 * @return list of Strings containing names of the providers 354 */ 355 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 356 if (criteria == null) { 357 throw new IllegalArgumentException("criteria==null"); 358 } 359 try { 360 return mService.getProviders(criteria, enabledOnly); 361 } catch (RemoteException ex) { 362 Log.e(TAG, "getProviders: RemoteException", ex); 363 } 364 return null; 365 } 366 367 /** 368 * Returns the name of the provider that best meets the given criteria. Only providers 369 * that are permitted to be accessed by the calling activity will be 370 * returned. If several providers meet the criteria, the one with the best 371 * accuracy is returned. If no provider meets the criteria, 372 * the criteria are loosened in the following sequence: 373 * 374 * <ul> 375 * <li> power requirement 376 * <li> accuracy 377 * <li> bearing 378 * <li> speed 379 * <li> altitude 380 * </ul> 381 * 382 * <p> Note that the requirement on monetary cost is not removed 383 * in this process. 384 * 385 * @param criteria the criteria that need to be matched 386 * @param enabledOnly if true then only a provider that is currently enabled is returned 387 * @return name of the provider that best matches the requirements 388 */ 389 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 390 if (criteria == null) { 391 throw new IllegalArgumentException("criteria==null"); 392 } 393 try { 394 return mService.getBestProvider(criteria, enabledOnly); 395 } catch (RemoteException ex) { 396 Log.e(TAG, "getBestProvider: RemoteException", ex); 397 } 398 return null; 399 } 400 401 /** 402 * Registers the current activity to be notified periodically by 403 * the named provider. Periodically, the supplied LocationListener will 404 * be called with the current Location or with status updates. 405 * 406 * <p> It may take a while to receive the most recent location. If 407 * an immediate location is required, applications may use the 408 * {@link #getLastKnownLocation(String)} method. 409 * 410 * <p> In case the provider is disabled by the user, updates will stop, 411 * and the {@link LocationListener#onProviderDisabled(String)} 412 * method will be called. As soon as the provider is enabled again, 413 * the {@link LocationListener#onProviderEnabled(String)} method will 414 * be called and location updates will start again. 415 * 416 * <p> The frequency of notification may be controlled using the 417 * minTime and minDistance parameters. If minTime is greater than 0, 418 * the LocationManager could potentially rest for minTime milliseconds 419 * between location updates to conserve power. If minDistance is greater than 0, 420 * a location will only be broadcasted if the device moves by minDistance meters. 421 * To obtain notifications as frequently as possible, set both parameters to 0. 422 * 423 * <p> Background services should be careful about setting a sufficiently high 424 * minTime so that the device doesn't consume too much power by keeping the 425 * GPS or wireless radios on all the time. In particular, values under 60000ms 426 * are not recommended. 427 * 428 * <p> The calling thread must be a {@link android.os.Looper} thread such as 429 * the main thread of the calling Activity. 430 * 431 * @param provider the name of the provider with which to register 432 * @param minTime the minimum time interval for notifications, in 433 * milliseconds. This field is only used as a hint to conserve power, and actual 434 * time between location updates may be greater or lesser than this value. 435 * @param minDistance the minimum distance interval for notifications, 436 * 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 or listener is null 442 * @throws RuntimeException if the calling thread has no Looper 443 * @throws SecurityException if no suitable permission is present for the provider. 444 */ 445 public void requestLocationUpdates(String provider, 446 long minTime, float minDistance, LocationListener listener) { 447 if (provider == null) { 448 throw new IllegalArgumentException("provider==null"); 449 } 450 if (listener == null) { 451 throw new IllegalArgumentException("listener==null"); 452 } 453 _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, null); 454 } 455 456 /** 457 * Registers the current activity to be notified periodically by 458 * the named provider. Periodically, the supplied LocationListener will 459 * be called with the current Location or with status updates. 460 * 461 * <p> It may take a while to receive the most recent location. If 462 * an immediate location is required, applications may use the 463 * {@link #getLastKnownLocation(String)} method. 464 * 465 * <p> In case the provider is disabled by the user, updates will stop, 466 * and the {@link LocationListener#onProviderDisabled(String)} 467 * method will be called. As soon as the provider is enabled again, 468 * the {@link LocationListener#onProviderEnabled(String)} method will 469 * be called and location updates will start again. 470 * 471 * <p> The frequency of notification may be controlled using the 472 * minTime and minDistance parameters. If minTime is greater than 0, 473 * the LocationManager could potentially rest for minTime milliseconds 474 * between location updates to conserve power. If minDistance is greater than 0, 475 * a location will only be broadcasted if the device moves by minDistance meters. 476 * To obtain notifications as frequently as possible, set both parameters to 0. 477 * 478 * <p> Background services should be careful about setting a sufficiently high 479 * minTime so that the device doesn't consume too much power by keeping the 480 * GPS or wireless radios on all the time. In particular, values under 60000ms 481 * are not recommended. 482 * 483 * <p> The supplied Looper is used to implement the callback mechanism. 484 * 485 * @param provider the name of the provider with which to register 486 * @param minTime the minimum time interval for notifications, in 487 * milliseconds. This field is only used as a hint to conserve power, and actual 488 * time between location updates may be greater or lesser than this value. 489 * @param minDistance the minimum distance interval for notifications, 490 * in meters 491 * @param listener a {#link LocationListener} whose 492 * {@link LocationListener#onLocationChanged} method will be called for 493 * each location update 494 * @param looper a Looper object whose message queue will be used to 495 * implement the callback mechanism. 496 * If looper is null then the callbacks will be called on the main thread. 497 * 498 * @throws IllegalArgumentException if provider is null or doesn't exist 499 * @throws IllegalArgumentException if listener is null 500 * @throws SecurityException if no suitable permission is present for the provider. 501 */ 502 public void requestLocationUpdates(String provider, 503 long minTime, float minDistance, LocationListener listener, 504 Looper looper) { 505 if (provider == null) { 506 throw new IllegalArgumentException("provider==null"); 507 } 508 if (listener == null) { 509 throw new IllegalArgumentException("listener==null"); 510 } 511 _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, looper); 512 } 513 514 /** 515 * Registers the current activity to be notified periodically based on 516 * the specified criteria. Periodically, the supplied LocationListener will 517 * be called with the current Location or with status updates. 518 * 519 * <p> It may take a while to receive the most recent location. If 520 * an immediate location is required, applications may use the 521 * {@link #getLastKnownLocation(String)} method. 522 * 523 * <p> In case the provider is disabled by the user, updates will stop, 524 * and the {@link LocationListener#onProviderDisabled(String)} 525 * method will be called. As soon as the provider is enabled again, 526 * the {@link LocationListener#onProviderEnabled(String)} method will 527 * be called and location updates will start again. 528 * 529 * <p> The frequency of notification may be controlled using the 530 * minTime and minDistance parameters. If minTime is greater than 0, 531 * the LocationManager could potentially rest for minTime milliseconds 532 * between location updates to conserve power. If minDistance is greater than 0, 533 * a location will only be broadcasted if the device moves by minDistance meters. 534 * To obtain notifications as frequently as possible, set both parameters to 0. 535 * 536 * <p> Background services should be careful about setting a sufficiently high 537 * minTime so that the device doesn't consume too much power by keeping the 538 * GPS or wireless radios on all the time. In particular, values under 60000ms 539 * are not recommended. 540 * 541 * <p> The supplied Looper is used to implement the callback mechanism. 542 * 543 * @param minTime the minimum time interval for notifications, in 544 * milliseconds. This field is only used as a hint to conserve power, and actual 545 * time between location updates may be greater or lesser than this value. 546 * @param minDistance the minimum distance interval for notifications, 547 * in meters 548 * @param criteria contains parameters for the location manager to choose the 549 * appropriate provider and parameters to compute the location 550 * @param listener a {#link LocationListener} whose 551 * {@link LocationListener#onLocationChanged} method will be called for 552 * each location update 553 * @param looper a Looper object whose message queue will be used to 554 * implement the callback mechanism. 555 * If looper is null then the callbacks will be called on the main thread. 556 * 557 * @throws IllegalArgumentException if criteria is null 558 * @throws IllegalArgumentException if listener is null 559 * @throws SecurityException if no suitable permission is present to access 560 * the location services. 561 */ 562 public void requestLocationUpdates(long minTime, float minDistance, 563 Criteria criteria, LocationListener listener, Looper looper) { 564 if (criteria == null) { 565 throw new IllegalArgumentException("criteria==null"); 566 } 567 if (listener == null) { 568 throw new IllegalArgumentException("listener==null"); 569 } 570 _requestLocationUpdates(null, criteria, minTime, minDistance, false, listener, looper); 571 } 572 573 private void _requestLocationUpdates(String provider, Criteria criteria, long minTime, 574 float minDistance, boolean singleShot, LocationListener listener, Looper looper) { 575 if (minTime < 0L) { 576 minTime = 0L; 577 } 578 if (minDistance < 0.0f) { 579 minDistance = 0.0f; 580 } 581 582 try { 583 synchronized (mListeners) { 584 ListenerTransport transport = mListeners.get(listener); 585 if (transport == null) { 586 transport = new ListenerTransport(listener, looper); 587 } 588 mListeners.put(listener, transport); 589 mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport); 590 } 591 } catch (RemoteException ex) { 592 Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex); 593 } 594 } 595 596 /** 597 * Registers the current activity to be notified periodically by 598 * the named provider. Periodically, the supplied PendingIntent will 599 * be broadcast with the current Location or with status updates. 600 * 601 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. 602 * 603 * <p> It may take a while to receive the most recent location. If 604 * an immediate location is required, applications may use the 605 * {@link #getLastKnownLocation(String)} method. 606 * 607 * <p> The frequency of notification or new locations may be controlled using the 608 * minTime and minDistance parameters. If minTime is greater than 0, 609 * the LocationManager could potentially rest for minTime milliseconds 610 * between location updates to conserve power. If minDistance is greater than 0, 611 * a location will only be broadcast if the device moves by minDistance meters. 612 * To obtain notifications as frequently as possible, set both parameters to 0. 613 * 614 * <p> Background services should be careful about setting a sufficiently high 615 * minTime so that the device doesn't consume too much power by keeping the 616 * GPS or wireless radios on all the time. In particular, values under 60000ms 617 * are not recommended. 618 * 619 * <p> In case the provider is disabled by the user, updates will stop, 620 * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value 621 * of false. If the provider is re-enabled, an intent will be sent with an 622 * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will 623 * start again. 624 * 625 * <p> If the provider's status changes, an intent will be sent with an extra with key 626 * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated 627 * with the status update will be sent as well. 628 * 629 * @param provider the name of the provider with which to register 630 * @param minTime the minimum time interval for notifications, in 631 * milliseconds. This field is only used as a hint to conserve power, and actual 632 * time between location updates may be greater or lesser than this value. 633 * @param minDistance the minimum distance interval for notifications, 634 * in meters 635 * @param intent a {#link PendingIntent} to be sent for each location update 636 * 637 * @throws IllegalArgumentException if provider is null or doesn't exist 638 * @throws IllegalArgumentException if intent is null 639 * @throws SecurityException if no suitable permission is present for the provider. 640 */ 641 public void requestLocationUpdates(String provider, 642 long minTime, float minDistance, PendingIntent intent) { 643 if (provider == null) { 644 throw new IllegalArgumentException("provider==null"); 645 } 646 if (intent == null) { 647 throw new IllegalArgumentException("intent==null"); 648 } 649 _requestLocationUpdates(provider, null, minTime, minDistance, false, intent); 650 } 651 652 /** 653 * Registers the current activity to be notified periodically based on 654 * the specified criteria. Periodically, the supplied PendingIntent will 655 * be broadcast with the current Location or with status updates. 656 * 657 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. 658 * 659 * <p> It may take a while to receive the most recent location. If 660 * an immediate location is required, applications may use the 661 * {@link #getLastKnownLocation(String)} method. 662 * 663 * <p> The frequency of notification or new locations may be controlled using the 664 * minTime and minDistance parameters. If minTime is greater than 0, 665 * the LocationManager could potentially rest for minTime milliseconds 666 * between location updates to conserve power. If minDistance is greater than 0, 667 * a location will only be broadcast if the device moves by minDistance meters. 668 * To obtain notifications as frequently as possible, set both parameters to 0. 669 * 670 * <p> Background services should be careful about setting a sufficiently high 671 * minTime so that the device doesn't consume too much power by keeping the 672 * GPS or wireless radios on all the time. In particular, values under 60000ms 673 * are not recommended. 674 * 675 * <p> In case the provider is disabled by the user, updates will stop, 676 * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value 677 * of false. If the provider is re-enabled, an intent will be sent with an 678 * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will 679 * start again. 680 * 681 * <p> If the provider's status changes, an intent will be sent with an extra with key 682 * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated 683 * with the status update will be sent as well. 684 * 685 * @param minTime the minimum time interval for notifications, in 686 * milliseconds. This field is only used as a hint to conserve power, and actual 687 * time between location updates may be greater or lesser than this value. 688 * @param minDistance the minimum distance interval for notifications, 689 * in meters 690 * @param criteria contains parameters for the location manager to choose the 691 * appropriate provider and parameters to compute the location 692 * @param intent a {#link PendingIntent} to be sent for each location update 693 * 694 * @throws IllegalArgumentException if provider is null or doesn't exist 695 * @throws IllegalArgumentException if intent is null 696 * @throws SecurityException if no suitable permission is present for the provider. 697 */ 698 public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent) { 699 if (criteria == null) { 700 throw new IllegalArgumentException("criteria==null"); 701 } 702 if (intent == null) { 703 throw new IllegalArgumentException("intent==null"); 704 } 705 _requestLocationUpdates(null, criteria, minTime, minDistance, false, intent); 706 } 707 708 private void _requestLocationUpdates(String provider, Criteria criteria, 709 long minTime, float minDistance, boolean singleShot, PendingIntent intent) { 710 if (minTime < 0L) { 711 minTime = 0L; 712 } 713 if (minDistance < 0.0f) { 714 minDistance = 0.0f; 715 } 716 717 try { 718 mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent); 719 } catch (RemoteException ex) { 720 Log.e(TAG, "requestLocationUpdates: RemoteException", ex); 721 } 722 } 723 724 /** 725 * Requests a single location update from the named provider. 726 * 727 * <p> It may take a while to receive the most recent location. If 728 * an immediate location is required, applications may use the 729 * {@link #getLastKnownLocation(String)} method. 730 * 731 * <p> In case the provider is disabled by the user, the update will not be received, 732 * and the {@link LocationListener#onProviderDisabled(String)} 733 * method will be called. As soon as the provider is enabled again, 734 * the {@link LocationListener#onProviderEnabled(String)} method will 735 * be called and location updates will start again. 736 * 737 * <p> The supplied Looper is used to implement the callback mechanism. 738 * 739 * @param provider the name of the provider with which to register 740 * @param listener a {#link LocationListener} whose 741 * {@link LocationListener#onLocationChanged} method will be called when 742 * the location update is available 743 * @param looper a Looper object whose message queue will be used to 744 * implement the callback mechanism. 745 * If looper is null then the callbacks will be called on the main thread. 746 * 747 * @throws IllegalArgumentException if provider is null or doesn't exist 748 * @throws IllegalArgumentException if listener is null 749 * @throws SecurityException if no suitable permission is present for the provider. 750 */ 751 public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) { 752 if (provider == null) { 753 throw new IllegalArgumentException("provider==null"); 754 } 755 if (listener == null) { 756 throw new IllegalArgumentException("listener==null"); 757 } 758 _requestLocationUpdates(provider, null, 0L, 0.0f, true, listener, looper); 759 } 760 761 /** 762 * Requests a single location update based on the specified criteria. 763 * 764 * <p> It may take a while to receive the most recent location. If 765 * an immediate location is required, applications may use the 766 * {@link #getLastKnownLocation(String)} method. 767 * 768 * <p> In case the provider is disabled by the user, the update will not be received, 769 * and the {@link LocationListener#onProviderDisabled(String)} 770 * method will be called. As soon as the provider is enabled again, 771 * the {@link LocationListener#onProviderEnabled(String)} method will 772 * be called and location updates will start again. 773 * 774 * <p> The supplied Looper is used to implement the callback mechanism. 775 * 776 * @param criteria contains parameters for the location manager to choose the 777 * appropriate provider and parameters to compute the location 778 * @param listener a {#link LocationListener} whose 779 * {@link LocationListener#onLocationChanged} method will be called when 780 * the location update is available 781 * @param looper a Looper object whose message queue will be used to 782 * implement the callback mechanism. 783 * If looper is null then the callbacks will be called on the current thread. 784 * 785 * @throws IllegalArgumentException if criteria is null 786 * @throws IllegalArgumentException if listener is null 787 * @throws SecurityException if no suitable permission is present to access 788 * the location services. 789 */ 790 public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) { 791 if (criteria == null) { 792 throw new IllegalArgumentException("criteria==null"); 793 } 794 if (listener == null) { 795 throw new IllegalArgumentException("listener==null"); 796 } 797 _requestLocationUpdates(null, criteria, 0L, 0.0f, true, listener, looper); 798 } 799 800 /** 801 * Requests a single location update from the named provider. 802 * 803 * <p> It may take a while to receive the most recent location. If 804 * an immediate location is required, applications may use the 805 * {@link #getLastKnownLocation(String)} method. 806 * 807 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. 808 * 809 * <p> In case the provider is disabled by the user, the update will not be received, 810 * and the {@link LocationListener#onProviderDisabled(String)} 811 * method will be called. As soon as the provider is enabled again, 812 * the {@link LocationListener#onProviderEnabled(String)} method will 813 * be called and location updates will start again. 814 * 815 * @param provider the name of the provider with which to register 816 * @param intent a {#link PendingIntent} to be sent for the location update 817 * 818 * @throws IllegalArgumentException if provider is null or doesn't exist 819 * @throws IllegalArgumentException if intent is null 820 * @throws SecurityException if no suitable permission is present for the provider. 821 */ 822 public void requestSingleUpdate(String provider, PendingIntent intent) { 823 if (provider == null) { 824 throw new IllegalArgumentException("provider==null"); 825 } 826 if (intent == null) { 827 throw new IllegalArgumentException("intent==null"); 828 } 829 _requestLocationUpdates(provider, null, 0L, 0.0f, true, intent); 830 } 831 832 /** 833 * Requests a single location update based on the specified criteria. 834 * 835 * <p> It may take a while to receive the most recent location. If 836 * an immediate location is required, applications may use the 837 * {@link #getLastKnownLocation(String)} method. 838 * 839 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. 840 * 841 * <p> In case the provider is disabled by the user, the update will not be received, 842 * and the {@link LocationListener#onProviderDisabled(String)} 843 * method will be called. As soon as the provider is enabled again, 844 * the {@link LocationListener#onProviderEnabled(String)} method will 845 * be called and location updates will start again. 846 * 847 * @param criteria contains parameters for the location manager to choose the 848 * appropriate provider and parameters to compute the location 849 * @param intent a {#link PendingIntent} to be sent for the location update 850 * 851 * @throws IllegalArgumentException if provider is null or doesn't exist 852 * @throws IllegalArgumentException if intent is null 853 * @throws SecurityException if no suitable permission is present for the provider. 854 */ 855 public void requestSingleUpdate(Criteria criteria, PendingIntent intent) { 856 if (criteria == null) { 857 throw new IllegalArgumentException("criteria==null"); 858 } 859 if (intent == null) { 860 throw new IllegalArgumentException("intent==null"); 861 } 862 _requestLocationUpdates(null, criteria, 0L, 0.0f, true, intent); 863 } 864 865 /** 866 * Removes any current registration for location updates of the current activity 867 * with the given LocationListener. Following this call, updates will no longer 868 * occur for this listener. 869 * 870 * @param listener {#link LocationListener} object that no longer needs location updates 871 * @throws IllegalArgumentException if listener is null 872 */ 873 public void removeUpdates(LocationListener listener) { 874 if (listener == null) { 875 throw new IllegalArgumentException("listener==null"); 876 } 877 if (false) { 878 Log.d(TAG, "removeUpdates: listener = " + listener); 879 } 880 try { 881 ListenerTransport transport = mListeners.remove(listener); 882 if (transport != null) { 883 mService.removeUpdates(transport); 884 } 885 } catch (RemoteException ex) { 886 Log.e(TAG, "removeUpdates: DeadObjectException", ex); 887 } 888 } 889 890 /** 891 * Removes any current registration for location updates of the current activity 892 * with the given PendingIntent. Following this call, updates will no longer 893 * occur for this intent. 894 * 895 * @param intent {#link PendingIntent} object that no longer needs location updates 896 * @throws IllegalArgumentException if intent is null 897 */ 898 public void removeUpdates(PendingIntent intent) { 899 if (intent == null) { 900 throw new IllegalArgumentException("intent==null"); 901 } 902 if (false) { 903 Log.d(TAG, "removeUpdates: intent = " + intent); 904 } 905 try { 906 mService.removeUpdatesPI(intent); 907 } catch (RemoteException ex) { 908 Log.e(TAG, "removeUpdates: RemoteException", ex); 909 } 910 } 911 912 /** 913 * Sets a proximity alert for the location given by the position 914 * (latitude, longitude) and the given radius. When the device 915 * detects that it has entered or exited the area surrounding the 916 * location, the given PendingIntent will be used to create an Intent 917 * to be fired. 918 * 919 * <p> The fired Intent will have a boolean extra added with key 920 * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is 921 * entering the proximity region; if false, it is exiting. 922 * 923 * <p> Due to the approximate nature of position estimation, if the 924 * device passes through the given area briefly, it is possible 925 * that no Intent will be fired. Similarly, an Intent could be 926 * fired if the device passes very close to the given area but 927 * does not actually enter it. 928 * 929 * <p> After the number of milliseconds given by the expiration 930 * parameter, the location manager will delete this proximity 931 * alert and no longer monitor it. A value of -1 indicates that 932 * there should be no expiration time. 933 * 934 * <p> In case the screen goes to sleep, checks for proximity alerts 935 * happen only once every 4 minutes. This conserves battery life by 936 * ensuring that the device isn't perpetually awake. 937 * 938 * <p> Internally, this method uses both {@link #NETWORK_PROVIDER} 939 * and {@link #GPS_PROVIDER}. 940 * 941 * @param latitude the latitude of the central point of the 942 * alert region 943 * @param longitude the longitude of the central point of the 944 * alert region 945 * @param radius the radius of the central point of the 946 * alert region, in meters 947 * @param expiration time for this proximity alert, in milliseconds, 948 * or -1 to indicate no expiration 949 * @param intent a PendingIntent that will be used to generate an Intent to 950 * fire when entry to or exit from the alert region is detected 951 * 952 * @throws SecurityException if no permission exists for the required 953 * providers. 954 */ 955 public void addProximityAlert(double latitude, double longitude, 956 float radius, long expiration, PendingIntent intent) { 957 if (false) { 958 Log.d(TAG, "addProximityAlert: latitude = " + latitude + 959 ", longitude = " + longitude + ", radius = " + radius + 960 ", expiration = " + expiration + 961 ", intent = " + intent); 962 } 963 try { 964 mService.addProximityAlert(latitude, longitude, radius, 965 expiration, intent); 966 } catch (RemoteException ex) { 967 Log.e(TAG, "addProximityAlert: RemoteException", ex); 968 } 969 } 970 971 /** 972 * Removes the proximity alert with the given PendingIntent. 973 * 974 * @param intent the PendingIntent that no longer needs to be notified of 975 * proximity alerts 976 */ 977 public void removeProximityAlert(PendingIntent intent) { 978 if (false) { 979 Log.d(TAG, "removeProximityAlert: intent = " + intent); 980 } 981 try { 982 mService.removeProximityAlert(intent); 983 } catch (RemoteException ex) { 984 Log.e(TAG, "removeProximityAlert: RemoteException", ex); 985 } 986 } 987 988 /** 989 * Returns the current enabled/disabled status of the given provider. If the 990 * user has enabled this provider in the Settings menu, true is returned 991 * otherwise false is returned 992 * 993 * @param provider the name of the provider 994 * @return true if the provider is enabled 995 * 996 * @throws SecurityException if no suitable permission is present for the provider. 997 * @throws IllegalArgumentException if provider is null 998 */ 999 public boolean isProviderEnabled(String provider) { 1000 if (provider == null) { 1001 throw new IllegalArgumentException("provider==null"); 1002 } 1003 try { 1004 return mService.isProviderEnabled(provider); 1005 } catch (RemoteException ex) { 1006 Log.e(TAG, "isProviderEnabled: RemoteException", ex); 1007 return false; 1008 } 1009 } 1010 1011 /** 1012 * Returns a Location indicating the data from the last known 1013 * location fix obtained from the given provider. This can be done 1014 * without starting the provider. Note that this location could 1015 * be out-of-date, for example if the device was turned off and 1016 * moved to another location. 1017 * 1018 * <p> If the provider is currently disabled, null is returned. 1019 * 1020 * @param provider the name of the provider 1021 * @return the last known location for the provider, or null 1022 * 1023 * @throws SecurityException if no suitable permission is present for the provider. 1024 * @throws IllegalArgumentException if provider is null or doesn't exist 1025 */ 1026 public Location getLastKnownLocation(String provider) { 1027 if (provider == null) { 1028 throw new IllegalArgumentException("provider==null"); 1029 } 1030 try { 1031 return mService.getLastKnownLocation(provider); 1032 } catch (RemoteException ex) { 1033 Log.e(TAG, "getLastKnowLocation: RemoteException", ex); 1034 return null; 1035 } 1036 } 1037 1038 // Mock provider support 1039 1040 /** 1041 * Creates a mock location provider and adds it to the set of active providers. 1042 * 1043 * @param name the provider name 1044 * @param requiresNetwork 1045 * @param requiresSatellite 1046 * @param requiresCell 1047 * @param hasMonetaryCost 1048 * @param supportsAltitude 1049 * @param supportsSpeed 1050 * @param supportsBearing 1051 * @param powerRequirement 1052 * @param accuracy 1053 * 1054 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1055 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1056 * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled 1057 * @throws IllegalArgumentException if a provider with the given name already exists 1058 */ 1059 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 1060 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 1061 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 1062 try { 1063 mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell, 1064 hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement, 1065 accuracy); 1066 } catch (RemoteException ex) { 1067 Log.e(TAG, "addTestProvider: RemoteException", ex); 1068 } 1069 } 1070 1071 /** 1072 * Removes the mock location provider with the given name. 1073 * 1074 * @param provider the provider name 1075 * 1076 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1077 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1078 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1079 * @throws IllegalArgumentException if no provider with the given name exists 1080 */ 1081 public void removeTestProvider(String provider) { 1082 try { 1083 mService.removeTestProvider(provider); 1084 } catch (RemoteException ex) { 1085 Log.e(TAG, "removeTestProvider: RemoteException", ex); 1086 } 1087 } 1088 1089 /** 1090 * Sets a mock location for the given provider. This location will be used in place 1091 * of any actual location from the provider. 1092 * 1093 * @param provider the provider name 1094 * @param loc the mock location 1095 * 1096 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1097 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1098 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1099 * @throws IllegalArgumentException if no provider with the given name exists 1100 */ 1101 public void setTestProviderLocation(String provider, Location loc) { 1102 try { 1103 mService.setTestProviderLocation(provider, loc); 1104 } catch (RemoteException ex) { 1105 Log.e(TAG, "setTestProviderLocation: RemoteException", ex); 1106 } 1107 } 1108 1109 /** 1110 * Removes any mock location associated with the given provider. 1111 * 1112 * @param provider the provider name 1113 * 1114 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1115 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1116 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1117 * @throws IllegalArgumentException if no provider with the given name exists 1118 */ 1119 public void clearTestProviderLocation(String provider) { 1120 try { 1121 mService.clearTestProviderLocation(provider); 1122 } catch (RemoteException ex) { 1123 Log.e(TAG, "clearTestProviderLocation: RemoteException", ex); 1124 } 1125 } 1126 1127 /** 1128 * Sets a mock enabled value for the given provider. This value will be used in place 1129 * of any actual value from the provider. 1130 * 1131 * @param provider the provider name 1132 * @param enabled the mock enabled value 1133 * 1134 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1135 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1136 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1137 * @throws IllegalArgumentException if no provider with the given name exists 1138 */ 1139 public void setTestProviderEnabled(String provider, boolean enabled) { 1140 try { 1141 mService.setTestProviderEnabled(provider, enabled); 1142 } catch (RemoteException ex) { 1143 Log.e(TAG, "setTestProviderEnabled: RemoteException", ex); 1144 } 1145 } 1146 1147 /** 1148 * Removes any mock enabled value associated with the given provider. 1149 * 1150 * @param provider the provider name 1151 * 1152 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1153 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1154 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1155 * @throws IllegalArgumentException if no provider with the given name exists 1156 */ 1157 public void clearTestProviderEnabled(String provider) { 1158 try { 1159 mService.clearTestProviderEnabled(provider); 1160 } catch (RemoteException ex) { 1161 Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex); 1162 } 1163 1164 } 1165 1166 /** 1167 * Sets mock status values for the given provider. These values will be used in place 1168 * of any actual values from the provider. 1169 * 1170 * @param provider the provider name 1171 * @param status the mock status 1172 * @param extras a Bundle containing mock extras 1173 * @param updateTime the mock update time 1174 * 1175 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1176 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1177 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1178 * @throws IllegalArgumentException if no provider with the given name exists 1179 */ 1180 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1181 try { 1182 mService.setTestProviderStatus(provider, status, extras, updateTime); 1183 } catch (RemoteException ex) { 1184 Log.e(TAG, "setTestProviderStatus: RemoteException", ex); 1185 } 1186 } 1187 1188 /** 1189 * Removes any mock status values associated with the given provider. 1190 * 1191 * @param provider the provider name 1192 * 1193 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1194 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1195 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1196 * @throws IllegalArgumentException if no provider with the given name exists 1197 */ 1198 public void clearTestProviderStatus(String provider) { 1199 try { 1200 mService.clearTestProviderStatus(provider); 1201 } catch (RemoteException ex) { 1202 Log.e(TAG, "clearTestProviderStatus: RemoteException", ex); 1203 } 1204 } 1205 1206 // GPS-specific support 1207 1208 // This class is used to send GPS status events to the client's main thread. 1209 private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { 1210 1211 private final GpsStatus.Listener mListener; 1212 private final GpsStatus.NmeaListener mNmeaListener; 1213 1214 // This must not equal any of the GpsStatus event IDs 1215 private static final int NMEA_RECEIVED = 1000; 1216 1217 private class Nmea { 1218 long mTimestamp; 1219 String mNmea; 1220 1221 Nmea(long timestamp, String nmea) { 1222 mTimestamp = timestamp; 1223 mNmea = nmea; 1224 } 1225 } 1226 private ArrayList<Nmea> mNmeaBuffer; 1227 1228 GpsStatusListenerTransport(GpsStatus.Listener listener) { 1229 mListener = listener; 1230 mNmeaListener = null; 1231 } 1232 1233 GpsStatusListenerTransport(GpsStatus.NmeaListener listener) { 1234 mNmeaListener = listener; 1235 mListener = null; 1236 mNmeaBuffer = new ArrayList<Nmea>(); 1237 } 1238 1239 public void onGpsStarted() { 1240 if (mListener != null) { 1241 Message msg = Message.obtain(); 1242 msg.what = GpsStatus.GPS_EVENT_STARTED; 1243 mGpsHandler.sendMessage(msg); 1244 } 1245 } 1246 1247 public void onGpsStopped() { 1248 if (mListener != null) { 1249 Message msg = Message.obtain(); 1250 msg.what = GpsStatus.GPS_EVENT_STOPPED; 1251 mGpsHandler.sendMessage(msg); 1252 } 1253 } 1254 1255 public void onFirstFix(int ttff) { 1256 if (mListener != null) { 1257 mGpsStatus.setTimeToFirstFix(ttff); 1258 Message msg = Message.obtain(); 1259 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; 1260 mGpsHandler.sendMessage(msg); 1261 } 1262 } 1263 1264 public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, 1265 float[] elevations, float[] azimuths, int ephemerisMask, 1266 int almanacMask, int usedInFixMask) { 1267 if (mListener != null) { 1268 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, 1269 ephemerisMask, almanacMask, usedInFixMask); 1270 1271 Message msg = Message.obtain(); 1272 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; 1273 // remove any SV status messages already in the queue 1274 mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); 1275 mGpsHandler.sendMessage(msg); 1276 } 1277 } 1278 1279 public void onNmeaReceived(long timestamp, String nmea) { 1280 if (mNmeaListener != null) { 1281 synchronized (mNmeaBuffer) { 1282 mNmeaBuffer.add(new Nmea(timestamp, nmea)); 1283 } 1284 Message msg = Message.obtain(); 1285 msg.what = NMEA_RECEIVED; 1286 // remove any NMEA_RECEIVED messages already in the queue 1287 mGpsHandler.removeMessages(NMEA_RECEIVED); 1288 mGpsHandler.sendMessage(msg); 1289 } 1290 } 1291 1292 private final Handler mGpsHandler = new Handler() { 1293 @Override 1294 public void handleMessage(Message msg) { 1295 if (msg.what == NMEA_RECEIVED) { 1296 synchronized (mNmeaBuffer) { 1297 int length = mNmeaBuffer.size(); 1298 for (int i = 0; i < length; i++) { 1299 Nmea nmea = mNmeaBuffer.get(i); 1300 mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea); 1301 } 1302 mNmeaBuffer.clear(); 1303 } 1304 } else { 1305 // synchronize on mGpsStatus to ensure the data is copied atomically. 1306 synchronized(mGpsStatus) { 1307 mListener.onGpsStatusChanged(msg.what); 1308 } 1309 } 1310 } 1311 }; 1312 } 1313 1314 /** 1315 * Adds a GPS status listener. 1316 * 1317 * @param listener GPS status listener object to register 1318 * 1319 * @return true if the listener was successfully added 1320 * 1321 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1322 */ 1323 public boolean addGpsStatusListener(GpsStatus.Listener listener) { 1324 boolean result; 1325 1326 if (mGpsStatusListeners.get(listener) != null) { 1327 // listener is already registered 1328 return true; 1329 } 1330 try { 1331 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1332 result = mService.addGpsStatusListener(transport); 1333 if (result) { 1334 mGpsStatusListeners.put(listener, transport); 1335 } 1336 } catch (RemoteException e) { 1337 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1338 result = false; 1339 } 1340 1341 return result; 1342 } 1343 1344 /** 1345 * Removes a GPS status listener. 1346 * 1347 * @param listener GPS status listener object to remove 1348 */ 1349 public void removeGpsStatusListener(GpsStatus.Listener listener) { 1350 try { 1351 GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener); 1352 if (transport != null) { 1353 mService.removeGpsStatusListener(transport); 1354 } 1355 } catch (RemoteException e) { 1356 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1357 } 1358 } 1359 1360 /** 1361 * Adds an NMEA listener. 1362 * 1363 * @param listener a {#link GpsStatus.NmeaListener} object to register 1364 * 1365 * @return true if the listener was successfully added 1366 * 1367 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1368 */ 1369 public boolean addNmeaListener(GpsStatus.NmeaListener listener) { 1370 boolean result; 1371 1372 if (mNmeaListeners.get(listener) != null) { 1373 // listener is already registered 1374 return true; 1375 } 1376 try { 1377 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1378 result = mService.addGpsStatusListener(transport); 1379 if (result) { 1380 mNmeaListeners.put(listener, transport); 1381 } 1382 } catch (RemoteException e) { 1383 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1384 result = false; 1385 } 1386 1387 return result; 1388 } 1389 1390 /** 1391 * Removes an NMEA listener. 1392 * 1393 * @param listener a {#link GpsStatus.NmeaListener} object to remove 1394 */ 1395 public void removeNmeaListener(GpsStatus.NmeaListener listener) { 1396 try { 1397 GpsStatusListenerTransport transport = mNmeaListeners.remove(listener); 1398 if (transport != null) { 1399 mService.removeGpsStatusListener(transport); 1400 } 1401 } catch (RemoteException e) { 1402 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1403 } 1404 } 1405 1406 /** 1407 * Retrieves information about the current status of the GPS engine. 1408 * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} 1409 * callback to ensure that the data is copied atomically. 1410 * 1411 * The caller may either pass in a {@link GpsStatus} object to set with the latest 1412 * status information, or pass null to create a new {@link GpsStatus} object. 1413 * 1414 * @param status object containing GPS status details, or null. 1415 * @return status object containing updated GPS status. 1416 */ 1417 public GpsStatus getGpsStatus(GpsStatus status) { 1418 if (status == null) { 1419 status = new GpsStatus(); 1420 } 1421 status.setStatus(mGpsStatus); 1422 return status; 1423 } 1424 1425 /** 1426 * Sends additional commands to a location provider. 1427 * Can be used to support provider specific extensions to the Location Manager API 1428 * 1429 * @param provider name of the location provider. 1430 * @param command name of the command to send to the provider. 1431 * @param extras optional arguments for the command (or null). 1432 * The provider may optionally fill the extras Bundle with results from the command. 1433 * 1434 * @return true if the command succeeds. 1435 */ 1436 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1437 try { 1438 return mService.sendExtraCommand(provider, command, extras); 1439 } catch (RemoteException e) { 1440 Log.e(TAG, "RemoteException in sendExtraCommand: ", e); 1441 return false; 1442 } 1443 } 1444 1445 /** 1446 * Used by NetInitiatedActivity to report user response 1447 * for network initiated GPS fix requests. 1448 * 1449 * {@hide} 1450 */ 1451 public boolean sendNiResponse(int notifId, int userResponse) { 1452 try { 1453 return mService.sendNiResponse(notifId, userResponse); 1454 } catch (RemoteException e) { 1455 Log.e(TAG, "RemoteException in sendNiResponse: ", e); 1456 return false; 1457 } 1458 } 1459 1460 } 1461