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