• 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 com.android.internal.location.ProviderProperties;
20 
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemApi;
23 import android.annotation.TestApi;
24 import android.app.PendingIntent;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.Build;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.RemoteException;
33 import android.util.Log;
34 
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 
39 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
40 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
41 
42 /**
43  * This class provides access to the system location services.  These
44  * services allow applications to obtain periodic updates of the
45  * device's geographical location, or to fire an application-specified
46  * {@link Intent} when the device enters the proximity of a given
47  * geographical location.
48  *
49  * <p>You do not
50  * instantiate this class directly; instead, retrieve it through
51  * {@link android.content.Context#getSystemService
52  * Context.getSystemService(Context.LOCATION_SERVICE)}.
53  *
54  * <p class="note">Unless noted, all Location API methods require
55  * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
56  * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.
57  * If your application only has the coarse permission then it will not have
58  * access to the GPS or passive location providers. Other providers will still
59  * return location results, but the update rate will be throttled and the exact
60  * location will be obfuscated to a coarse level of accuracy.
61  */
62 public class LocationManager {
63     private static final String TAG = "LocationManager";
64 
65     private final Context mContext;
66     private final ILocationManager mService;
67     private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport;
68     private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport;
69     private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
70             new HashMap<>();
71     private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
72             new HashMap<>();
73     private final HashMap<GnssStatusCallback, GnssStatusListenerTransport>
74             mOldGnssStatusListeners = new HashMap<>();
75     private final HashMap<GnssStatus.Callback, GnssStatusListenerTransport> mGnssStatusListeners =
76             new HashMap<>();
77     private final HashMap<GnssNmeaListener, GnssStatusListenerTransport> mOldGnssNmeaListeners =
78             new HashMap<>();
79     private final HashMap<OnNmeaMessageListener, GnssStatusListenerTransport> mGnssNmeaListeners =
80             new HashMap<>();
81     private final HashMap<GnssNavigationMessageEvent.Callback, GnssNavigationMessage.Callback>
82             mNavigationMessageBridge = new HashMap<>();
83     private GnssStatus mGnssStatus;
84     private int mTimeToFirstFix;
85 
86     /**
87      * Name of the network location provider.
88      * <p>This provider determines location based on
89      * availability of cell tower and WiFi access points. Results are retrieved
90      * by means of a network lookup.
91      */
92     public static final String NETWORK_PROVIDER = "network";
93 
94     /**
95      * Name of the GPS location provider.
96      *
97      * <p>This provider determines location using
98      * satellites. Depending on conditions, this provider may take a while to return
99      * a location fix. Requires the permission
100      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
101      *
102      * <p> The extras Bundle for the GPS location provider can contain the
103      * following key/value pairs:
104      * <ul>
105      * <li> satellites - the number of satellites used to derive the fix
106      * </ul>
107      */
108     public static final String GPS_PROVIDER = "gps";
109 
110     /**
111      * A special location provider for receiving locations without actually initiating
112      * a location fix.
113      *
114      * <p>This provider can be used to passively receive location updates
115      * when other applications or services request them without actually requesting
116      * the locations yourself.  This provider will return locations generated by other
117      * providers.  You can query the {@link Location#getProvider()} method to determine
118      * the origin of the location update. Requires the permission
119      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is
120      * not enabled this provider might only return coarse fixes.
121      */
122     public static final String PASSIVE_PROVIDER = "passive";
123 
124     /**
125      * Name of the Fused location provider.
126      *
127      * <p>This provider combines inputs for all possible location sources
128      * to provide the best possible Location fix. It is implicitly
129      * used for all API's that involve the {@link LocationRequest}
130      * object.
131      *
132      * @hide
133      */
134     public static final String FUSED_PROVIDER = "fused";
135 
136     /**
137      * Key used for the Bundle extra holding a boolean indicating whether
138      * a proximity alert is entering (true) or exiting (false)..
139      */
140     public static final String KEY_PROXIMITY_ENTERING = "entering";
141 
142     /**
143      * Key used for a Bundle extra holding an Integer status value
144      * when a status change is broadcast using a PendingIntent.
145      */
146     public static final String KEY_STATUS_CHANGED = "status";
147 
148     /**
149      * Key used for a Bundle extra holding an Boolean status value
150      * when a provider enabled/disabled event is broadcast using a PendingIntent.
151      */
152     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
153 
154     /**
155      * Key used for a Bundle extra holding a Location value
156      * when a location change is broadcast using a PendingIntent.
157      */
158     public static final String KEY_LOCATION_CHANGED = "location";
159 
160     /**
161      * Broadcast intent action indicating that the GPS has either been
162      * enabled or disabled. An intent extra provides this state as a boolean,
163      * where {@code true} means enabled.
164      * @see #EXTRA_GPS_ENABLED
165      *
166      * @hide
167      */
168     public static final String GPS_ENABLED_CHANGE_ACTION =
169         "android.location.GPS_ENABLED_CHANGE";
170 
171     /**
172      * Broadcast intent action when the configured location providers
173      * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
174      * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
175      * instead.
176      */
177     public static final String PROVIDERS_CHANGED_ACTION =
178         "android.location.PROVIDERS_CHANGED";
179 
180     /**
181      * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
182      * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
183      * If you're interacting with {@link #isProviderEnabled(String)}, use
184      * {@link #PROVIDERS_CHANGED_ACTION} instead.
185      *
186      * In the future, there may be mode changes that do not result in
187      * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
188      */
189     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
190 
191     /**
192      * Broadcast intent action indicating that the GPS has either started or
193      * stopped receiving GPS fixes. An intent extra provides this state as a
194      * boolean, where {@code true} means that the GPS is actively receiving fixes.
195      * @see #EXTRA_GPS_ENABLED
196      *
197      * @hide
198      */
199     public static final String GPS_FIX_CHANGE_ACTION =
200         "android.location.GPS_FIX_CHANGE";
201 
202     /**
203      * The lookup key for a boolean that indicates whether GPS is enabled or
204      * disabled. {@code true} means GPS is enabled. Retrieve it with
205      * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
206      *
207      * @hide
208      */
209     public static final String EXTRA_GPS_ENABLED = "enabled";
210 
211     /**
212      * Broadcast intent action indicating that a high power location requests
213      * has either started or stopped being active.  The current state of
214      * active location requests should be read from AppOpsManager using
215      * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
216      *
217      * @hide
218      */
219     public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
220         "android.location.HIGH_POWER_REQUEST_CHANGE";
221 
222     // Map from LocationListeners to their associated ListenerTransport objects
223     private HashMap<LocationListener,ListenerTransport> mListeners =
224         new HashMap<LocationListener,ListenerTransport>();
225 
226     private class ListenerTransport extends ILocationListener.Stub {
227         private static final int TYPE_LOCATION_CHANGED = 1;
228         private static final int TYPE_STATUS_CHANGED = 2;
229         private static final int TYPE_PROVIDER_ENABLED = 3;
230         private static final int TYPE_PROVIDER_DISABLED = 4;
231 
232         private LocationListener mListener;
233         private final Handler mListenerHandler;
234 
ListenerTransport(LocationListener listener, Looper looper)235         ListenerTransport(LocationListener listener, Looper looper) {
236             mListener = listener;
237 
238             if (looper == null) {
239                 mListenerHandler = new Handler() {
240                     @Override
241                     public void handleMessage(Message msg) {
242                         _handleMessage(msg);
243                     }
244                 };
245             } else {
246                 mListenerHandler = new Handler(looper) {
247                     @Override
248                     public void handleMessage(Message msg) {
249                         _handleMessage(msg);
250                     }
251                 };
252             }
253         }
254 
255         @Override
onLocationChanged(Location location)256         public void onLocationChanged(Location location) {
257             Message msg = Message.obtain();
258             msg.what = TYPE_LOCATION_CHANGED;
259             msg.obj = location;
260             mListenerHandler.sendMessage(msg);
261         }
262 
263         @Override
onStatusChanged(String provider, int status, Bundle extras)264         public void onStatusChanged(String provider, int status, Bundle extras) {
265             Message msg = Message.obtain();
266             msg.what = TYPE_STATUS_CHANGED;
267             Bundle b = new Bundle();
268             b.putString("provider", provider);
269             b.putInt("status", status);
270             if (extras != null) {
271                 b.putBundle("extras", extras);
272             }
273             msg.obj = b;
274             mListenerHandler.sendMessage(msg);
275         }
276 
277         @Override
onProviderEnabled(String provider)278         public void onProviderEnabled(String provider) {
279             Message msg = Message.obtain();
280             msg.what = TYPE_PROVIDER_ENABLED;
281             msg.obj = provider;
282             mListenerHandler.sendMessage(msg);
283         }
284 
285         @Override
onProviderDisabled(String provider)286         public void onProviderDisabled(String provider) {
287             Message msg = Message.obtain();
288             msg.what = TYPE_PROVIDER_DISABLED;
289             msg.obj = provider;
290             mListenerHandler.sendMessage(msg);
291         }
292 
_handleMessage(Message msg)293         private void _handleMessage(Message msg) {
294             switch (msg.what) {
295                 case TYPE_LOCATION_CHANGED:
296                     Location location = new Location((Location) msg.obj);
297                     mListener.onLocationChanged(location);
298                     break;
299                 case TYPE_STATUS_CHANGED:
300                     Bundle b = (Bundle) msg.obj;
301                     String provider = b.getString("provider");
302                     int status = b.getInt("status");
303                     Bundle extras = b.getBundle("extras");
304                     mListener.onStatusChanged(provider, status, extras);
305                     break;
306                 case TYPE_PROVIDER_ENABLED:
307                     mListener.onProviderEnabled((String) msg.obj);
308                     break;
309                 case TYPE_PROVIDER_DISABLED:
310                     mListener.onProviderDisabled((String) msg.obj);
311                     break;
312             }
313             try {
314                 mService.locationCallbackFinished(this);
315             } catch (RemoteException e) {
316                 throw e.rethrowFromSystemServer();
317             }
318         }
319     }
320 
321     /**
322      * @hide - hide this constructor because it has a parameter
323      * of type ILocationManager, which is a system private class. The
324      * right way to create an instance of this class is using the
325      * factory Context.getSystemService.
326      */
LocationManager(Context context, ILocationManager service)327     public LocationManager(Context context, ILocationManager service) {
328         mService = service;
329         mContext = context;
330         mGnssMeasurementCallbackTransport = new GnssMeasurementCallbackTransport(mContext, mService);
331         mGnssNavigationMessageCallbackTransport =
332                 new GnssNavigationMessageCallbackTransport(mContext, mService);
333     }
334 
createProvider(String name, ProviderProperties properties)335     private LocationProvider createProvider(String name, ProviderProperties properties) {
336         return new LocationProvider(name, properties);
337     }
338 
339     /**
340      * Returns a list of the names of all known location providers.
341      * <p>All providers are returned, including ones that are not permitted to
342      * be accessed by the calling activity or are currently disabled.
343      *
344      * @return list of Strings containing names of the provider
345      */
getAllProviders()346     public List<String> getAllProviders() {
347         try {
348             return mService.getAllProviders();
349         } catch (RemoteException e) {
350             throw e.rethrowFromSystemServer();
351         }
352     }
353 
354     /**
355      * Returns a list of the names of location providers.
356      *
357      * @param enabledOnly if true then only the providers which are currently
358      * enabled are returned.
359      * @return list of Strings containing names of the providers
360      */
getProviders(boolean enabledOnly)361     public List<String> getProviders(boolean enabledOnly) {
362         try {
363             return mService.getProviders(null, enabledOnly);
364         } catch (RemoteException e) {
365             throw e.rethrowFromSystemServer();
366         }
367     }
368 
369     /**
370      * Returns the information associated with the location provider of the
371      * given name, or null if no provider exists by that name.
372      *
373      * @param name the provider name
374      * @return a LocationProvider, or null
375      *
376      * @throws IllegalArgumentException if name is null or does not exist
377      * @throws SecurityException if the caller is not permitted to access the
378      * given provider.
379      */
getProvider(String name)380     public LocationProvider getProvider(String name) {
381         checkProvider(name);
382         try {
383             ProviderProperties properties = mService.getProviderProperties(name);
384             if (properties == null) {
385                 return null;
386             }
387             return createProvider(name, properties);
388         } catch (RemoteException e) {
389             throw e.rethrowFromSystemServer();
390         }
391     }
392 
393     /**
394      * Returns a list of the names of LocationProviders that satisfy the given
395      * criteria, or null if none do.  Only providers that are permitted to be
396      * accessed by the calling activity will be returned.
397      *
398      * @param criteria the criteria that the returned providers must match
399      * @param enabledOnly if true then only the providers which are currently
400      * enabled are returned.
401      * @return list of Strings containing names of the providers
402      */
getProviders(Criteria criteria, boolean enabledOnly)403     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
404         checkCriteria(criteria);
405         try {
406             return mService.getProviders(criteria, enabledOnly);
407         } catch (RemoteException e) {
408             throw e.rethrowFromSystemServer();
409         }
410     }
411 
412     /**
413      * Returns the name of the provider that best meets the given criteria. Only providers
414      * that are permitted to be accessed by the calling activity will be
415      * returned.  If several providers meet the criteria, the one with the best
416      * accuracy is returned.  If no provider meets the criteria,
417      * the criteria are loosened in the following sequence:
418      *
419      * <ul>
420      * <li> power requirement
421      * <li> accuracy
422      * <li> bearing
423      * <li> speed
424      * <li> altitude
425      * </ul>
426      *
427      * <p> Note that the requirement on monetary cost is not removed
428      * in this process.
429      *
430      * @param criteria the criteria that need to be matched
431      * @param enabledOnly if true then only a provider that is currently enabled is returned
432      * @return name of the provider that best matches the requirements
433      */
getBestProvider(Criteria criteria, boolean enabledOnly)434     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
435         checkCriteria(criteria);
436         try {
437             return mService.getBestProvider(criteria, enabledOnly);
438         } catch (RemoteException e) {
439             throw e.rethrowFromSystemServer();
440         }
441     }
442 
443     /**
444      * Register for location updates using the named provider, and a
445      * pending intent.
446      *
447      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
448      * for more detail on how to use this method.
449      *
450      * @param provider the name of the provider with which to register
451      * @param minTime minimum time interval between location updates, in milliseconds
452      * @param minDistance minimum distance between location updates, in meters
453      * @param listener a {@link LocationListener} whose
454      * {@link LocationListener#onLocationChanged} method will be called for
455      * each location update
456      *
457      * @throws IllegalArgumentException if provider is null or doesn't exist
458      * on this device
459      * @throws IllegalArgumentException if listener is null
460      * @throws RuntimeException if the calling thread has no Looper
461      * @throws SecurityException if no suitable permission is present
462      */
463     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)464     public void requestLocationUpdates(String provider, long minTime, float minDistance,
465             LocationListener listener) {
466         checkProvider(provider);
467         checkListener(listener);
468 
469         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
470                 provider, minTime, minDistance, false);
471         requestLocationUpdates(request, listener, null, null);
472     }
473 
474     /**
475      * Register for location updates using the named provider, and a callback on
476      * the specified looper thread.
477      *
478      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
479      * for more detail on how to use this method.
480      *
481      * @param provider the name of the provider with which to register
482      * @param minTime minimum time interval between location updates, in milliseconds
483      * @param minDistance minimum distance between location updates, in meters
484      * @param listener a {@link LocationListener} whose
485      * {@link LocationListener#onLocationChanged} method will be called for
486      * each location update
487      * @param looper a Looper object whose message queue will be used to
488      * implement the callback mechanism, or null to make callbacks on the calling
489      * thread
490      *
491      * @throws IllegalArgumentException if provider is null or doesn't exist
492      * @throws IllegalArgumentException if listener is null
493      * @throws SecurityException if no suitable permission is present
494      */
495     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener, Looper looper)496     public void requestLocationUpdates(String provider, long minTime, float minDistance,
497             LocationListener listener, Looper looper) {
498         checkProvider(provider);
499         checkListener(listener);
500 
501         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
502                 provider, minTime, minDistance, false);
503         requestLocationUpdates(request, listener, looper, null);
504     }
505 
506     /**
507      * Register for location updates using a Criteria, and a callback
508      * on the specified looper thread.
509      *
510      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
511      * for more detail on how to use this method.
512      *
513      * @param minTime minimum time interval between location updates, in milliseconds
514      * @param minDistance minimum distance between location updates, in meters
515      * @param criteria contains parameters for the location manager to choose the
516      * appropriate provider and parameters to compute the location
517      * @param listener a {@link LocationListener} whose
518      * {@link LocationListener#onLocationChanged} method will be called for
519      * each location update
520      * @param looper a Looper object whose message queue will be used to
521      * implement the callback mechanism, or null to make callbacks on the calling
522      * thread
523      *
524      * @throws IllegalArgumentException if criteria is null
525      * @throws IllegalArgumentException if listener is null
526      * @throws SecurityException if no suitable permission is present
527      */
528     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(long minTime, float minDistance, Criteria criteria, LocationListener listener, Looper looper)529     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
530             LocationListener listener, Looper looper) {
531         checkCriteria(criteria);
532         checkListener(listener);
533 
534         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
535                 criteria, minTime, minDistance, false);
536         requestLocationUpdates(request, listener, looper, null);
537     }
538 
539     /**
540      * Register for location updates using the named provider, and a
541      * pending intent.
542      *
543      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
544      * for more detail on how to use this method.
545      *
546      * @param provider the name of the provider with which to register
547      * @param minTime minimum time interval between location updates, in milliseconds
548      * @param minDistance minimum distance between location updates, in meters
549      * @param intent a {@link PendingIntent} to be sent for each location update
550      *
551      * @throws IllegalArgumentException if provider is null or doesn't exist
552      * on this device
553      * @throws IllegalArgumentException if intent is null
554      * @throws SecurityException if no suitable permission is present
555      */
556     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(String provider, long minTime, float minDistance, PendingIntent intent)557     public void requestLocationUpdates(String provider, long minTime, float minDistance,
558             PendingIntent intent) {
559         checkProvider(provider);
560         checkPendingIntent(intent);
561 
562         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
563                 provider, minTime, minDistance, false);
564         requestLocationUpdates(request, null, null, intent);
565     }
566 
567     /**
568      * Register for location updates using a Criteria and pending intent.
569      *
570      * <p>The <code>requestLocationUpdates()</code> and
571      * <code>requestSingleUpdate()</code> register the current activity to be
572      * updated periodically by the named provider, or by the provider matching
573      * the specified {@link Criteria}, with location and 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> Location updates are received either by {@link LocationListener}
580      * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.
581      *
582      * <p> If the caller supplied a pending intent, then location updates
583      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
584      * {@link android.location.Location} value.
585      *
586      * <p> The location update interval can be controlled using the minTime parameter.
587      * The elapsed time between location updates will never be less than
588      * minTime, although it can be more depending on the Location Provider
589      * implementation and the update interval requested by other applications.
590      *
591      * <p> Choosing a sensible value for minTime is important to conserve
592      * battery life. Each location update requires power from
593      * GPS, WIFI, Cell and other radios. Select a minTime value as high as
594      * possible while still providing a reasonable user experience.
595      * If your application is not in the foreground and showing
596      * location to the user then your application should avoid using an active
597      * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
598      * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
599      * or greater. If your application is in the foreground and showing
600      * location to the user then it is appropriate to select a faster
601      * update interval.
602      *
603      * <p> The minDistance parameter can also be used to control the
604      * frequency of location updates. If it is greater than 0 then the
605      * location provider will only send your application an update when
606      * the location has changed by at least minDistance meters, AND
607      * at least minTime milliseconds have passed. However it is more
608      * difficult for location providers to save power using the minDistance
609      * parameter, so minTime should be the primary tool to conserving battery
610      * life.
611      *
612      * <p> If your application wants to passively observe location
613      * updates triggered by other applications, but not consume
614      * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
615      * This provider does not actively turn on or modify active location
616      * providers, so you do not need to be as careful about minTime and
617      * minDistance. However if your application performs heavy work
618      * on a location update (such as network activity) then you should
619      * select non-zero values for minTime and/or minDistance to rate-limit
620      * your update frequency in the case another application enables a
621      * location provider with extremely fast updates.
622      *
623      * <p>In case the provider is disabled by the user, updates will stop,
624      * and a provider availability update will be sent.
625      * As soon as the provider is enabled again,
626      * location updates will immediately resume and a provider availability
627      * update sent. Providers can also send status updates, at any time,
628      * with extra's specific to the provider. If a callback was supplied
629      * then status and availability updates are via
630      * {@link LocationListener#onProviderDisabled},
631      * {@link LocationListener#onProviderEnabled} or
632      * {@link LocationListener#onStatusChanged}. Alternately, if a
633      * pending intent was supplied then status and availability updates
634      * are broadcast intents with extra keys of
635      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.
636      *
637      * <p> If a {@link LocationListener} is used but with no Looper specified
638      * then the calling thread must already
639      * be a {@link android.os.Looper} thread such as the main thread of the
640      * calling Activity. If a Looper is specified with a {@link LocationListener}
641      * then callbacks are made on the supplied Looper thread.
642      *
643      * <p class="note"> Prior to Jellybean, the minTime parameter was
644      * only a hint, and some location provider implementations ignored it.
645      * From Jellybean and onwards it is mandatory for Android compatible
646      * devices to observe both the minTime and minDistance parameters.
647      *
648      * @param minTime minimum time interval between location updates, in milliseconds
649      * @param minDistance minimum distance between location updates, in meters
650      * @param criteria contains parameters for the location manager to choose the
651      * appropriate provider and parameters to compute the location
652      * @param intent a {@link PendingIntent} to be sent for each location update
653      *
654      * @throws IllegalArgumentException if criteria is null
655      * @throws IllegalArgumentException if intent is null
656      * @throws SecurityException if no suitable permission is present
657      */
658     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent)659     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
660             PendingIntent intent) {
661         checkCriteria(criteria);
662         checkPendingIntent(intent);
663 
664         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
665                 criteria, minTime, minDistance, false);
666         requestLocationUpdates(request, null, null, intent);
667     }
668 
669     /**
670      * Register for a single location update using the named provider and
671      * a callback.
672      *
673      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
674      * for more detail on how to use this method.
675      *
676      * @param provider the name of the provider with which to register
677      * @param listener a {@link LocationListener} whose
678      * {@link LocationListener#onLocationChanged} method will be called when
679      * the location update is available
680      * @param looper a Looper object whose message queue will be used to
681      * implement the callback mechanism, or null to make callbacks on the calling
682      * thread
683      *
684      * @throws IllegalArgumentException if provider is null or doesn't exist
685      * @throws IllegalArgumentException if listener is null
686      * @throws SecurityException if no suitable permission is present
687      */
688     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(String provider, LocationListener listener, Looper looper)689     public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
690         checkProvider(provider);
691         checkListener(listener);
692 
693         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
694                 provider, 0, 0, true);
695         requestLocationUpdates(request, listener, looper, null);
696     }
697 
698     /**
699      * Register for a single location update using a Criteria and
700      * a callback.
701      *
702      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
703      * for more detail on how to use this method.
704      *
705      * @param criteria contains parameters for the location manager to choose the
706      * appropriate provider and parameters to compute the location
707      * @param listener a {@link LocationListener} whose
708      * {@link LocationListener#onLocationChanged} method will be called when
709      * the location update is available
710      * @param looper a Looper object whose message queue will be used to
711      * implement the callback mechanism, or null to make callbacks on the calling
712      * thread
713      *
714      * @throws IllegalArgumentException if criteria is null
715      * @throws IllegalArgumentException if listener is null
716      * @throws SecurityException if no suitable permission is present
717      */
718     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper)719     public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
720         checkCriteria(criteria);
721         checkListener(listener);
722 
723         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
724                 criteria, 0, 0, true);
725         requestLocationUpdates(request, listener, looper, null);
726     }
727 
728     /**
729      * Register for a single location update using a named provider and pending intent.
730      *
731      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
732      * for more detail on how to use this method.
733      *
734      * @param provider the name of the provider with which to register
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      */
741     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(String provider, PendingIntent intent)742     public void requestSingleUpdate(String provider, PendingIntent intent) {
743         checkProvider(provider);
744         checkPendingIntent(intent);
745 
746         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
747                 provider, 0, 0, true);
748         requestLocationUpdates(request, null, null, intent);
749     }
750 
751     /**
752      * Register for a single location update using a Criteria and pending intent.
753      *
754      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
755      * for more detail on how to use this method.
756      *
757      * @param criteria contains parameters for the location manager to choose the
758      * appropriate provider and parameters to compute the location
759      * @param intent a {@link PendingIntent} to be sent for the location update
760      *
761      * @throws IllegalArgumentException if provider is null or doesn't exist
762      * @throws IllegalArgumentException if intent is null
763      * @throws SecurityException if no suitable permission is present
764      */
765     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(Criteria criteria, PendingIntent intent)766     public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
767         checkCriteria(criteria);
768         checkPendingIntent(intent);
769 
770         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
771                 criteria, 0, 0, true);
772         requestLocationUpdates(request, null, null, intent);
773     }
774 
775     /**
776      * Register for fused location updates using a LocationRequest and callback.
777      *
778      * <p>Upon a location update, the system delivers the new {@link Location} to the
779      * provided {@link LocationListener}, by calling its {@link
780      * LocationListener#onLocationChanged} method.</p>
781      *
782      * <p>The system will automatically select and enable the best providers
783      * to compute a location for your application. It may use only passive
784      * locations, or just a single location source, or it may fuse together
785      * multiple location sources in order to produce the best possible
786      * result, depending on the quality of service requested in the
787      * {@link LocationRequest}.
788      *
789      * <p>LocationRequest can be null, in which case the system will choose
790      * default, low power parameters for location updates. You will occasionally
791      * receive location updates as available, without a major power impact on the
792      * system. If your application just needs an occasional location update
793      * without any strict demands, then pass a null LocationRequest.
794      *
795      * <p>Only one LocationRequest can be registered for each unique callback
796      * or pending intent. So a subsequent request with the same callback or
797      * pending intent will over-write the previous LocationRequest.
798      *
799      * <p> If a pending intent is supplied then location updates
800      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
801      * {@link android.location.Location} value. If a callback is supplied
802      * then location updates are made using the
803      * {@link LocationListener#onLocationChanged} callback, on the specified
804      * Looper thread. If a {@link LocationListener} is used
805      * but with a null Looper then the calling thread must already
806      * be a {@link android.os.Looper} thread (such as the main thread) and
807      * callbacks will occur on this thread.
808      *
809      * <p> Provider status updates and availability updates are deprecated
810      * because the system is performing provider fusion on the applications
811      * behalf. So {@link LocationListener#onProviderDisabled},
812      * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}
813      * will not be called, and intents with extra keys of
814      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not
815      * be received.
816      *
817      * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}.
818      *
819      * @param request quality of service required, null for default low power
820      * @param listener a {@link LocationListener} whose
821      * {@link LocationListener#onLocationChanged} method will be called when
822      * the location update is available
823      * @param looper a Looper object whose message queue will be used to
824      * implement the callback mechanism, or null to make callbacks on the calling
825      * thread
826      *
827      * @throws IllegalArgumentException if listener is null
828      * @throws SecurityException if no suitable permission is present
829      *
830      * @hide
831      */
832     @SystemApi
requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper)833     public void requestLocationUpdates(LocationRequest request, LocationListener listener,
834             Looper looper) {
835         checkListener(listener);
836         requestLocationUpdates(request, listener, looper, null);
837     }
838 
839 
840     /**
841      * Register for fused location updates using a LocationRequest and a pending intent.
842      *
843      * <p>Upon a location update, the system delivers the new {@link Location} with your provided
844      * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
845      * in the intent's extras.</p>
846      *
847      * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
848      *
849      * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
850      * for more detail.
851      *
852      * @param request quality of service required, null for default low power
853      * @param intent a {@link PendingIntent} to be sent for the location update
854      *
855      * @throws IllegalArgumentException if intent is null
856      * @throws SecurityException if no suitable permission is present
857      *
858      * @hide
859      */
860     @SystemApi
requestLocationUpdates(LocationRequest request, PendingIntent intent)861     public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
862         checkPendingIntent(intent);
863         requestLocationUpdates(request, null, null, intent);
864     }
865 
wrapListener(LocationListener listener, Looper looper)866     private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
867         if (listener == null) return null;
868         synchronized (mListeners) {
869             ListenerTransport transport = mListeners.get(listener);
870             if (transport == null) {
871                 transport = new ListenerTransport(listener, looper);
872             }
873             mListeners.put(listener, transport);
874             return transport;
875         }
876     }
877 
requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper, PendingIntent intent)878     private void requestLocationUpdates(LocationRequest request, LocationListener listener,
879             Looper looper, PendingIntent intent) {
880 
881         String packageName = mContext.getPackageName();
882 
883         // wrap the listener class
884         ListenerTransport transport = wrapListener(listener, looper);
885 
886         try {
887             mService.requestLocationUpdates(request, transport, intent, packageName);
888        } catch (RemoteException e) {
889            throw e.rethrowFromSystemServer();
890        }
891     }
892 
893     /**
894      * Removes all location updates for the specified LocationListener.
895      *
896      * <p>Following this call, updates will no longer
897      * occur for this listener.
898      *
899      * @param listener listener object that no longer needs location updates
900      * @throws IllegalArgumentException if listener is null
901      */
removeUpdates(LocationListener listener)902     public void removeUpdates(LocationListener listener) {
903         checkListener(listener);
904         String packageName = mContext.getPackageName();
905 
906         ListenerTransport transport;
907         synchronized (mListeners) {
908             transport = mListeners.remove(listener);
909         }
910         if (transport == null) return;
911 
912         try {
913             mService.removeUpdates(transport, null, packageName);
914         } catch (RemoteException e) {
915             throw e.rethrowFromSystemServer();
916         }
917     }
918 
919     /**
920      * Removes all location updates for the specified pending intent.
921      *
922      * <p>Following this call, updates will no longer for this pending intent.
923      *
924      * @param intent pending intent object that no longer needs location updates
925      * @throws IllegalArgumentException if intent is null
926      */
removeUpdates(PendingIntent intent)927     public void removeUpdates(PendingIntent intent) {
928         checkPendingIntent(intent);
929         String packageName = mContext.getPackageName();
930 
931         try {
932             mService.removeUpdates(null, intent, packageName);
933         } catch (RemoteException e) {
934             throw e.rethrowFromSystemServer();
935         }
936     }
937 
938     /**
939      * Set a proximity alert for the location given by the position
940      * (latitude, longitude) and the given radius.
941      *
942      * <p> When the device
943      * detects that it has entered or exited the area surrounding the
944      * location, the given PendingIntent will be used to create an Intent
945      * to be fired.
946      *
947      * <p> The fired Intent will have a boolean extra added with key
948      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
949      * entering the proximity region; if false, it is exiting.
950      *
951      * <p> Due to the approximate nature of position estimation, if the
952      * device passes through the given area briefly, it is possible
953      * that no Intent will be fired.  Similarly, an Intent could be
954      * fired if the device passes very close to the given area but
955      * does not actually enter it.
956      *
957      * <p> After the number of milliseconds given by the expiration
958      * parameter, the location manager will delete this proximity
959      * alert and no longer monitor it.  A value of -1 indicates that
960      * there should be no expiration time.
961      *
962      * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
963      * and {@link #GPS_PROVIDER}.
964      *
965      * <p>Before API version 17, this method could be used with
966      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
967      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
968      * From API version 17 and onwards, this method requires
969      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
970      *
971      * @param latitude the latitude of the central point of the
972      * alert region
973      * @param longitude the longitude of the central point of the
974      * alert region
975      * @param radius the radius of the central point of the
976      * alert region, in meters
977      * @param expiration time for this proximity alert, in milliseconds,
978      * or -1 to indicate no expiration
979      * @param intent a PendingIntent that will be used to generate an Intent to
980      * fire when entry to or exit from the alert region is detected
981      *
982      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
983      * permission is not present
984      */
985     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)986     public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
987             PendingIntent intent) {
988         checkPendingIntent(intent);
989         if (expiration < 0) expiration = Long.MAX_VALUE;
990 
991         Geofence fence = Geofence.createCircle(latitude, longitude, radius);
992         LocationRequest request = new LocationRequest().setExpireIn(expiration);
993         try {
994             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
995         } catch (RemoteException e) {
996             throw e.rethrowFromSystemServer();
997         }
998     }
999 
1000     /**
1001      * Add a geofence with the specified LocationRequest quality of service.
1002      *
1003      * <p> When the device
1004      * detects that it has entered or exited the area surrounding the
1005      * location, the given PendingIntent will be used to create an Intent
1006      * to be fired.
1007      *
1008      * <p> The fired Intent will have a boolean extra added with key
1009      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
1010      * entering the proximity region; if false, it is exiting.
1011      *
1012      * <p> The geofence engine fuses results from all location providers to
1013      * provide the best balance between accuracy and power. Applications
1014      * can choose the quality of service required using the
1015      * {@link LocationRequest} object. If it is null then a default,
1016      * low power geo-fencing implementation is used. It is possible to cross
1017      * a geo-fence without notification, but the system will do its best
1018      * to detect, using {@link LocationRequest} as a hint to trade-off
1019      * accuracy and power.
1020      *
1021      * <p> The power required by the geofence engine can depend on many factors,
1022      * such as quality and interval requested in {@link LocationRequest},
1023      * distance to nearest geofence and current device velocity.
1024      *
1025      * @param request quality of service required, null for default low power
1026      * @param fence a geographical description of the geofence area
1027      * @param intent pending intent to receive geofence updates
1028      *
1029      * @throws IllegalArgumentException if fence is null
1030      * @throws IllegalArgumentException if intent is null
1031      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1032      * permission is not present
1033      *
1034      * @hide
1035      */
1036     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
addGeofence(LocationRequest request, Geofence fence, PendingIntent intent)1037     public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
1038         checkPendingIntent(intent);
1039         checkGeofence(fence);
1040 
1041         try {
1042             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
1043         } catch (RemoteException e) {
1044             throw e.rethrowFromSystemServer();
1045         }
1046     }
1047 
1048     /**
1049      * Removes the proximity alert with the given PendingIntent.
1050      *
1051      * <p>Before API version 17, this method could be used with
1052      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
1053      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
1054      * From API version 17 and onwards, this method requires
1055      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
1056      *
1057      * @param intent the PendingIntent that no longer needs to be notified of
1058      * proximity alerts
1059      *
1060      * @throws IllegalArgumentException if intent is null
1061      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1062      * permission is not present
1063      */
removeProximityAlert(PendingIntent intent)1064     public void removeProximityAlert(PendingIntent intent) {
1065         checkPendingIntent(intent);
1066         String packageName = mContext.getPackageName();
1067 
1068         try {
1069             mService.removeGeofence(null, intent, packageName);
1070         } catch (RemoteException e) {
1071             throw e.rethrowFromSystemServer();
1072         }
1073     }
1074 
1075     /**
1076      * Remove a single geofence.
1077      *
1078      * <p>This removes only the specified geofence associated with the
1079      * specified pending intent. All other geofences remain unchanged.
1080      *
1081      * @param fence a geofence previously passed to {@link #addGeofence}
1082      * @param intent a pending intent previously passed to {@link #addGeofence}
1083      *
1084      * @throws IllegalArgumentException if fence is null
1085      * @throws IllegalArgumentException if intent is null
1086      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1087      * permission is not present
1088      *
1089      * @hide
1090      */
removeGeofence(Geofence fence, PendingIntent intent)1091     public void removeGeofence(Geofence fence, PendingIntent intent) {
1092         checkPendingIntent(intent);
1093         checkGeofence(fence);
1094         String packageName = mContext.getPackageName();
1095 
1096         try {
1097             mService.removeGeofence(fence, intent, packageName);
1098         } catch (RemoteException e) {
1099             throw e.rethrowFromSystemServer();
1100         }
1101     }
1102 
1103     /**
1104      * Remove all geofences registered to the specified pending intent.
1105      *
1106      * @param intent a pending intent previously passed to {@link #addGeofence}
1107      *
1108      * @throws IllegalArgumentException if intent is null
1109      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1110      * permission is not present
1111      *
1112      * @hide
1113      */
removeAllGeofences(PendingIntent intent)1114     public void removeAllGeofences(PendingIntent intent) {
1115         checkPendingIntent(intent);
1116         String packageName = mContext.getPackageName();
1117 
1118         try {
1119             mService.removeGeofence(null, intent, packageName);
1120         } catch (RemoteException e) {
1121             throw e.rethrowFromSystemServer();
1122         }
1123     }
1124 
1125     /**
1126      * Returns the current enabled/disabled status of the given provider.
1127      *
1128      * <p>If the user has enabled this provider in the Settings menu, true
1129      * is returned otherwise false is returned
1130      *
1131      * <p>Callers should instead use
1132      * {@link android.provider.Settings.Secure#LOCATION_MODE}
1133      * unless they depend on provider-specific APIs such as
1134      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
1135      *
1136      * <p>
1137      * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
1138      * method would throw {@link SecurityException} if the location permissions
1139      * were not sufficient to use the specified provider.
1140      *
1141      * @param provider the name of the provider
1142      * @return true if the provider exists and is enabled
1143      *
1144      * @throws IllegalArgumentException if provider is null
1145      */
isProviderEnabled(String provider)1146     public boolean isProviderEnabled(String provider) {
1147         checkProvider(provider);
1148 
1149         try {
1150             return mService.isProviderEnabled(provider);
1151         } catch (RemoteException e) {
1152             throw e.rethrowFromSystemServer();
1153         }
1154     }
1155 
1156     /**
1157      * Get the last known location.
1158      *
1159      * <p>This location could be very old so use
1160      * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can
1161      * also return null if no previous location is available.
1162      *
1163      * <p>Always returns immediately.
1164      *
1165      * @return The last known location, or null if not available
1166      * @throws SecurityException if no suitable permission is present
1167      *
1168      * @hide
1169      */
getLastLocation()1170     public Location getLastLocation() {
1171         String packageName = mContext.getPackageName();
1172 
1173         try {
1174             return mService.getLastLocation(null, packageName);
1175         } catch (RemoteException e) {
1176             throw e.rethrowFromSystemServer();
1177         }
1178     }
1179 
1180     /**
1181      * Returns a Location indicating the data from the last known
1182      * location fix obtained from the given provider.
1183      *
1184      * <p> This can be done
1185      * without starting the provider.  Note that this location could
1186      * be out-of-date, for example if the device was turned off and
1187      * moved to another location.
1188      *
1189      * <p> If the provider is currently disabled, null is returned.
1190      *
1191      * @param provider the name of the provider
1192      * @return the last known location for the provider, or null
1193      *
1194      * @throws SecurityException if no suitable permission is present
1195      * @throws IllegalArgumentException if provider is null or doesn't exist
1196      */
1197     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
getLastKnownLocation(String provider)1198     public Location getLastKnownLocation(String provider) {
1199         checkProvider(provider);
1200         String packageName = mContext.getPackageName();
1201         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
1202                 provider, 0, 0, true);
1203 
1204         try {
1205             return mService.getLastLocation(request, packageName);
1206         } catch (RemoteException e) {
1207             throw e.rethrowFromSystemServer();
1208         }
1209     }
1210 
1211     // --- Mock provider support ---
1212     // TODO: It would be fantastic to deprecate mock providers entirely, and replace
1213     // with something closer to LocationProviderBase.java
1214 
1215     /**
1216      * Creates a mock location provider and adds it to the set of active providers.
1217      *
1218      * @param name the provider name
1219      *
1220      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1221      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1222      * allowed} for your app.
1223      * @throws IllegalArgumentException if a provider with the given name already exists
1224      */
addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy)1225     public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1226             boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1227             boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1228         ProviderProperties properties = new ProviderProperties(requiresNetwork,
1229                 requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
1230                 supportsBearing, powerRequirement, accuracy);
1231         if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
1232             throw new IllegalArgumentException("provider name contains illegal character: " + name);
1233         }
1234 
1235         try {
1236             mService.addTestProvider(name, properties, mContext.getOpPackageName());
1237         } catch (RemoteException e) {
1238             throw e.rethrowFromSystemServer();
1239         }
1240     }
1241 
1242     /**
1243      * Removes the mock location provider with the given name.
1244      *
1245      * @param provider the provider name
1246      *
1247      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1248      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1249      * allowed} for your app.
1250      * @throws IllegalArgumentException if no provider with the given name exists
1251      */
removeTestProvider(String provider)1252     public void removeTestProvider(String provider) {
1253         try {
1254             mService.removeTestProvider(provider, mContext.getOpPackageName());
1255         } catch (RemoteException e) {
1256             throw e.rethrowFromSystemServer();
1257         }
1258     }
1259 
1260     /**
1261      * Sets a mock location for the given provider.
1262      * <p>This location will be used in place of any actual location from the provider.
1263      * The location object must have a minimum number of fields set to be
1264      * considered a valid LocationProvider Location, as per documentation
1265      * on {@link Location} class.
1266      *
1267      * @param provider the provider name
1268      * @param loc the mock location
1269      *
1270      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1271      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1272      * allowed} for your app.
1273      * @throws IllegalArgumentException if no provider with the given name exists
1274      * @throws IllegalArgumentException if the location is incomplete
1275      */
setTestProviderLocation(String provider, Location loc)1276     public void setTestProviderLocation(String provider, Location loc) {
1277         if (!loc.isComplete()) {
1278             IllegalArgumentException e = new IllegalArgumentException(
1279                     "Incomplete location object, missing timestamp or accuracy? " + loc);
1280             if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
1281                 // just log on old platform (for backwards compatibility)
1282                 Log.w(TAG, e);
1283                 loc.makeComplete();
1284             } else {
1285                 // really throw it!
1286                 throw e;
1287             }
1288         }
1289 
1290         try {
1291             mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
1292         } catch (RemoteException e) {
1293             throw e.rethrowFromSystemServer();
1294         }
1295     }
1296 
1297     /**
1298      * Removes any mock location associated with the given provider.
1299      *
1300      * @param provider the provider name
1301      *
1302      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1303      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1304      * allowed} for your app.
1305      * @throws IllegalArgumentException if no provider with the given name exists
1306      */
clearTestProviderLocation(String provider)1307     public void clearTestProviderLocation(String provider) {
1308         try {
1309             mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
1310         } catch (RemoteException e) {
1311             throw e.rethrowFromSystemServer();
1312         }
1313     }
1314 
1315     /**
1316      * Sets a mock enabled value for the given provider.  This value will be used in place
1317      * of any actual value from the provider.
1318      *
1319      * @param provider the provider name
1320      * @param enabled the mock enabled value
1321      *
1322      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1323      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1324      * allowed} for your app.
1325      * @throws IllegalArgumentException if no provider with the given name exists
1326      */
setTestProviderEnabled(String provider, boolean enabled)1327     public void setTestProviderEnabled(String provider, boolean enabled) {
1328         try {
1329             mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
1330         } catch (RemoteException e) {
1331             throw e.rethrowFromSystemServer();
1332         }
1333     }
1334 
1335     /**
1336      * Removes any mock enabled value associated with the given provider.
1337      *
1338      * @param provider the provider name
1339      *
1340      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1341      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1342      * allowed} for your app.
1343      * @throws IllegalArgumentException if no provider with the given name exists
1344      */
clearTestProviderEnabled(String provider)1345     public void clearTestProviderEnabled(String provider) {
1346         try {
1347             mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
1348         } catch (RemoteException e) {
1349             throw e.rethrowFromSystemServer();
1350         }
1351     }
1352 
1353     /**
1354      * Sets mock status values for the given provider.  These values will be used in place
1355      * of any actual values from the provider.
1356      *
1357      * @param provider the provider name
1358      * @param status the mock status
1359      * @param extras a Bundle containing mock extras
1360      * @param updateTime the mock update time
1361      *
1362      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1363      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1364      * allowed} for your app.
1365      * @throws IllegalArgumentException if no provider with the given name exists
1366      */
setTestProviderStatus(String provider, int status, Bundle extras, long updateTime)1367     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1368         try {
1369             mService.setTestProviderStatus(provider, status, extras, updateTime,
1370                     mContext.getOpPackageName());
1371         } catch (RemoteException e) {
1372             throw e.rethrowFromSystemServer();
1373         }
1374     }
1375 
1376     /**
1377      * Removes any mock status values associated with the given provider.
1378      *
1379      * @param provider the provider name
1380      *
1381      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1382      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1383      * allowed} for your app.
1384      * @throws IllegalArgumentException if no provider with the given name exists
1385      */
clearTestProviderStatus(String provider)1386     public void clearTestProviderStatus(String provider) {
1387         try {
1388             mService.clearTestProviderStatus(provider, mContext.getOpPackageName());
1389         } catch (RemoteException e) {
1390             throw e.rethrowFromSystemServer();
1391         }
1392     }
1393 
1394     // --- GPS-specific support ---
1395 
1396     // This class is used to send Gnss status events to the client's specific thread.
1397     private class GnssStatusListenerTransport extends IGnssStatusListener.Stub {
1398 
1399         private final GpsStatus.Listener mGpsListener;
1400         private final GpsStatus.NmeaListener mGpsNmeaListener;
1401         private final GnssStatusCallback mOldGnssCallback;
1402         private final GnssStatus.Callback mGnssCallback;
1403         private final GnssNmeaListener mOldGnssNmeaListener;
1404         private final OnNmeaMessageListener mGnssNmeaListener;
1405 
1406         private class GnssHandler extends Handler {
GnssHandler(Handler handler)1407             public GnssHandler(Handler handler) {
1408                 super(handler != null ? handler.getLooper() : Looper.myLooper());
1409             }
1410 
1411             @Override
handleMessage(Message msg)1412             public void handleMessage(Message msg) {
1413                 switch (msg.what) {
1414                     case NMEA_RECEIVED:
1415                         synchronized (mNmeaBuffer) {
1416                             int length = mNmeaBuffer.size();
1417                             for (int i = 0; i < length; i++) {
1418                                 Nmea nmea = mNmeaBuffer.get(i);
1419                                 mGnssNmeaListener.onNmeaMessage(nmea.mNmea, nmea.mTimestamp);
1420                             }
1421                             mNmeaBuffer.clear();
1422                         }
1423                         break;
1424                     case GpsStatus.GPS_EVENT_STARTED:
1425                         mGnssCallback.onStarted();
1426                         break;
1427                     case GpsStatus.GPS_EVENT_STOPPED:
1428                         mGnssCallback.onStopped();
1429                         break;
1430                     case GpsStatus.GPS_EVENT_FIRST_FIX:
1431                         mGnssCallback.onFirstFix(mTimeToFirstFix);
1432                         break;
1433                     case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
1434                         mGnssCallback.onSatelliteStatusChanged(mGnssStatus);
1435                         break;
1436                     default:
1437                         break;
1438                 }
1439             }
1440         }
1441 
1442         private final Handler mGnssHandler;
1443 
1444         // This must not equal any of the GpsStatus event IDs
1445         private static final int NMEA_RECEIVED = 1000;
1446 
1447         private class Nmea {
1448             long mTimestamp;
1449             String mNmea;
1450 
Nmea(long timestamp, String nmea)1451             Nmea(long timestamp, String nmea) {
1452                 mTimestamp = timestamp;
1453                 mNmea = nmea;
1454             }
1455         }
1456         private final ArrayList<Nmea> mNmeaBuffer;
1457 
GnssStatusListenerTransport(GpsStatus.Listener listener)1458         GnssStatusListenerTransport(GpsStatus.Listener listener) {
1459             this(listener, null);
1460         }
1461 
GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler)1462         GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) {
1463             mGpsListener = listener;
1464             mGnssHandler = new GnssHandler(handler);
1465             mGpsNmeaListener = null;
1466             mNmeaBuffer = null;
1467             mOldGnssCallback = null;
1468             mGnssCallback = new GnssStatus.Callback() {
1469                 @Override
1470                 public void onStarted() {
1471                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
1472                 }
1473 
1474                 @Override
1475                 public void onStopped() {
1476                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
1477                 }
1478 
1479                 @Override
1480                 public void onFirstFix(int ttff) {
1481                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
1482                 }
1483 
1484                 @Override
1485                 public void onSatelliteStatusChanged(GnssStatus status) {
1486                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
1487                 }
1488             };
1489             mOldGnssNmeaListener = null;
1490             mGnssNmeaListener = null;
1491         }
1492 
GnssStatusListenerTransport(GpsStatus.NmeaListener listener)1493         GnssStatusListenerTransport(GpsStatus.NmeaListener listener) {
1494             this(listener, null);
1495         }
1496 
GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler)1497         GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) {
1498             mGpsListener = null;
1499             mGnssHandler = new GnssHandler(handler);
1500             mGpsNmeaListener = listener;
1501             mNmeaBuffer = new ArrayList<Nmea>();
1502             mOldGnssCallback = null;
1503             mGnssCallback = null;
1504             mOldGnssNmeaListener = null;
1505             mGnssNmeaListener = new OnNmeaMessageListener() {
1506                 @Override
1507                 public void onNmeaMessage(String nmea, long timestamp) {
1508                     mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
1509                 }
1510             };
1511         }
1512 
GnssStatusListenerTransport(GnssStatusCallback callback)1513         GnssStatusListenerTransport(GnssStatusCallback callback) {
1514             this(callback, null);
1515         }
1516 
GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler)1517         GnssStatusListenerTransport(GnssStatusCallback callback, Handler handler) {
1518             mOldGnssCallback = callback;
1519             mGnssCallback = new GnssStatus.Callback() {
1520                 @Override
1521                 public void onStarted() {
1522                     mOldGnssCallback.onStarted();
1523                 }
1524 
1525                 @Override
1526                 public void onStopped() {
1527                     mOldGnssCallback.onStopped();
1528                 }
1529 
1530                 @Override
1531                 public void onFirstFix(int ttff) {
1532                     mOldGnssCallback.onFirstFix(ttff);
1533                 }
1534 
1535                 @Override
1536                 public void onSatelliteStatusChanged(GnssStatus status) {
1537                     mOldGnssCallback.onSatelliteStatusChanged(status);
1538                 }
1539             };
1540             mGnssHandler = new GnssHandler(handler);
1541             mOldGnssNmeaListener = null;
1542             mGnssNmeaListener = null;
1543             mNmeaBuffer = null;
1544             mGpsListener = null;
1545             mGpsNmeaListener = null;
1546         }
1547 
GnssStatusListenerTransport(GnssStatus.Callback callback)1548         GnssStatusListenerTransport(GnssStatus.Callback callback) {
1549             this(callback, null);
1550         }
1551 
GnssStatusListenerTransport(GnssStatus.Callback callback, Handler handler)1552         GnssStatusListenerTransport(GnssStatus.Callback callback, Handler handler) {
1553             mOldGnssCallback = null;
1554             mGnssCallback = callback;
1555             mGnssHandler = new GnssHandler(handler);
1556             mOldGnssNmeaListener = null;
1557             mGnssNmeaListener = null;
1558             mNmeaBuffer = null;
1559             mGpsListener = null;
1560             mGpsNmeaListener = null;
1561         }
1562 
GnssStatusListenerTransport(GnssNmeaListener listener)1563         GnssStatusListenerTransport(GnssNmeaListener listener) {
1564             this(listener, null);
1565         }
1566 
GnssStatusListenerTransport(GnssNmeaListener listener, Handler handler)1567         GnssStatusListenerTransport(GnssNmeaListener listener, Handler handler) {
1568             mGnssCallback = null;
1569             mOldGnssCallback = null;
1570             mGnssHandler = new GnssHandler(handler);
1571             mOldGnssNmeaListener = listener;
1572             mGnssNmeaListener = new OnNmeaMessageListener() {
1573                 @Override
1574                 public void onNmeaMessage(String message, long timestamp) {
1575                     mOldGnssNmeaListener.onNmeaReceived(timestamp, message);
1576                 }
1577             };
1578             mGpsListener = null;
1579             mGpsNmeaListener = null;
1580             mNmeaBuffer = new ArrayList<Nmea>();
1581         }
1582 
GnssStatusListenerTransport(OnNmeaMessageListener listener)1583         GnssStatusListenerTransport(OnNmeaMessageListener listener) {
1584             this(listener, null);
1585         }
1586 
GnssStatusListenerTransport(OnNmeaMessageListener listener, Handler handler)1587         GnssStatusListenerTransport(OnNmeaMessageListener listener, Handler handler) {
1588             mOldGnssCallback = null;
1589             mGnssCallback = null;
1590             mGnssHandler = new GnssHandler(handler);
1591             mOldGnssNmeaListener = null;
1592             mGnssNmeaListener = listener;
1593             mGpsListener = null;
1594             mGpsNmeaListener = null;
1595             mNmeaBuffer = new ArrayList<Nmea>();
1596         }
1597 
1598         @Override
onGnssStarted()1599         public void onGnssStarted() {
1600             if (mGpsListener != null) {
1601                 Message msg = Message.obtain();
1602                 msg.what = GpsStatus.GPS_EVENT_STARTED;
1603                 mGnssHandler.sendMessage(msg);
1604             }
1605         }
1606 
1607         @Override
onGnssStopped()1608         public void onGnssStopped() {
1609             if (mGpsListener != null) {
1610                 Message msg = Message.obtain();
1611                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
1612                 mGnssHandler.sendMessage(msg);
1613             }
1614         }
1615 
1616         @Override
onFirstFix(int ttff)1617         public void onFirstFix(int ttff) {
1618             if (mGpsListener != null) {
1619                 mTimeToFirstFix = ttff;
1620                 Message msg = Message.obtain();
1621                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
1622                 mGnssHandler.sendMessage(msg);
1623             }
1624         }
1625 
1626         @Override
onSvStatusChanged(int svCount, int[] prnWithFlags, float[] cn0s, float[] elevations, float[] azimuths)1627         public void onSvStatusChanged(int svCount, int[] prnWithFlags,
1628                 float[] cn0s, float[] elevations, float[] azimuths) {
1629             if (mGnssCallback != null) {
1630                 mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths);
1631 
1632                 Message msg = Message.obtain();
1633                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
1634                 // remove any SV status messages already in the queue
1635                 mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
1636                 mGnssHandler.sendMessage(msg);
1637             }
1638         }
1639 
1640         @Override
onNmeaReceived(long timestamp, String nmea)1641         public void onNmeaReceived(long timestamp, String nmea) {
1642             if (mGnssNmeaListener != null) {
1643                 synchronized (mNmeaBuffer) {
1644                     mNmeaBuffer.add(new Nmea(timestamp, nmea));
1645                 }
1646                 Message msg = Message.obtain();
1647                 msg.what = NMEA_RECEIVED;
1648                 // remove any NMEA_RECEIVED messages already in the queue
1649                 mGnssHandler.removeMessages(NMEA_RECEIVED);
1650                 mGnssHandler.sendMessage(msg);
1651             }
1652         }
1653     }
1654 
1655     /**
1656      * Adds a GPS status listener.
1657      *
1658      * @param listener GPS status listener object to register
1659      *
1660      * @return true if the listener was successfully added
1661      *
1662      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1663      * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead.
1664      */
1665     @Deprecated
1666     @RequiresPermission(ACCESS_FINE_LOCATION)
addGpsStatusListener(GpsStatus.Listener listener)1667     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
1668         boolean result;
1669 
1670         if (mGpsStatusListeners.get(listener) != null) {
1671             // listener is already registered
1672             return true;
1673         }
1674         try {
1675             GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
1676             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1677             if (result) {
1678                 mGpsStatusListeners.put(listener, transport);
1679             }
1680         } catch (RemoteException e) {
1681             throw e.rethrowFromSystemServer();
1682         }
1683 
1684         return result;
1685     }
1686 
1687     /**
1688      * Removes a GPS status listener.
1689      *
1690      * @param listener GPS status listener object to remove
1691      * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead.
1692      */
1693     @Deprecated
removeGpsStatusListener(GpsStatus.Listener listener)1694     public void removeGpsStatusListener(GpsStatus.Listener listener) {
1695         try {
1696             GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
1697             if (transport != null) {
1698                 mService.unregisterGnssStatusCallback(transport);
1699             }
1700         } catch (RemoteException e) {
1701             throw e.rethrowFromSystemServer();
1702         }
1703     }
1704 
1705     /**
1706      * Registers a GNSS status listener.
1707      *
1708      * @param callback GNSS status listener object to register
1709      *
1710      * @return true if the listener was successfully added
1711      *
1712      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1713      * @removed
1714      */
1715     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback(GnssStatusCallback callback)1716     public boolean registerGnssStatusCallback(GnssStatusCallback callback) {
1717         return registerGnssStatusCallback(callback, null);
1718     }
1719 
1720     /**
1721      * Registers a GNSS status listener.
1722      *
1723      * @param callback GNSS status listener object to register
1724      * @param handler the handler that the callback runs on.
1725      *
1726      * @return true if the listener was successfully added
1727      *
1728      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1729      * @removed
1730      */
1731     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback(GnssStatusCallback callback, Handler handler)1732     public boolean registerGnssStatusCallback(GnssStatusCallback callback, Handler handler) {
1733         boolean result;
1734         if (mOldGnssStatusListeners.get(callback) != null) {
1735             // listener is already registered
1736             return true;
1737         }
1738         try {
1739             GnssStatusListenerTransport transport =
1740                     new GnssStatusListenerTransport(callback, handler);
1741             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1742             if (result) {
1743                 mOldGnssStatusListeners.put(callback, transport);
1744             }
1745         } catch (RemoteException e) {
1746             throw e.rethrowFromSystemServer();
1747         }
1748 
1749         return result;
1750     }
1751 
1752     /**
1753      * Removes a GNSS status listener.
1754      *
1755      * @param callback GNSS status listener object to remove
1756      * @removed
1757      */
unregisterGnssStatusCallback(GnssStatusCallback callback)1758     public void unregisterGnssStatusCallback(GnssStatusCallback callback) {
1759         try {
1760             GnssStatusListenerTransport transport = mOldGnssStatusListeners.remove(callback);
1761             if (transport != null) {
1762                 mService.unregisterGnssStatusCallback(transport);
1763             }
1764         } catch (RemoteException e) {
1765             throw e.rethrowFromSystemServer();
1766         }
1767     }
1768 
1769     /**
1770      * Registers a GNSS status listener.
1771      *
1772      * @param callback GNSS status listener object to register
1773      *
1774      * @return true if the listener was successfully added
1775      *
1776      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1777      */
1778     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback(GnssStatus.Callback callback)1779     public boolean registerGnssStatusCallback(GnssStatus.Callback callback) {
1780         return registerGnssStatusCallback(callback, null);
1781     }
1782 
1783     /**
1784      * Registers a GNSS status listener.
1785      *
1786      * @param callback GNSS status listener object to register
1787      * @param handler the handler that the callback runs on.
1788      *
1789      * @return true if the listener was successfully added
1790      *
1791      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1792      */
1793     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback(GnssStatus.Callback callback, Handler handler)1794     public boolean registerGnssStatusCallback(GnssStatus.Callback callback, Handler handler) {
1795         boolean result;
1796         if (mGnssStatusListeners.get(callback) != null) {
1797             // listener is already registered
1798             return true;
1799         }
1800         try {
1801             GnssStatusListenerTransport transport =
1802                     new GnssStatusListenerTransport(callback, handler);
1803             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1804             if (result) {
1805                 mGnssStatusListeners.put(callback, transport);
1806             }
1807         } catch (RemoteException e) {
1808             throw e.rethrowFromSystemServer();
1809         }
1810 
1811         return result;
1812     }
1813 
1814     /**
1815      * Removes a GNSS status listener.
1816      *
1817      * @param callback GNSS status listener object to remove
1818      */
unregisterGnssStatusCallback(GnssStatus.Callback callback)1819     public void unregisterGnssStatusCallback(GnssStatus.Callback callback) {
1820         try {
1821             GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback);
1822             if (transport != null) {
1823                 mService.unregisterGnssStatusCallback(transport);
1824             }
1825         } catch (RemoteException e) {
1826             throw e.rethrowFromSystemServer();
1827         }
1828     }
1829 
1830     /**
1831      * Adds an NMEA listener.
1832      *
1833      * @param listener a {@link GpsStatus.NmeaListener} object to register
1834      *
1835      * @return true if the listener was successfully added
1836      *
1837      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1838      * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead.
1839      */
1840     @Deprecated
1841     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(GpsStatus.NmeaListener listener)1842     public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
1843         boolean result;
1844 
1845         if (mGpsNmeaListeners.get(listener) != null) {
1846             // listener is already registered
1847             return true;
1848         }
1849         try {
1850             GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
1851             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1852             if (result) {
1853                 mGpsNmeaListeners.put(listener, transport);
1854             }
1855         } catch (RemoteException e) {
1856             throw e.rethrowFromSystemServer();
1857         }
1858 
1859         return result;
1860     }
1861 
1862     /**
1863      * Removes an NMEA listener.
1864      *
1865      * @param listener a {@link GpsStatus.NmeaListener} object to remove
1866      * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
1867      */
1868     @Deprecated
removeNmeaListener(GpsStatus.NmeaListener listener)1869     public void removeNmeaListener(GpsStatus.NmeaListener listener) {
1870         try {
1871             GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener);
1872             if (transport != null) {
1873                 mService.unregisterGnssStatusCallback(transport);
1874             }
1875         } catch (RemoteException e) {
1876             throw e.rethrowFromSystemServer();
1877         }
1878     }
1879 
1880     /**
1881      * Adds an NMEA listener.
1882      *
1883      * @param listener a {@link GnssNmeaListener} object to register
1884      *
1885      * @return true if the listener was successfully added
1886      *
1887      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1888      * @removed
1889      */
1890     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(GnssNmeaListener listener)1891     public boolean addNmeaListener(GnssNmeaListener listener) {
1892         return addNmeaListener(listener, null);
1893     }
1894 
1895     /**
1896      * Adds an NMEA listener.
1897      *
1898      * @param listener a {@link GnssNmeaListener} object to register
1899      * @param handler the handler that the listener runs on.
1900      *
1901      * @return true if the listener was successfully added
1902      *
1903      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1904      * @removed
1905      */
1906     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(GnssNmeaListener listener, Handler handler)1907     public boolean addNmeaListener(GnssNmeaListener listener, Handler handler) {
1908         boolean result;
1909 
1910         if (mGpsNmeaListeners.get(listener) != null) {
1911             // listener is already registered
1912             return true;
1913         }
1914         try {
1915             GnssStatusListenerTransport transport =
1916                     new GnssStatusListenerTransport(listener, handler);
1917             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1918             if (result) {
1919                 mOldGnssNmeaListeners.put(listener, transport);
1920             }
1921         } catch (RemoteException e) {
1922             throw e.rethrowFromSystemServer();
1923         }
1924 
1925         return result;
1926     }
1927 
1928     /**
1929      * Removes an NMEA listener.
1930      *
1931      * @param listener a {@link GnssNmeaListener} object to remove
1932      * @removed
1933      */
removeNmeaListener(GnssNmeaListener listener)1934     public void removeNmeaListener(GnssNmeaListener listener) {
1935         try {
1936             GnssStatusListenerTransport transport = mOldGnssNmeaListeners.remove(listener);
1937             if (transport != null) {
1938                 mService.unregisterGnssStatusCallback(transport);
1939             }
1940         } catch (RemoteException e) {
1941             throw e.rethrowFromSystemServer();
1942         }
1943     }
1944 
1945     /**
1946      * Adds an NMEA listener.
1947      *
1948      * @param listener a {@link OnNmeaMessageListener} object to register
1949      *
1950      * @return true if the listener was successfully added
1951      *
1952      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1953      */
1954     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(OnNmeaMessageListener listener)1955     public boolean addNmeaListener(OnNmeaMessageListener listener) {
1956         return addNmeaListener(listener, null);
1957     }
1958 
1959     /**
1960      * Adds an NMEA listener.
1961      *
1962      * @param listener a {@link OnNmeaMessageListener} object to register
1963      * @param handler the handler that the listener runs on.
1964      *
1965      * @return true if the listener was successfully added
1966      *
1967      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1968      */
1969     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(OnNmeaMessageListener listener, Handler handler)1970     public boolean addNmeaListener(OnNmeaMessageListener listener, Handler handler) {
1971         boolean result;
1972 
1973         if (mGpsNmeaListeners.get(listener) != null) {
1974             // listener is already registered
1975             return true;
1976         }
1977         try {
1978             GnssStatusListenerTransport transport =
1979                     new GnssStatusListenerTransport(listener, handler);
1980             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
1981             if (result) {
1982                 mGnssNmeaListeners.put(listener, transport);
1983             }
1984         } catch (RemoteException e) {
1985             throw e.rethrowFromSystemServer();
1986         }
1987 
1988         return result;
1989     }
1990 
1991     /**
1992      * Removes an NMEA listener.
1993      *
1994      * @param listener a {@link OnNmeaMessageListener} object to remove
1995      */
removeNmeaListener(OnNmeaMessageListener listener)1996     public void removeNmeaListener(OnNmeaMessageListener listener) {
1997         try {
1998             GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener);
1999             if (transport != null) {
2000                 mService.unregisterGnssStatusCallback(transport);
2001             }
2002         } catch (RemoteException e) {
2003             throw e.rethrowFromSystemServer();
2004         }
2005     }
2006 
2007     /**
2008      * No-op method to keep backward-compatibility.
2009      * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
2010      * @hide
2011      * @deprecated Not supported anymore.
2012      */
2013     @Deprecated
2014     @SystemApi
addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)2015     public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
2016         return false;
2017     }
2018 
2019     /**
2020      * Registers a GPS Measurement callback.
2021      *
2022      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2023      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2024      */
2025     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback)2026     public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
2027         return registerGnssMeasurementsCallback(callback, null);
2028     }
2029 
2030     /**
2031      * Registers a GPS Measurement callback.
2032      *
2033      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2034      * @param handler the handler that the callback runs on.
2035      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2036      */
2037     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback, Handler handler)2038     public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback,
2039             Handler handler) {
2040         return mGnssMeasurementCallbackTransport.add(callback, handler);
2041     }
2042 
2043     /**
2044      * No-op method to keep backward-compatibility.
2045      * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead.
2046      * @hide
2047      * @deprecated use {@link #unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback)}
2048      * instead.
2049      */
2050     @Deprecated
2051     @SystemApi
removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)2052     public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
2053     }
2054 
2055     /**
2056      * Unregisters a GPS Measurement callback.
2057      *
2058      * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
2059      */
unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback)2060     public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
2061         mGnssMeasurementCallbackTransport.remove(callback);
2062     }
2063 
2064     /**
2065      * No-op method to keep backward-compatibility.
2066      * Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead.
2067      * @hide
2068      * @deprecated Not supported anymore.
2069      */
2070     @Deprecated
2071     @SystemApi
addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)2072     public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
2073         return false;
2074     }
2075 
2076     /**
2077      * No-op method to keep backward-compatibility.
2078      * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead.
2079      * @hide
2080      * @deprecated use {@link #unregisterGnssNavigationMessageCallback(GnssMeasurements.Callback)}
2081      * instead
2082      */
2083     @Deprecated
2084     @SystemApi
removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)2085     public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
2086     }
2087 
2088     /**
2089      * Registers a GNSS Navigation Message callback.
2090      *
2091      * @param callback a {@link GnssNavigationMessageEvent.Callback} object to register.
2092      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2093      * @removed
2094      */
registerGnssNavigationMessageCallback( GnssNavigationMessageEvent.Callback callback)2095     public boolean registerGnssNavigationMessageCallback(
2096             GnssNavigationMessageEvent.Callback callback) {
2097         return registerGnssNavigationMessageCallback(callback, null);
2098     }
2099 
2100     /**
2101      * Registers a GNSS Navigation Message callback.
2102      *
2103      * @param callback a {@link GnssNavigationMessageEvent.Callback} object to register.
2104      * @param handler the handler that the callback runs on.
2105      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2106      * @removed
2107      */
2108     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssNavigationMessageCallback( final GnssNavigationMessageEvent.Callback callback, Handler handler)2109     public boolean registerGnssNavigationMessageCallback(
2110             final GnssNavigationMessageEvent.Callback callback, Handler handler) {
2111         GnssNavigationMessage.Callback bridge = new GnssNavigationMessage.Callback() {
2112             @Override
2113             public void onGnssNavigationMessageReceived(GnssNavigationMessage message) {
2114                 GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
2115                 callback.onGnssNavigationMessageReceived(event);
2116             }
2117 
2118             @Override
2119             public void onStatusChanged(int status) {
2120                 callback.onStatusChanged(status);
2121             }
2122         };
2123         mNavigationMessageBridge.put(callback, bridge);
2124         return mGnssNavigationMessageCallbackTransport.add(bridge, handler);
2125     }
2126 
2127     /**
2128      * Unregisters a GNSS Navigation Message callback.
2129      *
2130      * @param callback a {@link GnssNavigationMessageEvent.Callback} object to remove.
2131      * @removed
2132      */
unregisterGnssNavigationMessageCallback( GnssNavigationMessageEvent.Callback callback)2133     public void unregisterGnssNavigationMessageCallback(
2134             GnssNavigationMessageEvent.Callback callback) {
2135         mGnssNavigationMessageCallbackTransport.remove(
2136                 mNavigationMessageBridge.remove(
2137                         callback));
2138     }
2139 
2140     /**
2141      * Registers a GNSS Navigation Message callback.
2142      *
2143      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
2144      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2145      */
registerGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback)2146     public boolean registerGnssNavigationMessageCallback(
2147             GnssNavigationMessage.Callback callback) {
2148         return registerGnssNavigationMessageCallback(callback, null);
2149     }
2150 
2151     /**
2152      * Registers a GNSS Navigation Message callback.
2153      *
2154      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
2155      * @param handler the handler that the callback runs on.
2156      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2157      */
2158     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback, Handler handler)2159     public boolean registerGnssNavigationMessageCallback(
2160             GnssNavigationMessage.Callback callback, Handler handler) {
2161         return mGnssNavigationMessageCallbackTransport.add(callback, handler);
2162     }
2163 
2164     /**
2165      * Unregisters a GNSS Navigation Message callback.
2166      *
2167      * @param callback a {@link GnssNavigationMessage.Callback} object to remove.
2168      */
unregisterGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback)2169     public void unregisterGnssNavigationMessageCallback(
2170             GnssNavigationMessage.Callback callback) {
2171         mGnssNavigationMessageCallbackTransport.remove(callback);
2172     }
2173 
2174     /**
2175      * Retrieves information about the current status of the GPS engine.
2176      * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
2177      * callback to ensure that the data is copied atomically.
2178      *
2179      * The caller may either pass in a {@link GpsStatus} object to set with the latest
2180      * status information, or pass null to create a new {@link GpsStatus} object.
2181      *
2182      * @param status object containing GPS status details, or null.
2183      * @return status object containing updated GPS status.
2184      */
2185     @Deprecated
2186     @RequiresPermission(ACCESS_FINE_LOCATION)
getGpsStatus(GpsStatus status)2187     public GpsStatus getGpsStatus(GpsStatus status) {
2188         if (status == null) {
2189             status = new GpsStatus();
2190         }
2191         // When mGnssStatus is null, that means that this method is called outside
2192         // onGpsStatusChanged().  Return an empty status  to maintain backwards compatibility.
2193         if (mGnssStatus != null) {
2194             status.setStatus(mGnssStatus, mTimeToFirstFix);
2195         }
2196         return status;
2197     }
2198 
2199     /**
2200      * Returns the system information of the GPS hardware.
2201      * May return 0 if GPS hardware is earlier than 2016.
2202      * @hide
2203      */
2204     @TestApi
getGnssYearOfHardware()2205     public int getGnssYearOfHardware() {
2206         try {
2207             return mService.getGnssYearOfHardware();
2208         } catch (RemoteException e) {
2209             throw e.rethrowFromSystemServer();
2210         }
2211     }
2212 
2213     /**
2214      * Sends additional commands to a location provider.
2215      * Can be used to support provider specific extensions to the Location Manager API
2216      *
2217      * @param provider name of the location provider.
2218      * @param command name of the command to send to the provider.
2219      * @param extras optional arguments for the command (or null).
2220      * The provider may optionally fill the extras Bundle with results from the command.
2221      *
2222      * @return true if the command succeeds.
2223      */
sendExtraCommand(String provider, String command, Bundle extras)2224     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
2225         try {
2226             return mService.sendExtraCommand(provider, command, extras);
2227         } catch (RemoteException e) {
2228             throw e.rethrowFromSystemServer();
2229         }
2230     }
2231 
2232     /**
2233      * Used by NetInitiatedActivity to report user response
2234      * for network initiated GPS fix requests.
2235      *
2236      * @hide
2237      */
sendNiResponse(int notifId, int userResponse)2238     public boolean sendNiResponse(int notifId, int userResponse) {
2239         try {
2240             return mService.sendNiResponse(notifId, userResponse);
2241         } catch (RemoteException e) {
2242             throw e.rethrowFromSystemServer();
2243         }
2244     }
2245 
checkProvider(String provider)2246     private static void checkProvider(String provider) {
2247         if (provider == null) {
2248             throw new IllegalArgumentException("invalid provider: " + provider);
2249         }
2250     }
2251 
checkCriteria(Criteria criteria)2252     private static void checkCriteria(Criteria criteria) {
2253         if (criteria == null) {
2254             throw new IllegalArgumentException("invalid criteria: " + criteria);
2255         }
2256     }
2257 
checkListener(LocationListener listener)2258     private static void checkListener(LocationListener listener) {
2259         if (listener == null) {
2260             throw new IllegalArgumentException("invalid listener: " + listener);
2261         }
2262     }
2263 
checkPendingIntent(PendingIntent intent)2264     private void checkPendingIntent(PendingIntent intent) {
2265         if (intent == null) {
2266             throw new IllegalArgumentException("invalid pending intent: " + intent);
2267         }
2268         if (!intent.isTargetedToPackage()) {
2269             IllegalArgumentException e = new IllegalArgumentException(
2270                     "pending intent must be targeted to package");
2271             if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
2272                 throw e;
2273             } else {
2274                 Log.w(TAG, e);
2275             }
2276         }
2277     }
2278 
checkGeofence(Geofence fence)2279     private static void checkGeofence(Geofence fence) {
2280         if (fence == null) {
2281             throw new IllegalArgumentException("invalid geofence: " + fence);
2282         }
2283     }
2284 }
2285