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