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