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