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