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