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