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