2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.location;
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;
28 import com.android.internal.location.DummyLocationProvider;
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;
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.
44 * instantiate this class directly; instead, retrieve it through
45 * {@link android.content.Context#getSystemService
46 * Context.getSystemService(Context.LOCATION_SERVICE)}.
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();
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.
62 * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION
63 * or android.permission.ACCESS_FINE_LOCATION.
65 public static final String NETWORK_PROVIDER = "network";
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
72 * Requires the permission android.permission.ACCESS_FINE_LOCATION.
74 * <p> The extras Bundle for the GPS location provider can contain the
75 * following key/value pairs:
78 * <li> satellites - the number of satellites used to derive the fix
81 public static final String GPS_PROVIDER = "gps";
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.
91 * Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS
92 * is not enabled this provider might only return coarse fixes.
94 public static final String PASSIVE_PROVIDER = "passive";
97 * Key used for the Bundle extra holding a boolean indicating whether
98 * a proximity alert is entering (true) or exiting (false)..
100 public static final String KEY_PROXIMITY_ENTERING = "entering";
103 * Key used for a Bundle extra holding an Integer status value
104 * when a status change is broadcast using a PendingIntent.
106 public static final String KEY_STATUS_CHANGED = "status";
109 * Key used for a Bundle extra holding an Boolean status value
110 * when a provider enabled/disabled event is broadcast using a PendingIntent.
112 public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
115 * Key used for a Bundle extra holding a Location value
116 * when a location change is broadcast using a PendingIntent.
118 public static final String KEY_LOCATION_CHANGED = "location";
120 // Map from LocationListeners to their associated ListenerTransport objects
121 private HashMap<LocationListener,ListenerTransport> mListeners =
122 new HashMap<LocationListener,ListenerTransport>();
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;
130 private LocationListener mListener;
131 private final Handler mListenerHandler;
133 ListenerTransport(LocationListener listener, Looper looper) {
134 mListener = listener;
136 if (looper == null) {
137 mListenerHandler = new Handler() {
139 public void handleMessage(Message msg) {
144 mListenerHandler = new Handler(looper) {
146 public void handleMessage(Message msg) {
153 public void onLocationChanged(Location location) {
154 Message msg = Message.obtain();
155 msg.what = TYPE_LOCATION_CHANGED;
157 mListenerHandler.sendMessage(msg);
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);
170 mListenerHandler.sendMessage(msg);
173 public void onProviderEnabled(String provider) {
174 Message msg = Message.obtain();
175 msg.what = TYPE_PROVIDER_ENABLED;
177 mListenerHandler.sendMessage(msg);
180 public void onProviderDisabled(String provider) {
181 Message msg = Message.obtain();
182 msg.what = TYPE_PROVIDER_DISABLED;
184 mListenerHandler.sendMessage(msg);
187 private void _handleMessage(Message msg) {
189 case TYPE_LOCATION_CHANGED:
190 Location location = new Location((Location) msg.obj);
191 mListener.onLocationChanged(location);
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);
200 case TYPE_PROVIDER_ENABLED:
201 mListener.onProviderEnabled((String) msg.obj);
203 case TYPE_PROVIDER_DISABLED:
204 mListener.onProviderDisabled((String) msg.obj);
208 mService.locationCallbackFinished(this);
209 } catch (RemoteException e) {
210 Log.e(TAG, "locationCallbackFinished: RemoteException", e);
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.
220 public LocationManager(ILocationManager service) {
222 Log.d(TAG, "Constructor: service = " + service);
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"));
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.
247 * @return list of Strings containing names of the providers
249 public List<String> getAllProviders() {
251 Log.d(TAG, "getAllProviders");
254 return mService.getAllProviders();
255 } catch (RemoteException ex) {
256 Log.e(TAG, "getAllProviders: RemoteException", ex);
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.
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
269 public List<String> getProviders(boolean enabledOnly) {
271 return mService.getProviders(enabledOnly);
272 } catch (RemoteException ex) {
273 Log.e(TAG, "getProviders: RemoteException", ex);
279 * Returns the information associated with the location provider of the
280 * given name, or null if no provider exists by that name.
282 * @param name the provider name
283 * @return a LocationProvider, or null
285 * @throws IllegalArgumentException if name is null
286 * @throws SecurityException if the caller is not permitted to access the
289 public LocationProvider getProvider(String name) {
291 throw new IllegalArgumentException("name==null");
294 Bundle info = mService.getProviderInfo(name);
298 return createProvider(name, info);
299 } catch (RemoteException ex) {
300 Log.e(TAG, "getProvider: RemoteException", ex);
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.
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
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>();
324 goodProviders.add(providerName);
327 return goodProviders;
331 * Returns the next looser power requirement, in the sequence:
333 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
335 private int nextPower(int 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:
345 return Criteria.NO_REQUIREMENT;
350 * Returns the next looser accuracy requirement, in the sequence:
352 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
354 private int nextAccuracy(int accuracy) {
355 if (accuracy == Criteria.ACCURACY_FINE) {
356 return Criteria.ACCURACY_COARSE;
358 return Criteria.NO_REQUIREMENT;
362 private abstract class LpComparator implements Comparator<LocationProvider> {
364 public int compare(int a1, int a2) {
367 } else if (a1 > a2) {
374 public int compare(float a1, float a2) {
377 } else if (a1 > a2) {
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
392 public boolean equals(LocationProvider l1, LocationProvider l2) {
393 int a1 = l1.getPowerRequirement();
394 int a2 = l2.getPowerRequirement();
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
406 public boolean equals(LocationProvider l1, LocationProvider l2) {
407 int a1 = l1.getAccuracy();
408 int a2 = l2.getAccuracy();
413 private class LpCapabilityComparator extends LpComparator {
415 private static final int ALTITUDE_SCORE = 4;
416 private static final int BEARING_SCORE = 4;
417 private static final int SPEED_SCORE = 4;
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);
425 public int compare(LocationProvider l1, LocationProvider l2) {
428 return compare(-a1, -a2); // Bigger is better
431 public boolean equals(LocationProvider l1, LocationProvider l2) {
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));
444 if (providers.size() < 2) {
445 return providers.get(0);
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);
457 List<LocationProvider> tmp = new ArrayList<LocationProvider>();
459 size = providers.size();
460 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
461 tmp.add(providers.get(idx));
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()) {
472 List<LocationProvider> tmp2 = new ArrayList<LocationProvider>();
475 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
476 tmp2.add(tmp.get(idx));
480 // Finally, sort by capability "score"
481 Collections.sort(tmp2, new LpCapabilityComparator());
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:
493 * <li> power requirement
500 * <p> Note that the requirement on monetary cost is not removed
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
507 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
508 List<String> goodProviders = getProviders(criteria, enabledOnly);
509 if (!goodProviders.isEmpty()) {
510 return best(goodProviders).getName();
513 // Make a copy of the criteria that we can modify
514 criteria = new Criteria(criteria);
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);
523 if (!goodProviders.isEmpty()) {
524 return best(goodProviders).getName();
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;
535 // criteria.setPreferredResponseTime(responseTime);
536 // goodProviders = getProviders(criteria);
538 // if (!goodProviders.isEmpty()) {
539 // return best(goodProviders);
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);
549 if (!goodProviders.isEmpty()) {
550 return best(goodProviders).getName();
553 // Remove bearing requirement
554 criteria.setBearingRequired(false);
555 goodProviders = getProviders(criteria, enabledOnly);
556 if (!goodProviders.isEmpty()) {
557 return best(goodProviders).getName();
560 // Remove speed requirement
561 criteria.setSpeedRequired(false);
562 goodProviders = getProviders(criteria, enabledOnly);
563 if (!goodProviders.isEmpty()) {
564 return best(goodProviders).getName();
567 // Remove altitude requirement
568 criteria.setAltitudeRequired(false);
569 goodProviders = getProviders(criteria, enabledOnly);
570 if (!goodProviders.isEmpty()) {
571 return best(goodProviders).getName();
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.
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.
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.
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.
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.
604 * <p> The calling thread must be a {@link android.os.Looper} thread such as
605 * the main thread of the calling Activity.
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,
613 * @param listener a {#link LocationListener} whose
614 * {@link LocationListener#onLocationChanged} method will be called for
615 * each location update
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.
622 public void requestLocationUpdates(String provider,
623 long minTime, float minDistance, LocationListener listener) {
624 if (provider == null) {
625 throw new IllegalArgumentException("provider==null");
627 if (listener == null) {
628 throw new IllegalArgumentException("listener==null");
630 _requestLocationUpdates(provider, minTime, minDistance, listener, null);
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.
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.
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.
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.
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.
660 * <p> The supplied Looper is used to implement the callback mechanism.
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,
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.
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.
679 public void requestLocationUpdates(String provider,
680 long minTime, float minDistance, LocationListener listener,
682 if (provider == null) {
683 throw new IllegalArgumentException("provider==null");
685 if (listener == null) {
686 throw new IllegalArgumentException("listener==null");
688 if (looper == null) {
689 throw new IllegalArgumentException("looper==null");
691 _requestLocationUpdates(provider, minTime, minDistance, listener, looper);
694 private void _requestLocationUpdates(String provider,
695 long minTime, float minDistance, LocationListener listener,
700 if (minDistance < 0.0f) {
705 synchronized (mListeners) {
706 ListenerTransport transport = mListeners.get(listener);
707 if (transport == null) {
708 transport = new ListenerTransport(listener, looper);
710 mListeners.put(listener, transport);
711 mService.requestLocationUpdates(provider, minTime, minDistance, transport);
713 } catch (RemoteException ex) {
714 Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
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.
723 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
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.
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.
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.
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
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.
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,
757 * @param intent a {#link PendingIntet} to be sent for each location update
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.
763 public void requestLocationUpdates(String provider,
764 long minTime, float minDistance, PendingIntent intent) {
765 if (provider == null) {
766 throw new IllegalArgumentException("provider==null");
768 if (intent == null) {
769 throw new IllegalArgumentException("intent==null");
771 _requestLocationUpdates(provider, minTime, minDistance, intent);
774 private void _requestLocationUpdates(String provider,
775 long minTime, float minDistance, PendingIntent intent) {
779 if (minDistance < 0.0f) {
784 mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent);
785 } catch (RemoteException ex) {
786 Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
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.
795 * @param listener {#link LocationListener} object that no longer needs location updates
796 * @throws IllegalArgumentException if listener is null
798 public void removeUpdates(LocationListener listener) {
799 if (listener == null) {
800 throw new IllegalArgumentException("listener==null");
803 Log.d(TAG, "removeUpdates: listener = " + listener);
806 ListenerTransport transport = mListeners.remove(listener);
807 if (transport != null) {
808 mService.removeUpdates(transport);
810 } catch (RemoteException ex) {
811 Log.e(TAG, "removeUpdates: DeadObjectException", ex);
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.
820 * @param intent {#link PendingIntent} object that no longer needs location updates
821 * @throws IllegalArgumentException if intent is null
823 public void removeUpdates(PendingIntent intent) {
824 if (intent == null) {
825 throw new IllegalArgumentException("intent==null");
828 Log.d(TAG, "removeUpdates: intent = " + intent);
831 mService.removeUpdatesPI(intent);
832 } catch (RemoteException ex) {
833 Log.e(TAG, "removeUpdates: RemoteException", ex);
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
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.
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.
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.
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.
863 * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
864 * and {@link #GPS_PROVIDER}.
866 * @param latitude the latitude of the central point of the
868 * @param longitude the longitude of the central point of the
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
877 * @throws SecurityException if no permission exists for the required
880 public void addProximityAlert(double latitude, double longitude,
881 float radius, long expiration, PendingIntent intent) {
883 Log.d(TAG, "addProximityAlert: latitude = " + latitude +
884 ", longitude = " + longitude + ", radius = " + radius +
885 ", expiration = " + expiration +
886 ", intent = " + intent);
889 mService.addProximityAlert(latitude, longitude, radius,
891 } catch (RemoteException ex) {
892 Log.e(TAG, "addProximityAlert: RemoteException", ex);
897 * Removes the proximity alert with the given PendingIntent.
899 * @param intent the PendingIntent that no longer needs to be notified of
902 public void removeProximityAlert(PendingIntent intent) {
904 Log.d(TAG, "removeProximityAlert: intent = " + intent);
907 mService.removeProximityAlert(intent);
908 } catch (RemoteException ex) {
909 Log.e(TAG, "removeProximityAlert: RemoteException", ex);
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
918 * @param provider the name of the provider
919 * @return true if the provider is enabled
921 * @throws SecurityException if no suitable permission is present for the provider.
922 * @throws IllegalArgumentException if provider is null or doesn't exist
924 public boolean isProviderEnabled(String provider) {
925 if (provider == null) {
926 throw new IllegalArgumentException("provider==null");
929 return mService.isProviderEnabled(provider);
930 } catch (RemoteException ex) {
931 Log.e(TAG, "isProviderEnabled: RemoteException", ex);
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.
943 * <p> If the provider is currently disabled, null is returned.
945 * @param provider the name of the provider
946 * @return the last known location for the provider, or null
948 * @throws SecurityException if no suitable permission is present for the provider.
949 * @throws IllegalArgumentException if provider is null or doesn't exist
951 public Location getLastKnownLocation(String provider) {
952 if (provider == null) {
953 throw new IllegalArgumentException("provider==null");
956 return mService.getLastKnownLocation(provider);
957 } catch (RemoteException ex) {
958 Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
963 // Mock provider support
966 * Creates a mock location provider and adds it to the set of active providers.
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
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
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) {
988 mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell,
989 hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement,
991 } catch (RemoteException ex) {
992 Log.e(TAG, "addTestProvider: RemoteException", ex);
997 * Removes the mock location provider with the given name.
999 * @param provider the provider name
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
1006 public void removeTestProvider(String provider) {
1008 mService.removeTestProvider(provider);
1009 } catch (RemoteException ex) {
1010 Log.e(TAG, "removeTestProvider: RemoteException", ex);
1015 * Sets a mock location for the given provider. This location will be used in place
1016 * of any actual location from the provider.
1018 * @param provider the provider name
1019 * @param loc the mock location
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
1026 public void setTestProviderLocation(String provider, Location loc) {
1028 mService.setTestProviderLocation(provider, loc);
1029 } catch (RemoteException ex) {
1030 Log.e(TAG, "setTestProviderLocation: RemoteException", ex);
1035 * Removes any mock location associated with the given provider.
1037 * @param provider the provider name
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
1044 public void clearTestProviderLocation(String provider) {
1046 mService.clearTestProviderLocation(provider);
1047 } catch (RemoteException ex) {
1048 Log.e(TAG, "clearTestProviderLocation: RemoteException", ex);
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.
1056 * @param provider the provider name
1057 * @param enabled the mock enabled value
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
1064 public void setTestProviderEnabled(String provider, boolean enabled) {
1066 mService.setTestProviderEnabled(provider, enabled);
1067 } catch (RemoteException ex) {
1068 Log.e(TAG, "setTestProviderEnabled: RemoteException", ex);
1073 * Removes any mock enabled value associated with the given provider.
1075 * @param provider the provider name
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
1082 public void clearTestProviderEnabled(String provider) {
1084 mService.clearTestProviderEnabled(provider);
1085 } catch (RemoteException ex) {
1086 Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex);
1092 * Sets mock status values for the given provider. These values will be used in place
1093 * of any actual values from the provider.
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
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
1105 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1107 mService.setTestProviderStatus(provider, status, extras, updateTime);
1108 } catch (RemoteException ex) {
1109 Log.e(TAG, "setTestProviderStatus: RemoteException", ex);
1114 * Removes any mock status values associated with the given provider.
1116 * @param provider the provider name
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
1123 public void clearTestProviderStatus(String provider) {
1125 mService.clearTestProviderStatus(provider);
1126 } catch (RemoteException ex) {
1127 Log.e(TAG, "clearTestProviderStatus: RemoteException", ex);
1131 // GPS-specific support
1133 // This class is used to send GPS status events to the client's main thread.
1134 private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
1136 private final GpsStatus.Listener mListener;
1137 private final GpsStatus.NmeaListener mNmeaListener;
1139 // This must not equal any of the GpsStatus event IDs
1140 private static final int NMEA_RECEIVED = 1000;
1142 private class Nmea {
1146 Nmea(long timestamp, String nmea) {
1147 mTimestamp = timestamp;
1151 private ArrayList<Nmea> mNmeaBuffer;
1153 GpsStatusListenerTransport(GpsStatus.Listener listener) {
1154 mListener = listener;
1155 mNmeaListener = null;
1158 GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
1159 mNmeaListener = listener;
1161 mNmeaBuffer = new ArrayList<Nmea>();
1164 public void onGpsStarted() {
1165 if (mListener != null) {
1166 Message msg = Message.obtain();
1167 msg.what = GpsStatus.GPS_EVENT_STARTED;
1168 mGpsHandler.sendMessage(msg);
1172 public void onGpsStopped() {
1173 if (mListener != null) {
1174 Message msg = Message.obtain();
1175 msg.what = GpsStatus.GPS_EVENT_STOPPED;
1176 mGpsHandler.sendMessage(msg);
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);
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);
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);
1204 public void onNmeaReceived(long timestamp, String nmea) {
1205 if (mNmeaListener != null) {
1206 synchronized (mNmeaBuffer) {
1207 mNmeaBuffer.add(new Nmea(timestamp, nmea));
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);
1217 private final Handler mGpsHandler = new Handler() {
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);
1227 mNmeaBuffer.clear();
1230 // synchronize on mGpsStatus to ensure the data is copied atomically.
1231 synchronized(mGpsStatus) {
1232 mListener.onGpsStatusChanged(msg.what);
1240 * Adds a GPS status listener.
1242 * @param listener GPS status listener object to register
1244 * @return true if the listener was successfully added
1246 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1248 public boolean addGpsStatusListener(GpsStatus.Listener listener) {
1251 if (mGpsStatusListeners.get(listener) != null) {
1252 // listener is already registered
1256 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1257 result = mService.addGpsStatusListener(transport);
1259 mGpsStatusListeners.put(listener, transport);
1261 } catch (RemoteException e) {
1262 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1270 * Removes a GPS status listener.
1272 * @param listener GPS status listener object to remove
1274 public void removeGpsStatusListener(GpsStatus.Listener listener) {
1276 GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
1277 if (transport != null) {
1278 mService.removeGpsStatusListener(transport);
1280 } catch (RemoteException e) {
1281 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
1286 * Adds an NMEA listener.
1288 * @param listener a {#link GpsStatus.NmeaListener} object to register
1290 * @return true if the listener was successfully added
1292 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1294 public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
1297 if (mNmeaListeners.get(listener) != null) {
1298 // listener is already registered
1302 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1303 result = mService.addGpsStatusListener(transport);
1305 mNmeaListeners.put(listener, transport);
1307 } catch (RemoteException e) {
1308 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1316 * Removes an NMEA listener.
1318 * @param listener a {#link GpsStatus.NmeaListener} object to remove
1320 public void removeNmeaListener(GpsStatus.NmeaListener listener) {
1322 GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
1323 if (transport != null) {
1324 mService.removeGpsStatusListener(transport);
1326 } catch (RemoteException e) {
1327 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
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.
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.
1339 * @param status object containing GPS status details, or null.
1340 * @return status object containing updated GPS status.
1342 public GpsStatus getGpsStatus(GpsStatus status) {
1343 if (status == null) {
1344 status = new GpsStatus();
1346 status.setStatus(mGpsStatus);
1351 * Sends additional commands to a location provider.
1352 * Can be used to support provider specific extensions to the Location Manager API
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.
1359 * @return true if the command succeeds.
1361 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1363 return mService.sendExtraCommand(provider, command, extras);
1364 } catch (RemoteException e) {
1365 Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
1371 * Used by NetInitiatedActivity to report user response
1372 * for network initiated GPS fix requests.
1376 public boolean sendNiResponse(int notifId, int userResponse) {
1378 return mService.sendNiResponse(notifId, userResponse);
1379 } catch (RemoteException e) {
1380 Log.e(TAG, "RemoteException in sendNiResponse: ", e);