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