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