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