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