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