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