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