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