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 * Key used for the Bundle extra holding a boolean indicating whether
85 * a proximity alert is entering (true) or exiting (false)..
87 public static final String KEY_PROXIMITY_ENTERING = "entering";
90 * Key used for a Bundle extra holding an Integer status value
91 * when a status change is broadcast using a PendingIntent.
93 public static final String KEY_STATUS_CHANGED = "status";
96 * Key used for a Bundle extra holding an Boolean status value
97 * when a provider enabled/disabled event is broadcast using a PendingIntent.
99 public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
102 * Key used for a Bundle extra holding a Location value
103 * when a location change is broadcast using a PendingIntent.
105 public static final String KEY_LOCATION_CHANGED = "location";
107 // Map from LocationListeners to their associated ListenerTransport objects
108 private HashMap<LocationListener,ListenerTransport> mListeners =
109 new HashMap<LocationListener,ListenerTransport>();
111 private class ListenerTransport extends ILocationListener.Stub {
112 private static final int TYPE_LOCATION_CHANGED = 1;
113 private static final int TYPE_STATUS_CHANGED = 2;
114 private static final int TYPE_PROVIDER_ENABLED = 3;
115 private static final int TYPE_PROVIDER_DISABLED = 4;
117 private LocationListener mListener;
118 private final Handler mListenerHandler;
120 ListenerTransport(LocationListener listener, Looper looper) {
121 mListener = listener;
123 if (looper == null) {
124 mListenerHandler = new Handler() {
126 public void handleMessage(Message msg) {
131 mListenerHandler = new Handler(looper) {
133 public void handleMessage(Message msg) {
140 public void onLocationChanged(Location location) {
141 Message msg = Message.obtain();
142 msg.what = TYPE_LOCATION_CHANGED;
144 mListenerHandler.sendMessage(msg);
147 public void onStatusChanged(String provider, int status, Bundle extras) {
148 Message msg = Message.obtain();
149 msg.what = TYPE_STATUS_CHANGED;
150 Bundle b = new Bundle();
151 b.putString("provider", provider);
152 b.putInt("status", status);
153 if (extras != null) {
154 b.putBundle("extras", extras);
157 mListenerHandler.sendMessage(msg);
160 public void onProviderEnabled(String provider) {
161 Message msg = Message.obtain();
162 msg.what = TYPE_PROVIDER_ENABLED;
164 mListenerHandler.sendMessage(msg);
167 public void onProviderDisabled(String provider) {
168 Message msg = Message.obtain();
169 msg.what = TYPE_PROVIDER_DISABLED;
171 mListenerHandler.sendMessage(msg);
174 private void _handleMessage(Message msg) {
176 case TYPE_LOCATION_CHANGED:
177 Location location = new Location((Location) msg.obj);
178 mListener.onLocationChanged(location);
180 case TYPE_STATUS_CHANGED:
181 Bundle b = (Bundle) msg.obj;
182 String provider = b.getString("provider");
183 int status = b.getInt("status");
184 Bundle extras = b.getBundle("extras");
185 mListener.onStatusChanged(provider, status, extras);
187 case TYPE_PROVIDER_ENABLED:
188 mListener.onProviderEnabled((String) msg.obj);
190 case TYPE_PROVIDER_DISABLED:
191 mListener.onProviderDisabled((String) msg.obj);
195 mService.locationCallbackFinished(this);
196 } catch (RemoteException e) {
197 Log.e(TAG, "locationCallbackFinished: RemoteException", e);
202 * @hide - hide this constructor because it has a parameter
203 * of type ILocationManager, which is a system private class. The
204 * right way to create an instance of this class is using the
205 * factory Context.getSystemService.
207 public LocationManager(ILocationManager service) {
209 Log.d(TAG, "Constructor: service = " + service);
214 private LocationProvider createProvider(String name, Bundle info) {
215 DummyLocationProvider provider =
216 new DummyLocationProvider(name);
217 provider.setRequiresNetwork(info.getBoolean("network"));
218 provider.setRequiresSatellite(info.getBoolean("satellite"));
219 provider.setRequiresCell(info.getBoolean("cell"));
220 provider.setHasMonetaryCost(info.getBoolean("cost"));
221 provider.setSupportsAltitude(info.getBoolean("altitude"));
222 provider.setSupportsSpeed(info.getBoolean("speed"));
223 provider.setSupportsBearing(info.getBoolean("bearing"));
224 provider.setPowerRequirement(info.getInt("power"));
225 provider.setAccuracy(info.getInt("accuracy"));
230 * Returns a list of the names of all known location providers. All
231 * providers are returned, including ones that are not permitted to be
232 * accessed by the calling activity or are currently disabled.
234 * @return list of Strings containing names of the providers
236 public List<String> getAllProviders() {
238 Log.d(TAG, "getAllProviders");
241 return mService.getAllProviders();
242 } catch (RemoteException ex) {
243 Log.e(TAG, "getAllProviders: RemoteException", ex);
249 * Returns a list of the names of location providers. Only providers that
250 * are permitted to be accessed by the calling activity will be returned.
252 * @param enabledOnly if true then only the providers which are currently
253 * enabled are returned.
254 * @return list of Strings containing names of the providers
256 public List<String> getProviders(boolean enabledOnly) {
258 return mService.getProviders(enabledOnly);
259 } catch (RemoteException ex) {
260 Log.e(TAG, "getProviders: RemoteException", ex);
266 * Returns the information associated with the location provider of the
267 * given name, or null if no provider exists by that name.
269 * @param name the provider name
270 * @return a LocationProvider, or null
272 * @throws IllegalArgumentException if name is null
273 * @throws SecurityException if the caller is not permitted to access the
276 public LocationProvider getProvider(String name) {
278 throw new IllegalArgumentException("name==null");
281 Bundle info = mService.getProviderInfo(name);
285 return createProvider(name, info);
286 } catch (RemoteException ex) {
287 Log.e(TAG, "getProvider: RemoteException", ex);
293 * Returns a list of the names of LocationProviders that satisfy the given
294 * criteria, or null if none do. Only providers that are permitted to be
295 * accessed by the calling activity will be returned.
297 * @param criteria the criteria that the returned providers must match
298 * @param enabledOnly if true then only the providers which are currently
299 * enabled are returned.
300 * @return list of Strings containing names of the providers
302 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
303 List<String> goodProviders = Collections.emptyList();
304 List<String> providers = getProviders(enabledOnly);
305 for (String providerName : providers) {
306 LocationProvider provider = getProvider(providerName);
307 if (provider.meetsCriteria(criteria)) {
308 if (goodProviders.isEmpty()) {
309 goodProviders = new ArrayList<String>();
311 goodProviders.add(providerName);
314 return goodProviders;
318 * Returns the next looser power requirement, in the sequence:
320 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
322 private int nextPower(int power) {
324 case Criteria.POWER_LOW:
325 return Criteria.POWER_MEDIUM;
326 case Criteria.POWER_MEDIUM:
327 return Criteria.POWER_HIGH;
328 case Criteria.POWER_HIGH:
329 return Criteria.NO_REQUIREMENT;
330 case Criteria.NO_REQUIREMENT:
332 return Criteria.NO_REQUIREMENT;
337 * Returns the next looser accuracy requirement, in the sequence:
339 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
341 private int nextAccuracy(int accuracy) {
342 if (accuracy == Criteria.ACCURACY_FINE) {
343 return Criteria.ACCURACY_COARSE;
345 return Criteria.NO_REQUIREMENT;
349 private abstract class LpComparator implements Comparator<LocationProvider> {
351 public int compare(int a1, int a2) {
354 } else if (a1 > a2) {
361 public int compare(float a1, float a2) {
364 } else if (a1 > a2) {
372 private class LpPowerComparator extends LpComparator {
373 public int compare(LocationProvider l1, LocationProvider l2) {
374 int a1 = l1.getPowerRequirement();
375 int a2 = l2.getPowerRequirement();
376 return compare(a1, a2); // Smaller is better
379 public boolean equals(LocationProvider l1, LocationProvider l2) {
380 int a1 = l1.getPowerRequirement();
381 int a2 = l2.getPowerRequirement();
386 private class LpAccuracyComparator extends LpComparator {
387 public int compare(LocationProvider l1, LocationProvider l2) {
388 int a1 = l1.getAccuracy();
389 int a2 = l2.getAccuracy();
390 return compare(a1, a2); // Smaller is better
393 public boolean equals(LocationProvider l1, LocationProvider l2) {
394 int a1 = l1.getAccuracy();
395 int a2 = l2.getAccuracy();
400 private class LpCapabilityComparator extends LpComparator {
402 private static final int ALTITUDE_SCORE = 4;
403 private static final int BEARING_SCORE = 4;
404 private static final int SPEED_SCORE = 4;
406 private int score(LocationProvider p) {
407 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
408 (p.supportsBearing() ? BEARING_SCORE : 0) +
409 (p.supportsSpeed() ? SPEED_SCORE : 0);
412 public int compare(LocationProvider l1, LocationProvider l2) {
415 return compare(-a1, -a2); // Bigger is better
418 public boolean equals(LocationProvider l1, LocationProvider l2) {
425 private LocationProvider best(List<String> providerNames) {
426 List<LocationProvider> providers = new ArrayList<LocationProvider>(providerNames.size());
427 for (String name : providerNames) {
428 providers.add(getProvider(name));
431 if (providers.size() < 2) {
432 return providers.get(0);
435 // First, sort by power requirement
436 Collections.sort(providers, new LpPowerComparator());
437 int power = providers.get(0).getPowerRequirement();
438 if (power < providers.get(1).getPowerRequirement()) {
439 return providers.get(0);
444 List<LocationProvider> tmp = new ArrayList<LocationProvider>();
446 size = providers.size();
447 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
448 tmp.add(providers.get(idx));
452 // Next, sort by accuracy
453 Collections.sort(tmp, new LpAccuracyComparator());
454 int acc = tmp.get(0).getAccuracy();
455 if (acc < tmp.get(1).getAccuracy()) {
459 List<LocationProvider> tmp2 = new ArrayList<LocationProvider>();
462 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
463 tmp2.add(tmp.get(idx));
467 // Finally, sort by capability "score"
468 Collections.sort(tmp2, new LpCapabilityComparator());
473 * Returns the name of the provider that best meets the given criteria. Only providers
474 * that are permitted to be accessed by the calling activity will be
475 * returned. If several providers meet the criteria, the one with the best
476 * accuracy is returned. If no provider meets the criteria,
477 * the criteria are loosened in the following sequence:
480 * <li> power requirement
487 * <p> Note that the requirement on monetary cost is not removed
490 * @param criteria the criteria that need to be matched
491 * @param enabledOnly if true then only a provider that is currently enabled is returned
492 * @return name of the provider that best matches the requirements
494 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
495 List<String> goodProviders = getProviders(criteria, enabledOnly);
496 if (!goodProviders.isEmpty()) {
497 return best(goodProviders).getName();
500 // Make a copy of the criteria that we can modify
501 criteria = new Criteria(criteria);
503 // Loosen power requirement
504 int power = criteria.getPowerRequirement();
505 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
506 power = nextPower(power);
507 criteria.setPowerRequirement(power);
508 goodProviders = getProviders(criteria, enabledOnly);
510 if (!goodProviders.isEmpty()) {
511 return best(goodProviders).getName();
514 // // Loosen response time requirement
515 // int responseTime = criteria.getPreferredResponseTime();
516 // while (goodProviders.isEmpty() &&
517 // (responseTime != Criteria.NO_REQUIREMENT)) {
518 // responseTime += 1000;
519 // if (responseTime > 60000) {
520 // responseTime = Criteria.NO_REQUIREMENT;
522 // criteria.setPreferredResponseTime(responseTime);
523 // goodProviders = getProviders(criteria);
525 // if (!goodProviders.isEmpty()) {
526 // return best(goodProviders);
529 // Loosen accuracy requirement
530 int accuracy = criteria.getAccuracy();
531 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
532 accuracy = nextAccuracy(accuracy);
533 criteria.setAccuracy(accuracy);
534 goodProviders = getProviders(criteria, enabledOnly);
536 if (!goodProviders.isEmpty()) {
537 return best(goodProviders).getName();
540 // Remove bearing requirement
541 criteria.setBearingRequired(false);
542 goodProviders = getProviders(criteria, enabledOnly);
543 if (!goodProviders.isEmpty()) {
544 return best(goodProviders).getName();
547 // Remove speed requirement
548 criteria.setSpeedRequired(false);
549 goodProviders = getProviders(criteria, enabledOnly);
550 if (!goodProviders.isEmpty()) {
551 return best(goodProviders).getName();
554 // Remove altitude requirement
555 criteria.setAltitudeRequired(false);
556 goodProviders = getProviders(criteria, enabledOnly);
557 if (!goodProviders.isEmpty()) {
558 return best(goodProviders).getName();
565 * Registers the current activity to be notified periodically by
566 * the named provider. Periodically, the supplied LocationListener will
567 * be called with the current Location or with status updates.
569 * <p> It may take a while to receive the most recent location. If
570 * an immediate location is required, applications may use the
571 * {@link #getLastKnownLocation(String)} method.
573 * <p> In case the provider is disabled by the user, updates will stop,
574 * and the {@link LocationListener#onProviderDisabled(String)}
575 * method will be called. As soon as the provider is enabled again,
576 * the {@link LocationListener#onProviderEnabled(String)} method will
577 * be called and location updates will start again.
579 * <p> The frequency of notification may be controlled using the
580 * minTime and minDistance parameters. If minTime is greater than 0,
581 * the LocationManager could potentially rest for minTime milliseconds
582 * between location updates to conserve power. If minDistance is greater than 0,
583 * a location will only be broadcasted if the device moves by minDistance meters.
584 * To obtain notifications as frequently as possible, set both parameters to 0.
586 * <p> Background services should be careful about setting a sufficiently high
587 * minTime so that the device doesn't consume too much power by keeping the
588 * GPS or wireless radios on all the time. In particular, values under 60000ms
589 * are not recommended.
591 * <p> The calling thread must be a {@link android.os.Looper} thread such as
592 * the main thread of the calling Activity.
594 * @param provider the name of the provider with which to register
595 * @param minTime the minimum time interval for notifications, in
596 * milliseconds. This field is only used as a hint to conserve power, and actual
597 * time between location updates may be greater or lesser than this value.
598 * @param minDistance the minimum distance interval for notifications,
600 * @param listener a {#link LocationListener} whose
601 * {@link LocationListener#onLocationChanged} method will be called for
602 * each location update
604 * @throws IllegalArgumentException if provider is null or doesn't exist
605 * @throws IllegalArgumentException if listener is null
606 * @throws RuntimeException if the calling thread has no Looper
607 * @throws SecurityException if no suitable permission is present for the provider.
609 public void requestLocationUpdates(String provider,
610 long minTime, float minDistance, LocationListener listener) {
611 if (provider == null) {
612 throw new IllegalArgumentException("provider==null");
614 if (listener == null) {
615 throw new IllegalArgumentException("listener==null");
617 _requestLocationUpdates(provider, minTime, minDistance, listener, null);
621 * Registers the current activity to be notified periodically by
622 * the named provider. Periodically, the supplied LocationListener will
623 * be called with the current Location or with status updates.
625 * <p> It may take a while to receive the most recent location. If
626 * an immediate location is required, applications may use the
627 * {@link #getLastKnownLocation(String)} method.
629 * <p> In case the provider is disabled by the user, updates will stop,
630 * and the {@link LocationListener#onProviderDisabled(String)}
631 * method will be called. As soon as the provider is enabled again,
632 * the {@link LocationListener#onProviderEnabled(String)} method will
633 * be called and location updates will start again.
635 * <p> The frequency of notification may be controlled using the
636 * minTime and minDistance parameters. If minTime is greater than 0,
637 * the LocationManager could potentially rest for minTime milliseconds
638 * between location updates to conserve power. If minDistance is greater than 0,
639 * a location will only be broadcasted if the device moves by minDistance meters.
640 * To obtain notifications as frequently as possible, set both parameters to 0.
642 * <p> Background services should be careful about setting a sufficiently high
643 * minTime so that the device doesn't consume too much power by keeping the
644 * GPS or wireless radios on all the time. In particular, values under 60000ms
645 * are not recommended.
647 * <p> The supplied Looper is used to implement the callback mechanism.
649 * @param provider the name of the provider with which to register
650 * @param minTime the minimum time interval for notifications, in
651 * milliseconds. This field is only used as a hint to conserve power, and actual
652 * time between location updates may be greater or lesser than this value.
653 * @param minDistance the minimum distance interval for notifications,
655 * @param listener a {#link LocationListener} whose
656 * {@link LocationListener#onLocationChanged} method will be called for
657 * each location update
658 * @param looper a Looper object whose message queue will be used to
659 * implement the callback mechanism.
661 * @throws IllegalArgumentException if provider is null or doesn't exist
662 * @throws IllegalArgumentException if listener is null
663 * @throws IllegalArgumentException if looper is null
664 * @throws SecurityException if no suitable permission is present for the provider.
666 public void requestLocationUpdates(String provider,
667 long minTime, float minDistance, LocationListener listener,
669 if (provider == null) {
670 throw new IllegalArgumentException("provider==null");
672 if (listener == null) {
673 throw new IllegalArgumentException("listener==null");
675 if (looper == null) {
676 throw new IllegalArgumentException("looper==null");
678 _requestLocationUpdates(provider, minTime, minDistance, listener, looper);
681 private void _requestLocationUpdates(String provider,
682 long minTime, float minDistance, LocationListener listener,
687 if (minDistance < 0.0f) {
692 synchronized (mListeners) {
693 ListenerTransport transport = mListeners.get(listener);
694 if (transport == null) {
695 transport = new ListenerTransport(listener, looper);
697 mListeners.put(listener, transport);
698 mService.requestLocationUpdates(provider, minTime, minDistance, transport);
700 } catch (RemoteException ex) {
701 Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
706 * Registers the current activity to be notified periodically by
707 * the named provider. Periodically, the supplied PendingIntent will
708 * be broadcast with the current Location or with status updates.
710 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
712 * <p> It may take a while to receive the most recent location. If
713 * an immediate location is required, applications may use the
714 * {@link #getLastKnownLocation(String)} method.
716 * <p> The frequency of notification or new locations may be controlled using the
717 * minTime and minDistance parameters. If minTime is greater than 0,
718 * the LocationManager could potentially rest for minTime milliseconds
719 * between location updates to conserve power. If minDistance is greater than 0,
720 * a location will only be broadcast if the device moves by minDistance meters.
721 * To obtain notifications as frequently as possible, set both parameters to 0.
723 * <p> Background services should be careful about setting a sufficiently high
724 * minTime so that the device doesn't consume too much power by keeping the
725 * GPS or wireless radios on all the time. In particular, values under 60000ms
726 * are not recommended.
728 * <p> In case the provider is disabled by the user, updates will stop,
729 * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value
730 * of false. If the provider is re-enabled, an intent will be sent with an
731 * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will
734 * <p> If the provider's status changes, an intent will be sent with an extra with key
735 * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated
736 * with the status update will be sent as well.
738 * @param provider the name of the provider with which to register
739 * @param minTime the minimum time interval for notifications, in
740 * milliseconds. This field is only used as a hint to conserve power, and actual
741 * time between location updates may be greater or lesser than this value.
742 * @param minDistance the minimum distance interval for notifications,
744 * @param intent a {#link PendingIntet} to be sent for each location update
746 * @throws IllegalArgumentException if provider is null or doesn't exist
747 * @throws IllegalArgumentException if intent is null
748 * @throws SecurityException if no suitable permission is present for the provider.
750 public void requestLocationUpdates(String provider,
751 long minTime, float minDistance, PendingIntent intent) {
752 if (provider == null) {
753 throw new IllegalArgumentException("provider==null");
755 if (intent == null) {
756 throw new IllegalArgumentException("intent==null");
758 _requestLocationUpdates(provider, minTime, minDistance, intent);
761 private void _requestLocationUpdates(String provider,
762 long minTime, float minDistance, PendingIntent intent) {
766 if (minDistance < 0.0f) {
771 mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent);
772 } catch (RemoteException ex) {
773 Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
778 * Removes any current registration for location updates of the current activity
779 * with the given LocationListener. Following this call, updates will no longer
780 * occur for this listener.
782 * @param listener {#link LocationListener} object that no longer needs location updates
783 * @throws IllegalArgumentException if listener is null
785 public void removeUpdates(LocationListener listener) {
786 if (listener == null) {
787 throw new IllegalArgumentException("listener==null");
790 Log.d(TAG, "removeUpdates: listener = " + listener);
793 ListenerTransport transport = mListeners.remove(listener);
794 if (transport != null) {
795 mService.removeUpdates(transport);
797 } catch (RemoteException ex) {
798 Log.e(TAG, "removeUpdates: DeadObjectException", ex);
803 * Removes any current registration for location updates of the current activity
804 * with the given PendingIntent. Following this call, updates will no longer
805 * occur for this intent.
807 * @param intent {#link PendingIntent} object that no longer needs location updates
808 * @throws IllegalArgumentException if intent is null
810 public void removeUpdates(PendingIntent intent) {
811 if (intent == null) {
812 throw new IllegalArgumentException("intent==null");
815 Log.d(TAG, "removeUpdates: intent = " + intent);
818 mService.removeUpdatesPI(intent);
819 } catch (RemoteException ex) {
820 Log.e(TAG, "removeUpdates: RemoteException", ex);
825 * Sets a proximity alert for the location given by the position
826 * (latitude, longitude) and the given radius. When the device
827 * detects that it has entered or exited the area surrounding the
828 * location, the given PendingIntent will be used to create an Intent
831 * <p> The fired Intent will have a boolean extra added with key
832 * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
833 * entering the proximity region; if false, it is exiting.
835 * <p> Due to the approximate nature of position estimation, if the
836 * device passes through the given area briefly, it is possible
837 * that no Intent will be fired. Similarly, an Intent could be
838 * fired if the device passes very close to the given area but
839 * does not actually enter it.
841 * <p> After the number of milliseconds given by the expiration
842 * parameter, the location manager will delete this proximity
843 * alert and no longer monitor it. A value of -1 indicates that
844 * there should be no expiration time.
846 * <p> In case the screen goes to sleep, checks for proximity alerts
847 * happen only once every 4 minutes. This conserves battery life by
848 * ensuring that the device isn't perpetually awake.
850 * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
851 * and {@link #GPS_PROVIDER}.
853 * @param latitude the latitude of the central point of the
855 * @param longitude the longitude of the central point of the
857 * @param radius the radius of the central point of the
858 * alert region, in meters
859 * @param expiration time for this proximity alert, in milliseconds,
860 * or -1 to indicate no expiration
861 * @param intent a PendingIntent that will be used to generate an Intent to
862 * fire when entry to or exit from the alert region is detected
864 * @throws SecurityException if no permission exists for the required
867 public void addProximityAlert(double latitude, double longitude,
868 float radius, long expiration, PendingIntent intent) {
870 Log.d(TAG, "addProximityAlert: latitude = " + latitude +
871 ", longitude = " + longitude + ", radius = " + radius +
872 ", expiration = " + expiration +
873 ", intent = " + intent);
876 mService.addProximityAlert(latitude, longitude, radius,
878 } catch (RemoteException ex) {
879 Log.e(TAG, "addProximityAlert: RemoteException", ex);
884 * Removes the proximity alert with the given PendingIntent.
886 * @param intent the PendingIntent that no longer needs to be notified of
889 public void removeProximityAlert(PendingIntent intent) {
891 Log.d(TAG, "removeProximityAlert: intent = " + intent);
894 mService.removeProximityAlert(intent);
895 } catch (RemoteException ex) {
896 Log.e(TAG, "removeProximityAlert: RemoteException", ex);
901 * Returns the current enabled/disabled status of the given provider. If the
902 * user has enabled this provider in the Settings menu, true is returned
903 * otherwise false is returned
905 * @param provider the name of the provider
906 * @return true if the provider is enabled
908 * @throws SecurityException if no suitable permission is present for the provider.
909 * @throws IllegalArgumentException if provider is null or doesn't exist
911 public boolean isProviderEnabled(String provider) {
912 if (provider == null) {
913 throw new IllegalArgumentException("provider==null");
916 return mService.isProviderEnabled(provider);
917 } catch (RemoteException ex) {
918 Log.e(TAG, "isProviderEnabled: RemoteException", ex);
924 * Returns a Location indicating the data from the last known
925 * location fix obtained from the given provider. This can be done
926 * without starting the provider. Note that this location could
927 * be out-of-date, for example if the device was turned off and
928 * moved to another location.
930 * <p> If the provider is currently disabled, null is returned.
932 * @param provider the name of the provider
933 * @return the last known location for the provider, or null
935 * @throws SecurityException if no suitable permission is present for the provider.
936 * @throws IllegalArgumentException if provider is null or doesn't exist
938 public Location getLastKnownLocation(String provider) {
939 if (provider == null) {
940 throw new IllegalArgumentException("provider==null");
943 return mService.getLastKnownLocation(provider);
944 } catch (RemoteException ex) {
945 Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
950 // Mock provider support
953 * Creates a mock location provider and adds it to the set of active providers.
955 * @param name the provider name
956 * @param requiresNetwork
957 * @param requiresSatellite
958 * @param requiresCell
959 * @param hasMonetaryCost
960 * @param supportsAltitude
961 * @param supportsSpeed
962 * @param supportsBearing
963 * @param powerRequirement
966 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
967 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
968 * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled
969 * @throws IllegalArgumentException if a provider with the given name already exists
971 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
972 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
973 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
975 mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell,
976 hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement,
978 } catch (RemoteException ex) {
979 Log.e(TAG, "addTestProvider: RemoteException", ex);
984 * Removes the mock location provider with the given name.
986 * @param provider the provider name
988 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
989 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
990 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
991 * @throws IllegalArgumentException if no provider with the given name exists
993 public void removeTestProvider(String provider) {
995 mService.removeTestProvider(provider);
996 } catch (RemoteException ex) {
997 Log.e(TAG, "removeTestProvider: RemoteException", ex);
1002 * Sets a mock location for the given provider. This location will be used in place
1003 * of any actual location from the provider.
1005 * @param provider the provider name
1006 * @param loc the mock location
1008 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1009 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1010 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1011 * @throws IllegalArgumentException if no provider with the given name exists
1013 public void setTestProviderLocation(String provider, Location loc) {
1015 mService.setTestProviderLocation(provider, loc);
1016 } catch (RemoteException ex) {
1017 Log.e(TAG, "setTestProviderLocation: RemoteException", ex);
1022 * Removes any mock location associated with the given provider.
1024 * @param provider the provider name
1026 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1027 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1028 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1029 * @throws IllegalArgumentException if no provider with the given name exists
1031 public void clearTestProviderLocation(String provider) {
1033 mService.clearTestProviderLocation(provider);
1034 } catch (RemoteException ex) {
1035 Log.e(TAG, "clearTestProviderLocation: RemoteException", ex);
1040 * Sets a mock enabled value for the given provider. This value will be used in place
1041 * of any actual value from the provider.
1043 * @param provider the provider name
1044 * @param enabled the mock enabled value
1046 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1047 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1048 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1049 * @throws IllegalArgumentException if no provider with the given name exists
1051 public void setTestProviderEnabled(String provider, boolean enabled) {
1053 mService.setTestProviderEnabled(provider, enabled);
1054 } catch (RemoteException ex) {
1055 Log.e(TAG, "setTestProviderEnabled: RemoteException", ex);
1060 * Removes any mock enabled value associated with the given provider.
1062 * @param provider the provider name
1064 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1065 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1066 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1067 * @throws IllegalArgumentException if no provider with the given name exists
1069 public void clearTestProviderEnabled(String provider) {
1071 mService.clearTestProviderEnabled(provider);
1072 } catch (RemoteException ex) {
1073 Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex);
1079 * Sets mock status values for the given provider. These values will be used in place
1080 * of any actual values from the provider.
1082 * @param provider the provider name
1083 * @param status the mock status
1084 * @param extras a Bundle containing mock extras
1085 * @param updateTime the mock update time
1087 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1088 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1089 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1090 * @throws IllegalArgumentException if no provider with the given name exists
1092 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1094 mService.setTestProviderStatus(provider, status, extras, updateTime);
1095 } catch (RemoteException ex) {
1096 Log.e(TAG, "setTestProviderStatus: RemoteException", ex);
1101 * Removes any mock status values associated with the given provider.
1103 * @param provider the provider name
1105 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1106 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1107 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1108 * @throws IllegalArgumentException if no provider with the given name exists
1110 public void clearTestProviderStatus(String provider) {
1112 mService.clearTestProviderStatus(provider);
1113 } catch (RemoteException ex) {
1114 Log.e(TAG, "clearTestProviderStatus: RemoteException", ex);
1118 // GPS-specific support
1120 // This class is used to send GPS status events to the client's main thread.
1121 private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
1123 private final GpsStatus.Listener mListener;
1124 private final GpsStatus.NmeaListener mNmeaListener;
1126 // This must not equal any of the GpsStatus event IDs
1127 private static final int NMEA_RECEIVED = 1000;
1129 private class Nmea {
1133 Nmea(long timestamp, String nmea) {
1134 mTimestamp = timestamp;
1138 private ArrayList<Nmea> mNmeaBuffer;
1140 GpsStatusListenerTransport(GpsStatus.Listener listener) {
1141 mListener = listener;
1142 mNmeaListener = null;
1145 GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
1146 mNmeaListener = listener;
1148 mNmeaBuffer = new ArrayList<Nmea>();
1151 public void onGpsStarted() {
1152 if (mListener != null) {
1153 Message msg = Message.obtain();
1154 msg.what = GpsStatus.GPS_EVENT_STARTED;
1155 mGpsHandler.sendMessage(msg);
1159 public void onGpsStopped() {
1160 if (mListener != null) {
1161 Message msg = Message.obtain();
1162 msg.what = GpsStatus.GPS_EVENT_STOPPED;
1163 mGpsHandler.sendMessage(msg);
1167 public void onFirstFix(int ttff) {
1168 if (mListener != null) {
1169 mGpsStatus.setTimeToFirstFix(ttff);
1170 Message msg = Message.obtain();
1171 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
1172 mGpsHandler.sendMessage(msg);
1176 public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
1177 float[] elevations, float[] azimuths, int ephemerisMask,
1178 int almanacMask, int usedInFixMask) {
1179 if (mListener != null) {
1180 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
1181 ephemerisMask, almanacMask, usedInFixMask);
1183 Message msg = Message.obtain();
1184 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
1185 // remove any SV status messages already in the queue
1186 mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
1187 mGpsHandler.sendMessage(msg);
1191 public void onNmeaReceived(long timestamp, String nmea) {
1192 if (mNmeaListener != null) {
1193 synchronized (mNmeaBuffer) {
1194 mNmeaBuffer.add(new Nmea(timestamp, nmea));
1196 Message msg = Message.obtain();
1197 msg.what = NMEA_RECEIVED;
1198 // remove any NMEA_RECEIVED messages already in the queue
1199 mGpsHandler.removeMessages(NMEA_RECEIVED);
1200 mGpsHandler.sendMessage(msg);
1204 private final Handler mGpsHandler = new Handler() {
1206 public void handleMessage(Message msg) {
1207 if (msg.what == NMEA_RECEIVED) {
1208 synchronized (mNmeaBuffer) {
1209 int length = mNmeaBuffer.size();
1210 for (int i = 0; i < length; i++) {
1211 Nmea nmea = mNmeaBuffer.get(i);
1212 mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
1214 mNmeaBuffer.clear();
1217 // synchronize on mGpsStatus to ensure the data is copied atomically.
1218 synchronized(mGpsStatus) {
1219 mListener.onGpsStatusChanged(msg.what);
1227 * Adds a GPS status listener.
1229 * @param listener GPS status listener object to register
1231 * @return true if the listener was successfully added
1233 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1235 public boolean addGpsStatusListener(GpsStatus.Listener listener) {
1238 if (mGpsStatusListeners.get(listener) != null) {
1239 // listener is already registered
1243 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1244 result = mService.addGpsStatusListener(transport);
1246 mGpsStatusListeners.put(listener, transport);
1248 } catch (RemoteException e) {
1249 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1257 * Removes a GPS status listener.
1259 * @param listener GPS status listener object to remove
1261 public void removeGpsStatusListener(GpsStatus.Listener listener) {
1263 GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
1264 if (transport != null) {
1265 mService.removeGpsStatusListener(transport);
1267 } catch (RemoteException e) {
1268 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
1273 * Adds an NMEA listener.
1275 * @param listener a {#link GpsStatus.NmeaListener} object to register
1277 * @return true if the listener was successfully added
1279 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1281 public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
1284 if (mNmeaListeners.get(listener) != null) {
1285 // listener is already registered
1289 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1290 result = mService.addGpsStatusListener(transport);
1292 mNmeaListeners.put(listener, transport);
1294 } catch (RemoteException e) {
1295 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1303 * Removes an NMEA listener.
1305 * @param listener a {#link GpsStatus.NmeaListener} object to remove
1307 public void removeNmeaListener(GpsStatus.NmeaListener listener) {
1309 GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
1310 if (transport != null) {
1311 mService.removeGpsStatusListener(transport);
1313 } catch (RemoteException e) {
1314 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
1319 * Retrieves information about the current status of the GPS engine.
1320 * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
1321 * callback to ensure that the data is copied atomically.
1323 * The caller may either pass in a {@link GpsStatus} object to set with the latest
1324 * status information, or pass null to create a new {@link GpsStatus} object.
1326 * @param status object containing GPS status details, or null.
1327 * @return status object containing updated GPS status.
1329 public GpsStatus getGpsStatus(GpsStatus status) {
1330 if (status == null) {
1331 status = new GpsStatus();
1333 status.setStatus(mGpsStatus);
1338 * Sends additional commands to a location provider.
1339 * Can be used to support provider specific extensions to the Location Manager API
1341 * @param provider name of the location provider.
1342 * @param command name of the command to send to the provider.
1343 * @param extras optional arguments for the command (or null).
1344 * The provider may optionally fill the extras Bundle with results from the command.
1346 * @return true if the command succeeds.
1348 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1350 return mService.sendExtraCommand(provider, command, extras);
1351 } catch (RemoteException e) {
1352 Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
1358 * Used by NetInitiatedActivity to report user response
1359 * for network initiated GPS fix requests.
1363 public boolean sendNiResponse(int notifId, int userResponse) {
1365 return mService.sendNiResponse(notifId, userResponse);
1366 } catch (RemoteException e) {
1367 Log.e(TAG, "RemoteException in sendNiResponse: ", e);