• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.location;
18 
19 import 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 import static android.app.AlarmManager.ELAPSED_REALTIME;
24 
25 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
26 
27 import android.Manifest;
28 import android.annotation.CallbackExecutor;
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.RequiresFeature;
32 import android.annotation.RequiresPermission;
33 import android.annotation.SystemApi;
34 import android.annotation.SystemService;
35 import android.annotation.TestApi;
36 import android.app.AlarmManager;
37 import android.app.AppOpsManager;
38 import android.app.PendingIntent;
39 import android.app.PropertyInvalidatedCache;
40 import android.compat.Compatibility;
41 import android.compat.annotation.ChangeId;
42 import android.compat.annotation.EnabledAfter;
43 import android.compat.annotation.UnsupportedAppUsage;
44 import android.content.Context;
45 import android.content.pm.PackageManager;
46 import android.os.Binder;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.CancellationSignal;
50 import android.os.Handler;
51 import android.os.HandlerExecutor;
52 import android.os.ICancellationSignal;
53 import android.os.Looper;
54 import android.os.Process;
55 import android.os.RemoteException;
56 import android.os.SystemClock;
57 import android.os.UserHandle;
58 import android.provider.Settings;
59 import android.util.ArrayMap;
60 
61 import com.android.internal.annotations.GuardedBy;
62 import com.android.internal.location.ProviderProperties;
63 import com.android.internal.util.Preconditions;
64 import com.android.internal.util.function.pooled.PooledRunnable;
65 
66 import java.util.Collections;
67 import java.util.List;
68 import java.util.concurrent.Executor;
69 import java.util.concurrent.RejectedExecutionException;
70 import java.util.function.Consumer;
71 
72 /**
73  * This class provides access to the system location services. These services allow applications to
74  * obtain periodic updates of the device's geographical location, or to be notified when the device
75  * enters the proximity of a given geographical location.
76  *
77  * <p class="note">Unless noted, all Location API methods require the {@link
78  * android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link
79  * android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only has the
80  * coarse permission then it will not have access to fine location providers. Other providers will
81  * still return location results, but the exact location will be obfuscated to a coarse level of
82  * accuracy.
83  */
84 @SuppressWarnings({"deprecation"})
85 @SystemService(Context.LOCATION_SERVICE)
86 @RequiresFeature(PackageManager.FEATURE_LOCATION)
87 public class LocationManager {
88 
89     @GuardedBy("mLock")
90     private PropertyInvalidatedCache<Integer, Boolean> mLocationEnabledCache =
91             new PropertyInvalidatedCache<Integer, Boolean>(
92                 4,
93                 CACHE_KEY_LOCATION_ENABLED_PROPERTY) {
94                 @Override
95                 protected Boolean recompute(Integer userHandle) {
96                     try {
97                         return mService.isLocationEnabledForUser(userHandle);
98                     } catch (RemoteException e) {
99                         throw e.rethrowFromSystemServer();
100                     }
101                 }
102             };
103 
104     private final Object mLock = new Object();
105 
106     /**
107      * For apps targeting Android R and above, {@link #getProvider(String)} will no longer throw any
108      * security exceptions.
109      *
110      * @hide
111      */
112     @ChangeId
113     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
114     private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
115 
116     /**
117      * For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
118      * specific package.
119      *
120      * @hide
121      */
122     @ChangeId
123     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
124     private static final long TARGETED_PENDING_INTENT = 148963590L;
125 
126     /**
127      * For apps targeting Android K and above, incomplete locations may not be passed to
128      * {@link #setTestProviderLocation}.
129      *
130      * @hide
131      */
132     @ChangeId
133     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
134     private static final long INCOMPLETE_LOCATION = 148964793L;
135 
136     /**
137      * For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
138      * {@link GnssStatus} APIs.
139      *
140      * @hide
141      */
142     @ChangeId
143     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
144     private static final long GPS_STATUS_USAGE = 144027538L;
145 
146     /**
147      * Name of the network location provider.
148      *
149      * <p>This provider determines location based on nearby of cell tower and WiFi access points.
150      * Results are retrieved by means of a network lookup.
151      */
152     public static final String NETWORK_PROVIDER = "network";
153 
154     /**
155      * Name of the GNSS location provider.
156      *
157      * <p>This provider determines location using GNSS satellites. Depending on conditions, this
158      * provider may take a while to return a location fix. Requires the
159      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
160      *
161      * <p>The extras Bundle for the GPS location provider can contain the following key/value pairs:
162      * <ul>
163      * <li> satellites - the number of satellites used to derive the fix
164      * </ul>
165      */
166     public static final String GPS_PROVIDER = "gps";
167 
168     /**
169      * A special location provider for receiving locations without actually initiating a location
170      * fix.
171      *
172      * <p>This provider can be used to passively receive location updates when other applications or
173      * services request them without actually requesting the locations yourself. This provider will
174      * only return locations generated by other providers.  You can query the
175      * {@link Location#getProvider()} method to determine the actual provider that supplied the
176      * location update. Requires the {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
177      * permission, although there is no guarantee of fine locations.
178      */
179     public static final String PASSIVE_PROVIDER = "passive";
180 
181     /**
182      * The fused location provider.
183      *
184      * <p>This provider combines may combine inputs from several location sources to provide the
185      * best possible location fix. It is implicitly used for all API's that involve the
186      * {@link LocationRequest} object.
187      *
188      * @hide
189      */
190     @TestApi
191     public static final String FUSED_PROVIDER = "fused";
192 
193     /**
194      * Key used for the Bundle extra holding a boolean indicating whether
195      * a proximity alert is entering (true) or exiting (false)..
196      */
197     public static final String KEY_PROXIMITY_ENTERING = "entering";
198 
199     /**
200      * This key is no longer in use.
201      *
202      * <p>Key used for a Bundle extra holding an Integer status value when a status change is
203      * broadcast using a PendingIntent.
204      *
205      * @deprecated Status changes are deprecated and no longer broadcast from Android Q onwards.
206      */
207     @Deprecated
208     public static final String KEY_STATUS_CHANGED = "status";
209 
210     /**
211      * Key used for an extra holding a boolean enabled/disabled status value when a provider
212      * enabled/disabled event is broadcast using a PendingIntent.
213      *
214      * @see #requestLocationUpdates(String, long, float, PendingIntent)
215      */
216     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
217 
218     /**
219      * Key used for an extra holding a {@link Location} value when a location change is broadcast
220      * using a PendingIntent.
221      *
222      * @see #requestLocationUpdates(String, long, float, PendingIntent)
223      */
224     public static final String KEY_LOCATION_CHANGED = "location";
225 
226     /**
227      * Broadcast intent action when the set of enabled location providers changes. To check the
228      * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
229      * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
230      * whose state has changed. From Android R and above, will include a boolean intent extra,
231      * {@link #EXTRA_PROVIDER_ENABLED}, with the enabled state of the provider.
232      *
233      * @see #EXTRA_PROVIDER_NAME
234      * @see #EXTRA_PROVIDER_ENABLED
235      * @see #isProviderEnabled(String)
236      */
237     public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
238 
239     /**
240      * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name
241      * of the location provider that has changed.
242      *
243      * @see #PROVIDERS_CHANGED_ACTION
244      * @see #EXTRA_PROVIDER_ENABLED
245      */
246     public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
247 
248     /**
249      * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the
250      * boolean enabled state of the location provider that has changed.
251      *
252      * @see #PROVIDERS_CHANGED_ACTION
253      * @see #EXTRA_PROVIDER_NAME
254      */
255     public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
256 
257     /**
258      * Broadcast intent action when the device location enabled state changes. From Android R and
259      * above, will include a boolean intent extra, {@link #EXTRA_LOCATION_ENABLED}, with the enabled
260      * state of location.
261      *
262      * @see #EXTRA_LOCATION_ENABLED
263      * @see #isLocationEnabled()
264      */
265     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
266 
267     /**
268      * Intent extra included with {@link #MODE_CHANGED_ACTION} broadcasts, containing the boolean
269      * enabled state of location.
270      *
271      * @see #MODE_CHANGED_ACTION
272      */
273     public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
274 
275     /**
276      * Broadcast intent action indicating that a high power location requests
277      * has either started or stopped being active.  The current state of
278      * active location requests should be read from AppOpsManager using
279      * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
280      *
281      * @hide
282      */
283     public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
284             "android.location.HIGH_POWER_REQUEST_CHANGE";
285 
286     /**
287      * Broadcast intent action for Settings app to inject a footer at the bottom of location
288      * settings. This is for use only by apps that are included in the system image.
289      *
290      * <p>To inject a footer to location settings, you must declare a broadcast receiver for
291      * this action in the manifest:
292      * <pre>
293      *     &lt;receiver android:name="com.example.android.footer.MyFooterInjector"&gt;
294      *         &lt;intent-filter&gt;
295      *             &lt;action android:name="com.android.settings.location.INJECT_FOOTER" /&gt;
296      *         &lt;/intent-filter&gt;
297      *         &lt;meta-data
298      *             android:name="com.android.settings.location.FOOTER_STRING"
299      *             android:resource="@string/my_injected_footer_string" /&gt;
300      *     &lt;/receiver&gt;
301      * </pre>
302      *
303      * <p>This broadcast receiver will never actually be invoked. See also
304      * {#METADATA_SETTINGS_FOOTER_STRING}.
305      *
306      * @hide
307      */
308     public static final String SETTINGS_FOOTER_DISPLAYED_ACTION =
309             "com.android.settings.location.DISPLAYED_FOOTER";
310 
311     /**
312      * Metadata name for {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast
313      * receivers to specify a string resource id as location settings footer text. This is for use
314      * only by apps that are included in the system image.
315      *
316      * <p>See {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} for more detail on how to use.
317      *
318      * @hide
319      */
320     public static final String METADATA_SETTINGS_FOOTER_STRING =
321             "com.android.settings.location.FOOTER_STRING";
322 
323     private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
324 
325     private final Context mContext;
326 
327     @UnsupportedAppUsage
328     private final ILocationManager mService;
329 
330     @GuardedBy("mListeners")
331     private final ArrayMap<LocationListener, LocationListenerTransport> mListeners =
332             new ArrayMap<>();
333 
334     @GuardedBy("mBatchedLocationCallbackManager")
335     private final BatchedLocationCallbackManager mBatchedLocationCallbackManager =
336             new BatchedLocationCallbackManager();
337     private final GnssStatusListenerManager
338             mGnssStatusListenerManager = new GnssStatusListenerManager();
339     private final GnssMeasurementsListenerManager mGnssMeasurementsListenerManager =
340             new GnssMeasurementsListenerManager();
341     private final GnssNavigationMessageListenerManager mGnssNavigationMessageListenerTransport =
342             new GnssNavigationMessageListenerManager();
343     private final GnssAntennaInfoListenerManager mGnssAntennaInfoListenerManager =
344             new GnssAntennaInfoListenerManager();
345 
346     /**
347      * @hide
348      */
LocationManager(@onNull Context context, @NonNull ILocationManager service)349     public LocationManager(@NonNull Context context, @NonNull ILocationManager service) {
350         mService = service;
351         mContext = context;
352     }
353 
354     /**
355      * @hide
356      */
357     @TestApi
getBackgroundThrottlingWhitelist()358     public @NonNull String[] getBackgroundThrottlingWhitelist() {
359         try {
360             return mService.getBackgroundThrottlingWhitelist();
361         } catch (RemoteException e) {
362             throw e.rethrowFromSystemServer();
363         }
364     }
365 
366     /**
367      * @hide
368      */
369     @TestApi
getIgnoreSettingsWhitelist()370     public @NonNull String[] getIgnoreSettingsWhitelist() {
371         try {
372             return mService.getIgnoreSettingsWhitelist();
373         } catch (RemoteException e) {
374             throw e.rethrowFromSystemServer();
375         }
376     }
377 
378     /**
379      * Returns the extra location controller package on the device.
380      *
381      * @hide
382      */
383     @SystemApi
getExtraLocationControllerPackage()384     public @Nullable String getExtraLocationControllerPackage() {
385         try {
386             return mService.getExtraLocationControllerPackage();
387         } catch (RemoteException e) {
388             e.rethrowFromSystemServer();
389             return null;
390         }
391     }
392 
393     /**
394      * Set the extra location controller package for location services on the device.
395      *
396      * @hide
397      */
398     @SystemApi
399     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
setExtraLocationControllerPackage(@ullable String packageName)400     public void setExtraLocationControllerPackage(@Nullable String packageName) {
401         try {
402             mService.setExtraLocationControllerPackage(packageName);
403         } catch (RemoteException e) {
404             e.rethrowFromSystemServer();
405         }
406     }
407 
408     /**
409      * Set whether the extra location controller package is currently enabled on the device.
410      *
411      * @hide
412      */
413     @SystemApi
414     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
setExtraLocationControllerPackageEnabled(boolean enabled)415     public void setExtraLocationControllerPackageEnabled(boolean enabled) {
416         try {
417             mService.setExtraLocationControllerPackageEnabled(enabled);
418         } catch (RemoteException e) {
419             e.rethrowFromSystemServer();
420         }
421     }
422 
423     /**
424      * Returns whether extra location controller package is currently enabled on the device.
425      *
426      * @hide
427      */
428     @SystemApi
isExtraLocationControllerPackageEnabled()429     public boolean isExtraLocationControllerPackageEnabled() {
430         try {
431             return mService.isExtraLocationControllerPackageEnabled();
432         } catch (RemoteException e) {
433             e.rethrowFromSystemServer();
434             return false;
435         }
436     }
437 
438     /**
439      * Set the extra location controller package for location services on the device.
440      *
441      * @removed
442      * @deprecated Use {@link #setExtraLocationControllerPackage} instead.
443      * @hide
444      */
445     @Deprecated
446     @SystemApi
447     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
setLocationControllerExtraPackage(String packageName)448     public void setLocationControllerExtraPackage(String packageName) {
449         try {
450             mService.setExtraLocationControllerPackage(packageName);
451         } catch (RemoteException e) {
452             e.rethrowFromSystemServer();
453         }
454     }
455 
456     /**
457      * Set whether the extra location controller package is currently enabled on the device.
458      *
459      * @removed
460      * @deprecated Use {@link #setExtraLocationControllerPackageEnabled} instead.
461      * @hide
462      */
463     @SystemApi
464     @Deprecated
465     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
setLocationControllerExtraPackageEnabled(boolean enabled)466     public void setLocationControllerExtraPackageEnabled(boolean enabled) {
467         try {
468             mService.setExtraLocationControllerPackageEnabled(enabled);
469         } catch (RemoteException e) {
470             e.rethrowFromSystemServer();
471         }
472     }
473 
474     /**
475      * Returns the current enabled/disabled state of location. To listen for changes, see
476      * {@link #MODE_CHANGED_ACTION}.
477      *
478      * @return true if location is enabled and false if location is disabled.
479      */
isLocationEnabled()480     public boolean isLocationEnabled() {
481         return isLocationEnabledForUser(Process.myUserHandle());
482     }
483 
484     /**
485      * Returns the current enabled/disabled state of location for the given user.
486      *
487      * @param userHandle the user to query
488      * @return true if location is enabled and false if location is disabled.
489      *
490      * @hide
491      */
492     @SystemApi
isLocationEnabledForUser(@onNull UserHandle userHandle)493     public boolean isLocationEnabledForUser(@NonNull UserHandle userHandle) {
494         synchronized (mLock) {
495             if (mLocationEnabledCache != null) {
496                 return mLocationEnabledCache.query(userHandle.getIdentifier());
497             }
498         }
499 
500         // fallback if cache is disabled
501         try {
502             return mService.isLocationEnabledForUser(userHandle.getIdentifier());
503         } catch (RemoteException e) {
504             throw e.rethrowFromSystemServer();
505         }
506     }
507 
508     /**
509      * Enables or disables location for the given user.
510      *
511      * @param enabled true to enable location and false to disable location.
512      * @param userHandle the user to set
513      *
514      * @hide
515      */
516     @SystemApi
517     @TestApi
518     @RequiresPermission(WRITE_SECURE_SETTINGS)
setLocationEnabledForUser(boolean enabled, @NonNull UserHandle userHandle)519     public void setLocationEnabledForUser(boolean enabled, @NonNull UserHandle userHandle) {
520         try {
521             mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
522         } catch (RemoteException e) {
523             throw e.rethrowFromSystemServer();
524         }
525     }
526 
527     /**
528      * Returns the current enabled/disabled status of the given provider. To listen for changes, see
529      * {@link #PROVIDERS_CHANGED_ACTION}.
530      *
531      * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw
532      * {@link SecurityException} if the location permissions were not sufficient to use the
533      * specified provider.
534      *
535      * @param provider a provider listed by {@link #getAllProviders()}
536      * @return true if the provider exists and is enabled
537      *
538      * @throws IllegalArgumentException if provider is null
539      */
isProviderEnabled(@onNull String provider)540     public boolean isProviderEnabled(@NonNull String provider) {
541         return isProviderEnabledForUser(provider, Process.myUserHandle());
542     }
543 
544     /**
545      * Returns the current enabled/disabled status of the given provider and user. Callers should
546      * prefer {@link #isLocationEnabledForUser(UserHandle)} unless they depend on provider-specific
547      * APIs.
548      *
549      * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw
550      * {@link SecurityException} if the location permissions were not sufficient to use the
551      * specified provider.
552      *
553      * @param provider a provider listed by {@link #getAllProviders()}
554      * @param userHandle the user to query
555      * @return true if the provider exists and is enabled
556      *
557      * @throws IllegalArgumentException if provider is null
558      * @hide
559      */
560     @SystemApi
isProviderEnabledForUser( @onNull String provider, @NonNull UserHandle userHandle)561     public boolean isProviderEnabledForUser(
562             @NonNull String provider, @NonNull UserHandle userHandle) {
563         Preconditions.checkArgument(provider != null, "invalid null provider");
564 
565         try {
566             return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
567         } catch (RemoteException e) {
568             throw e.rethrowFromSystemServer();
569         }
570     }
571 
572     /**
573      * Method for enabling or disabling a single location provider. This method is deprecated and
574      * functions as a best effort. It should not be relied on in any meaningful sense as providers
575      * may no longer be enabled or disabled by clients.
576      *
577      * @param provider a provider listed by {@link #getAllProviders()}
578      * @param enabled whether to enable or disable the provider
579      * @param userHandle the user to set
580      * @return true if the value was set, false otherwise
581      *
582      * @throws IllegalArgumentException if provider is null
583      * @deprecated Do not manipulate providers individually, use
584      * {@link #setLocationEnabledForUser(boolean, UserHandle)} instead.
585      * @hide
586      */
587     @Deprecated
588     @SystemApi
589     @RequiresPermission(WRITE_SECURE_SETTINGS)
setProviderEnabledForUser( @onNull String provider, boolean enabled, @NonNull UserHandle userHandle)590     public boolean setProviderEnabledForUser(
591             @NonNull String provider, boolean enabled, @NonNull UserHandle userHandle) {
592         Preconditions.checkArgument(provider != null, "invalid null provider");
593 
594         return Settings.Secure.putStringForUser(
595                 mContext.getContentResolver(),
596                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
597                 (enabled ? "+" : "-") + provider,
598                 userHandle.getIdentifier());
599     }
600 
601     /**
602      * Gets the last known location from the fused provider, or null if there is no last known
603      * location. The returned location may be quite old in some circumstances, so the age of the
604      * location should always be checked.
605      *
606      * @return the last known location, or null if not available
607      * @throws SecurityException if no suitable location permission is present
608      *
609      * @hide
610      */
611     @Nullable
612     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
getLastLocation()613     public Location getLastLocation() {
614         try {
615             return mService.getLastLocation(null, mContext.getPackageName(),
616                     mContext.getAttributionTag());
617         } catch (RemoteException e) {
618             throw e.rethrowFromSystemServer();
619         }
620     }
621 
622     /**
623      * Gets the last known location from the given provider, or null if there is no last known
624      * location. The returned location may be quite old in some circumstances, so the age of the
625      * location should always be checked.
626      *
627      * <p>This will never activate sensors to compute a new location, and will only ever return a
628      * cached location.
629      *
630      * <p>See also {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)} which
631      * will always attempt to return a current location, but will potentially use additional power
632      * in the course of the attempt as compared to this method.
633      *
634      * @param provider a provider listed by {@link #getAllProviders()}
635      * @return the last known location for the given provider, or null if not available
636      * @throws SecurityException if no suitable permission is present
637      * @throws IllegalArgumentException if provider is null or doesn't exist
638      */
639     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
640     @Nullable
getLastKnownLocation(@onNull String provider)641     public Location getLastKnownLocation(@NonNull String provider) {
642         Preconditions.checkArgument(provider != null, "invalid null provider");
643 
644         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
645                 provider, 0, 0, true);
646 
647         try {
648             return mService.getLastLocation(request, mContext.getPackageName(),
649                     mContext.getAttributionTag());
650         } catch (RemoteException e) {
651             throw e.rethrowFromSystemServer();
652         }
653     }
654 
655     /**
656      * Asynchronously returns a single current location fix. This may activate sensors in order to
657      * compute a new location, unlike {@link #getLastKnownLocation(String)}, which will only return
658      * a cached fix if available. The given callback will be invoked once and only once, either with
659      * a valid location fix or with a null location fix if the provider was unable to generate a
660      * valid location.
661      *
662      * <p>A client may supply an optional {@link CancellationSignal}. If this is used to cancel the
663      * operation, no callback should be expected after the cancellation.
664      *
665      * <p>This method may return locations from the very recent past (on the order of several
666      * seconds), but will never return older locations (for example, several minutes old or older).
667      * Clients may rely upon the guarantee that if this method returns a location, it will represent
668      * the best estimation of the location of the device in the present moment.
669      *
670      * <p>Clients calling this method from the background may notice that the method fails to
671      * determine a valid location fix more often than while in the foreground. Background
672      * applications may be throttled in their location accesses to some degree.
673      *
674      * @param provider           a provider listed by {@link #getAllProviders()}
675      * @param cancellationSignal an optional signal that allows for cancelling this call
676      * @param executor           the callback will take place on this {@link Executor}
677      * @param consumer           the callback invoked with either a {@link Location} or null
678      *
679      * @throws IllegalArgumentException if provider is null or doesn't exist
680      * @throws IllegalArgumentException if executor is null
681      * @throws IllegalArgumentException if consumer is null
682      * @throws SecurityException        if no suitable permission is present
683      */
684     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
getCurrentLocation(@onNull String provider, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer)685     public void getCurrentLocation(@NonNull String provider,
686             @Nullable CancellationSignal cancellationSignal,
687             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
688         getCurrentLocation(LocationRequest.createFromDeprecatedProvider(provider, 0, 0, true),
689                 cancellationSignal, executor, consumer);
690     }
691 
692     /**
693      * Asynchronously returns a single current location fix based on the given
694      * {@link LocationRequest}.
695      *
696      * <p>See {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)} for more
697      * information.
698      *
699      * @param locationRequest    the location request containing location parameters
700      * @param cancellationSignal an optional signal that allows for cancelling this call
701      * @param executor           the callback will take place on this {@link Executor}
702      * @param consumer           the callback invoked with either a {@link Location} or null
703      *
704      * @throws IllegalArgumentException if provider is null or doesn't exist
705      * @throws IllegalArgumentException if executor is null
706      * @throws IllegalArgumentException if consumer is null
707      * @throws SecurityException        if no suitable permission is present
708      * @hide
709      */
710     @SystemApi
711     @TestApi
712     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
getCurrentLocation(@onNull LocationRequest locationRequest, @Nullable CancellationSignal cancellationSignal, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer)713     public void getCurrentLocation(@NonNull LocationRequest locationRequest,
714             @Nullable CancellationSignal cancellationSignal,
715             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
716         LocationRequest currentLocationRequest = new LocationRequest(locationRequest)
717                 .setNumUpdates(1);
718         if (currentLocationRequest.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
719             currentLocationRequest.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
720         }
721 
722         GetCurrentLocationTransport transport = new GetCurrentLocationTransport(executor,
723                 consumer);
724 
725         if (cancellationSignal != null) {
726             cancellationSignal.throwIfCanceled();
727         }
728 
729         try {
730             ICancellationSignal cancelRemote = mService.getCurrentLocation(
731                     currentLocationRequest, transport, mContext.getPackageName(),
732                     mContext.getAttributionTag(), transport.getListenerId());
733             if (cancelRemote != null) {
734                 transport.register(mContext.getSystemService(AlarmManager.class),
735                         cancellationSignal, cancelRemote);
736                 if (cancellationSignal != null) {
737                     cancellationSignal.setRemote(cancelRemote);
738                 }
739             } else {
740                 transport.fail();
741             }
742         } catch (RemoteException e) {
743             throw e.rethrowFromSystemServer();
744         }
745     }
746 
747     /**
748      * Register for a single location update using the named provider and a callback.
749      *
750      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for
751      * more detail on how to use this method.
752      *
753      * @param provider a provider listed by {@link #getAllProviders()}
754      * @param listener the listener to receive location updates
755      * @param looper   the looper handling listener callbacks, or null to use the looper of the
756      *                 calling thread
757      *
758      * @throws IllegalArgumentException if provider is null or doesn't exist
759      * @throws IllegalArgumentException if listener is null
760      * @throws SecurityException        if no suitable permission is present
761      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
762      * instead as it does not carry a risk of extreme battery drain.
763      */
764     @Deprecated
765     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate( @onNull String provider, @NonNull LocationListener listener, @Nullable Looper looper)766     public void requestSingleUpdate(
767             @NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) {
768         Preconditions.checkArgument(provider != null, "invalid null provider");
769         Preconditions.checkArgument(listener != null, "invalid null listener");
770 
771         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
772                 provider, 0, 0, true);
773         request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
774         requestLocationUpdates(request, listener, looper);
775     }
776 
777     /**
778      * Register for a single location update using a Criteria and a callback.
779      *
780      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
781      * on how to use this method.
782      *
783      * @param criteria contains parameters to choose the appropriate provider for location updates
784      * @param listener the listener to receive location updates
785      * @param looper   the looper handling listener callbacks, or null to use the looper of the
786      *                 calling thread
787      *
788      * @throws IllegalArgumentException if criteria is null
789      * @throws IllegalArgumentException if listener is null
790      * @throws SecurityException        if no suitable permission is present
791      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
792      * instead as it does not carry a risk of extreme battery drain.
793      */
794     @Deprecated
795     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate( @onNull Criteria criteria, @NonNull LocationListener listener, @Nullable Looper looper)796     public void requestSingleUpdate(
797             @NonNull Criteria criteria,
798             @NonNull LocationListener listener,
799             @Nullable Looper looper) {
800         Preconditions.checkArgument(criteria != null, "invalid null criteria");
801         Preconditions.checkArgument(listener != null, "invalid null listener");
802 
803         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
804                 criteria, 0, 0, true);
805         request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
806         requestLocationUpdates(request, listener, looper);
807     }
808 
809     /**
810      * Register for a single location update using a named provider and pending intent.
811      *
812      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
813      * on how to use this method.
814      *
815      * @param provider      a provider listed by {@link #getAllProviders()}
816      * @param pendingIntent the pending intent to send location updates
817      *
818      * @throws IllegalArgumentException if provider is null or doesn't exist
819      * @throws IllegalArgumentException if intent is null
820      * @throws SecurityException        if no suitable permission is present
821      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
822      * instead as it does not carry a risk of extreme battery drain.
823      */
824     @Deprecated
825     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(@onNull String provider, @NonNull PendingIntent pendingIntent)826     public void requestSingleUpdate(@NonNull String provider,
827             @NonNull PendingIntent pendingIntent) {
828         Preconditions.checkArgument(provider != null, "invalid null provider");
829 
830         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
831                 provider, 0, 0, true);
832         request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
833         requestLocationUpdates(request, pendingIntent);
834     }
835 
836     /**
837      * Register for a single location update using a Criteria and pending intent.
838      *
839      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} for more detail
840      * on how to use this method.
841      *
842      * @param criteria      contains parameters to choose the appropriate provider for location
843      *                      updates
844      * @param pendingIntent the pending intent to send location updates
845      *
846      * @throws IllegalArgumentException if provider is null or doesn't exist
847      * @throws IllegalArgumentException if intent is null
848      * @throws SecurityException        if no suitable permission is present
849      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
850      * instead as it does not carry a risk of extreme battery drain.
851      */
852     @Deprecated
853     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestSingleUpdate(@onNull Criteria criteria, @NonNull PendingIntent pendingIntent)854     public void requestSingleUpdate(@NonNull Criteria criteria,
855             @NonNull PendingIntent pendingIntent) {
856         Preconditions.checkArgument(criteria != null, "invalid null criteria");
857 
858         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
859                 criteria, 0, 0, true);
860         request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
861         requestLocationUpdates(request, pendingIntent);
862     }
863 
864     /**
865      * Register for location updates from the given provider with the given arguments. {@link
866      * LocationListener} callbacks will take place on the given {@link Looper} or {@link Executor}.
867      * If a null {@link Looper} is supplied, the Looper of the calling thread will be used instead.
868      * Only one request can be registered for each unique listener, so any subsequent requests with
869      * the same listener will overwrite all associated arguments.
870      *
871      * <p> It may take a while to receive the first location update. If an immediate location is
872      * required, applications may use the {@link #getLastKnownLocation(String)} method.
873      *
874      * <p> The location update interval can be controlled using the minimum time parameter. The
875      * elapsed time between location updates will never be less than this parameter, although it may
876      * be more depending on location availability and other factors. Choosing a sensible value for
877      * the minimum time parameter is important to conserve battery life. Every location update
878      * requires power from a variety of sensors. Select a minimum time parameter as high as possible
879      * while still providing a reasonable user experience. If your application is not in the
880      * foreground and showing location to the user then your application should consider switching
881      * to the {@link #PASSIVE_PROVIDER} instead.
882      *
883      * <p> The minimum distance parameter can also be used to control the frequency of location
884      * updates. If it is greater than 0 then the location provider will only send your application
885      * an update when the location has changed by at least minDistance meters, AND when the minimum
886      * time has elapsed. However it is more difficult for location providers to save power using the
887      * minimum distance parameter, so the minimum time parameter should be the primary tool for
888      * conserving battery life.
889      *
890      * <p> If your application wants to passively observe location updates triggered by other
891      * applications, but not consume any additional power otherwise, then use the {@link
892      * #PASSIVE_PROVIDER}. This provider does not turn on or modify active location providers, so
893      * you do not need to be as careful about minimum time and minimum distance parameters. However,
894      * if your application performs heavy work on a location update (such as network activity) then
895      * you should select non-zero values for the parameters to rate-limit your update frequency in
896      * the case another application enables a location provider with extremely fast updates.
897      *
898      * <p>In case the provider you have selected is disabled, location updates will cease, and a
899      * provider availability update will be sent. As soon as the provider is enabled again, another
900      * provider availability update will be sent and location updates will immediately resume.
901      *
902      * <p> When location callbacks are invoked, the system will hold a wakelock on your
903      * application's behalf for some period of time, but not indefinitely. If your application
904      * requires a long running wakelock within the location callback, you should acquire it
905      * yourself.
906      *
907      * <p class="note"> Prior to Jellybean, the minTime parameter was only a hint, and some location
908      * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
909      * Android compatible devices to observe both the minTime and minDistance parameters.
910      *
911      * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
912      *
913      * @param provider     a provider listed by {@link #getAllProviders()}
914      * @param minTimeMs    minimum time interval between location updates in milliseconds
915      * @param minDistanceM minimum distance between location updates in meters
916      * @param listener     the listener to receive location updates
917      *
918      * @throws IllegalArgumentException if provider is null or doesn't exist
919      * @throws IllegalArgumentException if listener is null
920      * @throws RuntimeException if the calling thread has no Looper
921      * @throws SecurityException if no suitable permission is present
922      */
923     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(@onNull String provider, long minTimeMs, float minDistanceM, @NonNull LocationListener listener)924     public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
925             @NonNull LocationListener listener) {
926         Preconditions.checkArgument(provider != null, "invalid null provider");
927         Preconditions.checkArgument(listener != null, "invalid null listener");
928 
929         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
930                 provider, minTimeMs, minDistanceM, false);
931         requestLocationUpdates(request, listener, null);
932     }
933 
934     /**
935      * Register for location updates using the named provider, and a callback on
936      * the specified {@link Looper}.
937      *
938      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
939      * for more detail on how this method works.
940      *
941      * @param provider     a provider listed by {@link #getAllProviders()}
942      * @param minTimeMs    minimum time interval between location updates in milliseconds
943      * @param minDistanceM minimum distance between location updates in meters
944      * @param listener     the listener to receive location updates
945      * @param looper       the looper handling listener callbacks, or null to use the looper of the
946      *                     calling thread
947      *
948      * @throws IllegalArgumentException if provider is null or doesn't exist
949      * @throws IllegalArgumentException if listener is null
950      * @throws SecurityException if no suitable permission is present
951      */
952     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(@onNull String provider, long minTimeMs, float minDistanceM, @NonNull LocationListener listener, @Nullable Looper looper)953     public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
954             @NonNull LocationListener listener, @Nullable Looper looper) {
955         Preconditions.checkArgument(provider != null, "invalid null provider");
956         Preconditions.checkArgument(listener != null, "invalid null listener");
957 
958         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
959                 provider, minTimeMs, minDistanceM, false);
960         requestLocationUpdates(request, listener, looper);
961     }
962 
963     /**
964      * Register for location updates using the named provider, and a callback on
965      * the specified {@link Executor}.
966      *
967      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
968      * for more detail on how this method works.
969      *
970      * @param provider     a provider listed by {@link #getAllProviders()}
971      * @param minTimeMs    minimum time interval between location updates in milliseconds
972      * @param minDistanceM minimum distance between location updates in meters
973      * @param executor     the executor handling listener callbacks
974      * @param listener     the listener to receive location updates
975      *
976      * @throws IllegalArgumentException if provider is null or doesn't exist
977      * @throws IllegalArgumentException if executor is null
978      * @throws IllegalArgumentException if listener is null
979      * @throws SecurityException if no suitable permission is present
980      */
981     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates( @onNull String provider, long minTimeMs, float minDistanceM, @NonNull @CallbackExecutor Executor executor, @NonNull LocationListener listener)982     public void requestLocationUpdates(
983             @NonNull String provider,
984             long minTimeMs,
985             float minDistanceM,
986             @NonNull @CallbackExecutor Executor executor,
987             @NonNull LocationListener listener) {
988         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
989                 provider, minTimeMs, minDistanceM, false);
990         requestLocationUpdates(request, executor, listener);
991     }
992 
993     /**
994      * Register for location updates using a provider selected through the given Criteria, and a
995      * callback on the specified {@link Looper}.
996      *
997      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
998      * for more detail on how this method works.
999      *
1000      * @param minTimeMs minimum time interval between location updates in milliseconds
1001      * @param minDistanceM minimum distance between location updates in meters
1002      * @param criteria contains parameters to choose the appropriate provider for location updates
1003      * @param listener the listener to receive location updates
1004      *
1005      * @throws IllegalArgumentException if criteria is null
1006      * @throws IllegalArgumentException if listener is null
1007      * @throws SecurityException if no suitable permission is present
1008      */
1009     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(long minTimeMs, float minDistanceM, @NonNull Criteria criteria, @NonNull LocationListener listener, @Nullable Looper looper)1010     public void requestLocationUpdates(long minTimeMs, float minDistanceM,
1011             @NonNull Criteria criteria, @NonNull LocationListener listener,
1012             @Nullable Looper looper) {
1013         Preconditions.checkArgument(criteria != null, "invalid null criteria");
1014         Preconditions.checkArgument(listener != null, "invalid null listener");
1015 
1016         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
1017                 criteria, minTimeMs, minDistanceM, false);
1018         requestLocationUpdates(request, listener, looper);
1019     }
1020 
1021     /**
1022      * Register for location updates using a provider selected through the given Criteria, and a
1023      * callback on the specified {@link Executor}.
1024      *
1025      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
1026      * for more detail on how this method works.
1027      *
1028      * @param minTimeMs minimum time interval between location updates in milliseconds
1029      * @param minDistanceM minimum distance between location updates in meters
1030      * @param criteria contains parameters to choose the appropriate provider for location updates
1031      * @param executor the executor handling listener callbacks
1032      * @param listener the listener to receive location updates
1033      *
1034      * @throws IllegalArgumentException if criteria is null
1035      * @throws IllegalArgumentException if executor is null
1036      * @throws IllegalArgumentException if listener is null
1037      * @throws SecurityException        if no suitable permission is present
1038      */
1039     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates( long minTimeMs, float minDistanceM, @NonNull Criteria criteria, @NonNull @CallbackExecutor Executor executor, @NonNull LocationListener listener)1040     public void requestLocationUpdates(
1041             long minTimeMs,
1042             float minDistanceM,
1043             @NonNull Criteria criteria,
1044             @NonNull @CallbackExecutor Executor executor,
1045             @NonNull LocationListener listener) {
1046         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
1047                 criteria, minTimeMs, minDistanceM, false);
1048         requestLocationUpdates(request, executor, listener);
1049     }
1050 
1051     /**
1052      * Register for location updates using the named provider, and callbacks delivered via the
1053      * provided {@link PendingIntent}.
1054      *
1055      * <p>The delivered pending intents will contain extras with the callback information. The keys
1056      * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
1057      * the documentation for each respective extra key for information on the values.
1058      *
1059      * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
1060      *
1061      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
1062      * for more detail on how this method works.
1063      *
1064      * @param provider      a provider listed by {@link #getAllProviders()}
1065      * @param minTimeMs     minimum time interval between location updates in milliseconds
1066      * @param minDistanceM  minimum distance between location updates in meters
1067      * @param pendingIntent the pending intent to send location updates
1068      *
1069      * @throws IllegalArgumentException if provider is null or doesn't exist
1070      * @throws IllegalArgumentException if pendingIntent is null
1071      * @throws SecurityException if no suitable permission is present
1072      */
1073     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(@onNull String provider, long minTimeMs, float minDistanceM, @NonNull PendingIntent pendingIntent)1074     public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
1075             @NonNull PendingIntent pendingIntent) {
1076         Preconditions.checkArgument(provider != null, "invalid null provider");
1077 
1078         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
1079                 provider, minTimeMs, minDistanceM, false);
1080         requestLocationUpdates(request, pendingIntent);
1081     }
1082 
1083     /**
1084      * Register for location updates using a provider selected through the given Criteria, and
1085      * callbacks delivered via the provided {@link PendingIntent}.
1086      *
1087      * <p>See {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on
1088      * how this method works.
1089      *
1090      * @param minTimeMs minimum time interval between location updates in milliseconds
1091      * @param minDistanceM minimum distance between location updates in meters
1092      * @param criteria contains parameters to choose the appropriate provider for location updates
1093      * @param pendingIntent the pending intent to send location updates
1094      *
1095      * @throws IllegalArgumentException if provider is null or doesn't exist
1096      * @throws IllegalArgumentException if pendingIntent is null
1097      * @throws SecurityException if no suitable permission is present
1098      */
1099     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates(long minTimeMs, float minDistanceM, @NonNull Criteria criteria, @NonNull PendingIntent pendingIntent)1100     public void requestLocationUpdates(long minTimeMs, float minDistanceM,
1101             @NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
1102         Preconditions.checkArgument(criteria != null, "invalid null criteria");
1103 
1104         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
1105                 criteria, minTimeMs, minDistanceM, false);
1106         requestLocationUpdates(request, pendingIntent);
1107     }
1108 
1109     /**
1110      * Register for location updates using a {@link LocationRequest}, and a callback on the
1111      * specified {@link Looper}.
1112      *
1113      * <p>The system will automatically select and enable the best provider based on the given
1114      * {@link LocationRequest}. The LocationRequest can be null, in which case the system will
1115      * choose default low power parameters for location updates, but this is heavily discouraged,
1116      * and an explicit LocationRequest should always be provided.
1117      *
1118      * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
1119      * for more detail on how this method works.
1120      *
1121      * @param locationRequest the location request containing location parameters
1122      * @param listener the listener to receive location updates
1123      * @param looper the looper handling listener callbacks, or null to use the looper of the
1124      *               calling thread
1125      *
1126      * @throws IllegalArgumentException if listener is null
1127      * @throws SecurityException if no suitable permission is present
1128      *
1129      * @hide
1130      */
1131     @SystemApi
1132     @TestApi
1133     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates( @ullable LocationRequest locationRequest, @NonNull LocationListener listener, @Nullable Looper looper)1134     public void requestLocationUpdates(
1135             @Nullable LocationRequest locationRequest,
1136             @NonNull LocationListener listener,
1137             @Nullable Looper looper) {
1138         Handler handler = looper == null ? new Handler() : new Handler(looper);
1139         requestLocationUpdates(locationRequest, new HandlerExecutor(handler), listener);
1140     }
1141 
1142     /**
1143      * Register for location updates using a {@link LocationRequest}, and a callback on the
1144      * specified {@link Executor}.
1145      *
1146      * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} for more
1147      * detail on how this method works.
1148      *
1149      * @param locationRequest the location request containing location parameters
1150      * @param executor the executor handling listener callbacks
1151      * @param listener the listener to receive location updates
1152      *
1153      * @throws IllegalArgumentException if executor is null
1154      * @throws IllegalArgumentException if listener is null
1155      * @throws SecurityException if no suitable permission is present
1156      *
1157      * @hide
1158      */
1159     @SystemApi
1160     @TestApi
1161     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates( @ullable LocationRequest locationRequest, @NonNull @CallbackExecutor Executor executor, @NonNull LocationListener listener)1162     public void requestLocationUpdates(
1163             @Nullable LocationRequest locationRequest,
1164             @NonNull @CallbackExecutor Executor executor,
1165             @NonNull LocationListener listener) {
1166         synchronized (mListeners) {
1167             LocationListenerTransport transport = mListeners.get(listener);
1168             if (transport != null) {
1169                 transport.unregister();
1170             } else {
1171                 transport = new LocationListenerTransport(listener);
1172                 mListeners.put(listener, transport);
1173             }
1174             transport.register(executor);
1175 
1176             boolean registered = false;
1177             try {
1178                 mService.requestLocationUpdates(locationRequest, transport, null,
1179                         mContext.getPackageName(), mContext.getAttributionTag(),
1180                         transport.getListenerId());
1181                 registered = true;
1182             } catch (RemoteException e) {
1183                 throw e.rethrowFromSystemServer();
1184             } finally {
1185                 if (!registered) {
1186                     // allow gc after exception
1187                     transport.unregister();
1188                     mListeners.remove(listener);
1189                 }
1190             }
1191         }
1192     }
1193 
1194     /**
1195      * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
1196      * the provided {@link PendingIntent}.
1197      *
1198      * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} and
1199      * {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on how
1200      * this method works.
1201      *
1202      * @param locationRequest the location request containing location parameters
1203      * @param pendingIntent the pending intent to send location updates
1204      *
1205      * @throws IllegalArgumentException if pendingIntent is null
1206      * @throws SecurityException if no suitable permission is present
1207      *
1208      * @hide
1209      */
1210     @SystemApi
1211     @TestApi
1212     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
requestLocationUpdates( @ullable LocationRequest locationRequest, @NonNull PendingIntent pendingIntent)1213     public void requestLocationUpdates(
1214             @Nullable LocationRequest locationRequest,
1215             @NonNull PendingIntent pendingIntent) {
1216         Preconditions.checkArgument(locationRequest != null, "invalid null location request");
1217         Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
1218         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1219             Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
1220                     "pending intent must be targeted to a package");
1221         }
1222 
1223         try {
1224             mService.requestLocationUpdates(locationRequest, null, pendingIntent,
1225                     mContext.getPackageName(), mContext.getAttributionTag(), null);
1226         } catch (RemoteException e) {
1227             throw e.rethrowFromSystemServer();
1228         }
1229     }
1230 
1231     /**
1232      * Set the last known location with a new location.
1233      *
1234      * <p>A privileged client can inject a {@link Location} if it has a better estimate of what
1235      * the recent location is.  This is especially useful when the device boots up and the GPS
1236      * chipset is in the process of getting the first fix.  If the client has cached the location,
1237      * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link
1238      * #getLastKnownLocation(String)}, the location information is still useful before getting
1239      * the first fix.
1240      *
1241      * @param location newly available {@link Location} object
1242      * @return true if the location was injected, false otherwise
1243      *
1244      * @throws IllegalArgumentException if location is null
1245      * @throws SecurityException if permissions are not present
1246      *
1247      * @hide
1248      */
1249     @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION})
injectLocation(@onNull Location location)1250     public boolean injectLocation(@NonNull Location location) {
1251         Preconditions.checkArgument(location != null, "invalid null location");
1252         Preconditions.checkArgument(location.isComplete(),
1253                 "incomplete location object, missing timestamp or accuracy?");
1254 
1255         try {
1256             mService.injectLocation(location);
1257             return true;
1258         } catch (RemoteException e) {
1259             throw e.rethrowFromSystemServer();
1260         }
1261     }
1262 
1263     /**
1264      * Removes location updates for the specified {@link LocationListener}. Following this call,
1265      * the listener will no longer receive location updates.
1266      *
1267      * @param listener listener that no longer needs location updates
1268      *
1269      * @throws IllegalArgumentException if listener is null
1270      */
removeUpdates(@onNull LocationListener listener)1271     public void removeUpdates(@NonNull LocationListener listener) {
1272         Preconditions.checkArgument(listener != null, "invalid null listener");
1273 
1274         synchronized (mListeners) {
1275             LocationListenerTransport transport = mListeners.remove(listener);
1276             if (transport == null) {
1277                 return;
1278             }
1279             transport.unregister();
1280 
1281             try {
1282                 mService.removeUpdates(transport, null);
1283             } catch (RemoteException e) {
1284                 throw e.rethrowFromSystemServer();
1285             }
1286         }
1287     }
1288 
1289     /**
1290      * Removes location updates for the specified {@link PendingIntent}. Following this call, the
1291      * PendingIntent will no longer receive location updates.
1292      *
1293      * @param pendingIntent pending intent that no longer needs location updates
1294      *
1295      * @throws IllegalArgumentException if pendingIntent is null
1296      */
removeUpdates(@onNull PendingIntent pendingIntent)1297     public void removeUpdates(@NonNull PendingIntent pendingIntent) {
1298         Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
1299 
1300         try {
1301             mService.removeUpdates(null, pendingIntent);
1302         } catch (RemoteException e) {
1303             throw e.rethrowFromSystemServer();
1304         }
1305     }
1306 
1307     /**
1308      * Returns a list of the names of all known location providers. All providers are returned,
1309      * including ones that are not permitted to be accessed by the calling activity or are currently
1310      * disabled.
1311      *
1312      * @return list of provider names
1313      */
getAllProviders()1314     public @NonNull List<String> getAllProviders() {
1315         try {
1316             return mService.getAllProviders();
1317         } catch (RemoteException e) {
1318             throw e.rethrowFromSystemServer();
1319         }
1320     }
1321 
1322     /**
1323      * Returns a list of the names of location providers. Only providers that the caller has
1324      * permission to access will be returned.
1325      *
1326      * @param enabledOnly if true then only enabled providers are included
1327      * @return list of provider names
1328      */
getProviders(boolean enabledOnly)1329     public @NonNull List<String> getProviders(boolean enabledOnly) {
1330         try {
1331             return mService.getProviders(null, enabledOnly);
1332         } catch (RemoteException e) {
1333             throw e.rethrowFromSystemServer();
1334         }
1335     }
1336 
1337     /**
1338      * Returns a list of the names of providers that satisfy the given criteria. Only providers that
1339      * the caller has permission to access will be returned.
1340      *
1341      * @param criteria the criteria that providers must match
1342      * @param enabledOnly if true then only enabled providers are included
1343      * @return list of provider names
1344      *
1345      * @throws IllegalArgumentException if criteria is null
1346      */
getProviders(@onNull Criteria criteria, boolean enabledOnly)1347     public @NonNull List<String> getProviders(@NonNull Criteria criteria, boolean enabledOnly) {
1348         Preconditions.checkArgument(criteria != null, "invalid null criteria");
1349 
1350         try {
1351             return mService.getProviders(criteria, enabledOnly);
1352         } catch (RemoteException e) {
1353             throw e.rethrowFromSystemServer();
1354         }
1355     }
1356 
1357     /**
1358      * Returns the name of the provider that best meets the given criteria. Only providers that are
1359      * permitted to be accessed by the caller will be returned. If several providers meet the
1360      * criteria, the one with the best accuracy is returned. If no provider meets the criteria, the
1361      * criteria are loosened in the following order:
1362      *
1363      * <ul>
1364      * <li> power requirement
1365      * <li> accuracy
1366      * <li> bearing
1367      * <li> speed
1368      * <li> altitude
1369      * </ul>
1370      *
1371      * <p> Note that the requirement on monetary cost is not removed in this process.
1372      *
1373      * @param criteria the criteria that need to be matched
1374      * @param enabledOnly if true then only enabled providers are included
1375      * @return name of the provider that best matches the criteria, or null if none match
1376      *
1377      * @throws IllegalArgumentException if criteria is null
1378      */
getBestProvider(@onNull Criteria criteria, boolean enabledOnly)1379     public @Nullable String getBestProvider(@NonNull Criteria criteria, boolean enabledOnly) {
1380         Preconditions.checkArgument(criteria != null, "invalid null criteria");
1381 
1382         try {
1383             return mService.getBestProvider(criteria, enabledOnly);
1384         } catch (RemoteException e) {
1385             throw e.rethrowFromSystemServer();
1386         }
1387     }
1388 
1389     /**
1390      * Returns the information about the location provider with the given name, or null if no
1391      * provider exists by that name.
1392      *
1393      * @param provider a provider listed by {@link #getAllProviders()}
1394      * @return location provider information, or null if provider does not exist
1395      *
1396      * @throws IllegalArgumentException if provider is null
1397      */
getProvider(@onNull String provider)1398     public @Nullable LocationProvider getProvider(@NonNull String provider) {
1399         Preconditions.checkArgument(provider != null, "invalid null provider");
1400 
1401         if (!Compatibility.isChangeEnabled(GET_PROVIDER_SECURITY_EXCEPTIONS)) {
1402             if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
1403                 try {
1404                     mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(),
1405                             Process.myUid(), null);
1406                 } catch (SecurityException e) {
1407                     mContext.enforcePermission(ACCESS_COARSE_LOCATION, Process.myPid(),
1408                             Process.myUid(), null);
1409                 }
1410             } else {
1411                 mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(), Process.myUid(),
1412                         null);
1413             }
1414         }
1415 
1416         try {
1417             ProviderProperties properties = mService.getProviderProperties(provider);
1418             if (properties == null) {
1419                 return null;
1420             }
1421             return new LocationProvider(provider, properties);
1422         } catch (RemoteException e) {
1423             throw e.rethrowFromSystemServer();
1424         }
1425     }
1426 
1427     /**
1428      * Returns true if the given package name matches a location provider package, and false
1429      * otherwise.
1430      *
1431      * @hide
1432      */
1433     @SystemApi
1434     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
isProviderPackage(@onNull String packageName)1435     public boolean isProviderPackage(@NonNull String packageName) {
1436         try {
1437             return mService.isProviderPackage(packageName);
1438         } catch (RemoteException e) {
1439             e.rethrowFromSystemServer();
1440             return false;
1441         }
1442     }
1443 
1444     /**
1445      * Returns a list of packages associated with the given provider,
1446      * and an empty list if no package is associated with the provider.
1447      *
1448      * @hide
1449      */
1450     @TestApi
1451     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
1452     @Nullable
getProviderPackages(@onNull String provider)1453     public List<String> getProviderPackages(@NonNull String provider) {
1454         try {
1455             return mService.getProviderPackages(provider);
1456         } catch (RemoteException e) {
1457             e.rethrowFromSystemServer();
1458             return Collections.emptyList();
1459         }
1460     }
1461 
1462     /**
1463      * Sends additional commands to a location provider. Can be used to support provider specific
1464      * extensions to the Location Manager API.
1465      *
1466      * @param provider a provider listed by {@link #getAllProviders()}
1467      * @param command  name of the command to send to the provider
1468      * @param extras   optional arguments for the command, or null
1469      * @return true always, the return value may be ignored
1470      */
sendExtraCommand( @onNull String provider, @NonNull String command, @Nullable Bundle extras)1471     public boolean sendExtraCommand(
1472             @NonNull String provider, @NonNull String command, @Nullable Bundle extras) {
1473         Preconditions.checkArgument(provider != null, "invalid null provider");
1474         Preconditions.checkArgument(command != null, "invalid null command");
1475 
1476         try {
1477             return mService.sendExtraCommand(provider, command, extras);
1478         } catch (RemoteException e) {
1479             throw e.rethrowFromSystemServer();
1480         }
1481     }
1482 
1483     /**
1484      * Creates a test location provider and adds it to the set of active providers. This provider
1485      * will replace any provider with the same name that exists prior to this call.
1486      *
1487      * @param provider the provider name
1488      *
1489      * @throws IllegalArgumentException if provider is null
1490      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1491      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1492      * allowed} for your app.
1493      */
addTestProvider( @onNull String provider, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy)1494     public void addTestProvider(
1495             @NonNull String provider, boolean requiresNetwork, boolean requiresSatellite,
1496             boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1497             boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1498         Preconditions.checkArgument(provider != null, "invalid null provider");
1499 
1500         ProviderProperties properties = new ProviderProperties(requiresNetwork,
1501                 requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
1502                 supportsBearing, powerRequirement, accuracy);
1503         try {
1504             mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
1505                     mContext.getAttributionTag());
1506         } catch (RemoteException e) {
1507             throw e.rethrowFromSystemServer();
1508         }
1509     }
1510 
1511     /**
1512      * Removes the test location provider with the given name or does nothing if no such test
1513      * location provider exists.
1514      *
1515      * @param provider the provider name
1516      *
1517      * @throws IllegalArgumentException if provider is null
1518      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1519      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1520      * allowed} for your app.
1521      */
removeTestProvider(@onNull String provider)1522     public void removeTestProvider(@NonNull String provider) {
1523         Preconditions.checkArgument(provider != null, "invalid null provider");
1524 
1525         try {
1526             mService.removeTestProvider(provider, mContext.getOpPackageName(),
1527                     mContext.getAttributionTag());
1528         } catch (RemoteException e) {
1529             throw e.rethrowFromSystemServer();
1530         }
1531     }
1532 
1533     /**
1534      * Sets a new location for the given test provider. This location will be identiable as a mock
1535      * location to all clients via {@link Location#isFromMockProvider()}.
1536      *
1537      * <p>The location object must have a minimum number of fields set to be considered valid, as
1538      * per documentation on {@link Location} class.
1539      *
1540      * @param provider the provider name
1541      * @param location the mock location
1542      *
1543      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
1544      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
1545      * allowed} for your app.
1546      * @throws IllegalArgumentException if the provider is null or not a test provider
1547      * @throws IllegalArgumentException if the location is null or incomplete
1548      */
setTestProviderLocation(@onNull String provider, @NonNull Location location)1549     public void setTestProviderLocation(@NonNull String provider, @NonNull Location location) {
1550         Preconditions.checkArgument(provider != null, "invalid null provider");
1551         Preconditions.checkArgument(location != null, "invalid null location");
1552 
1553         if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
1554             Preconditions.checkArgument(location.isComplete(),
1555                     "incomplete location object, missing timestamp or accuracy?");
1556         } else {
1557             location.makeComplete();
1558         }
1559 
1560         try {
1561             mService.setTestProviderLocation(provider, location, mContext.getOpPackageName(),
1562                     mContext.getAttributionTag());
1563         } catch (RemoteException e) {
1564             throw e.rethrowFromSystemServer();
1565         }
1566     }
1567 
1568     /**
1569      * Does nothing.
1570      *
1571      * @deprecated This method has always been a no-op, and may be removed in the future.
1572      */
1573     @Deprecated
clearTestProviderLocation(@onNull String provider)1574     public void clearTestProviderLocation(@NonNull String provider) {}
1575 
1576     /**
1577      * Sets the given test provider to be enabled or disabled.
1578      *
1579      * @param provider the provider name
1580      * @param enabled the mock enabled value
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 provider is null or not a test provider
1586      */
setTestProviderEnabled(@onNull String provider, boolean enabled)1587     public void setTestProviderEnabled(@NonNull String provider, boolean enabled) {
1588         Preconditions.checkArgument(provider != null, "invalid null provider");
1589 
1590         try {
1591             mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName(),
1592                     mContext.getAttributionTag());
1593         } catch (RemoteException e) {
1594             throw e.rethrowFromSystemServer();
1595         }
1596     }
1597 
1598     /**
1599      * Equivalent to calling {@link #setTestProviderEnabled(String, boolean)} to disable a test
1600      * provider.
1601      *
1602      * @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
1603      */
1604     @Deprecated
clearTestProviderEnabled(@onNull String provider)1605     public void clearTestProviderEnabled(@NonNull String provider) {
1606         setTestProviderEnabled(provider, false);
1607     }
1608 
1609     /**
1610      * This method has no effect as provider status has been deprecated and is no longer supported.
1611      *
1612      * @deprecated This method has no effect.
1613      */
1614     @Deprecated
setTestProviderStatus( @onNull String provider, int status, @Nullable Bundle extras, long updateTime)1615     public void setTestProviderStatus(
1616             @NonNull String provider, int status, @Nullable Bundle extras, long updateTime) {}
1617 
1618     /**
1619      * This method has no effect as provider status has been deprecated and is no longer supported.
1620      *
1621      * @deprecated This method has no effect.
1622      */
1623     @Deprecated
clearTestProviderStatus(@onNull String provider)1624     public void clearTestProviderStatus(@NonNull String provider) {}
1625 
1626     /**
1627      * Get the last list of {@link LocationRequest}s sent to the provider.
1628      *
1629      * @hide
1630      */
1631     @TestApi
1632     @NonNull
getTestProviderCurrentRequests(String providerName)1633     public List<LocationRequest> getTestProviderCurrentRequests(String providerName) {
1634         Preconditions.checkArgument(providerName != null, "invalid null provider");
1635         try {
1636             return mService.getTestProviderCurrentRequests(providerName);
1637         } catch (RemoteException e) {
1638             throw e.rethrowFromSystemServer();
1639         }
1640     }
1641 
1642     /**
1643      * Set a proximity alert for the location given by the position
1644      * (latitude, longitude) and the given radius.
1645      *
1646      * <p> When the device
1647      * detects that it has entered or exited the area surrounding the
1648      * location, the given PendingIntent will be used to create an Intent
1649      * to be fired.
1650      *
1651      * <p> The fired Intent will have a boolean extra added with key
1652      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
1653      * entering the proximity region; if false, it is exiting.
1654      *
1655      * <p> Due to the approximate nature of position estimation, if the
1656      * device passes through the given area briefly, it is possible
1657      * that no Intent will be fired.  Similarly, an Intent could be
1658      * fired if the device passes very close to the given area but
1659      * does not actually enter it.
1660      *
1661      * <p> After the number of milliseconds given by the expiration
1662      * parameter, the location manager will delete this proximity
1663      * alert and no longer monitor it.  A value of -1 indicates that
1664      * there should be no expiration time.
1665      *
1666      * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
1667      * and {@link #GPS_PROVIDER}.
1668      *
1669      * <p>Before API version 17, this method could be used with
1670      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
1671      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
1672      * From API version 17 and onwards, this method requires
1673      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
1674      *
1675      * @param latitude the latitude of the central point of the
1676      * alert region
1677      * @param longitude the longitude of the central point of the
1678      * alert region
1679      * @param radius the radius of the central point of the
1680      * alert region, in meters
1681      * @param expiration time for this proximity alert, in milliseconds,
1682      * or -1 to indicate no expiration
1683      * @param intent a PendingIntent that will be used to generate an Intent to
1684      * fire when entry to or exit from the alert region is detected
1685      *
1686      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1687      * permission is not present
1688      */
1689     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
addProximityAlert(double latitude, double longitude, float radius, long expiration, @NonNull PendingIntent intent)1690     public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
1691             @NonNull PendingIntent intent) {
1692         Preconditions.checkArgument(intent != null, "invalid null pending intent");
1693         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1694             Preconditions.checkArgument(intent.isTargetedToPackage(),
1695                     "pending intent must be targeted to a package");
1696         }
1697         if (expiration < 0) expiration = Long.MAX_VALUE;
1698 
1699         Geofence fence = Geofence.createCircle(latitude, longitude, radius);
1700         LocationRequest request = new LocationRequest().setExpireIn(expiration);
1701         try {
1702             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
1703                     mContext.getAttributionTag());
1704         } catch (RemoteException e) {
1705             throw e.rethrowFromSystemServer();
1706         }
1707     }
1708 
1709     /**
1710      * Removes the proximity alert with the given PendingIntent.
1711      *
1712      * <p>Before API version 17, this method could be used with
1713      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
1714      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
1715      * From API version 17 and onwards, this method requires
1716      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
1717      *
1718      * @param intent the PendingIntent that no longer needs to be notified of
1719      * proximity alerts
1720      *
1721      * @throws IllegalArgumentException if intent is null
1722      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1723      * permission is not present
1724      */
removeProximityAlert(@onNull PendingIntent intent)1725     public void removeProximityAlert(@NonNull PendingIntent intent) {
1726         Preconditions.checkArgument(intent != null, "invalid null pending intent");
1727         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1728             Preconditions.checkArgument(intent.isTargetedToPackage(),
1729                     "pending intent must be targeted to a package");
1730         }
1731 
1732         try {
1733             mService.removeGeofence(null, intent, mContext.getPackageName());
1734         } catch (RemoteException e) {
1735             throw e.rethrowFromSystemServer();
1736         }
1737     }
1738 
1739     /**
1740      * Add a geofence with the specified LocationRequest quality of service.
1741      *
1742      * <p> When the device
1743      * detects that it has entered or exited the area surrounding the
1744      * location, the given PendingIntent will be used to create an Intent
1745      * to be fired.
1746      *
1747      * <p> The fired Intent will have a boolean extra added with key
1748      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
1749      * entering the proximity region; if false, it is exiting.
1750      *
1751      * <p> The geofence engine fuses results from all location providers to
1752      * provide the best balance between accuracy and power. Applications
1753      * can choose the quality of service required using the
1754      * {@link LocationRequest} object. If it is null then a default,
1755      * low power geo-fencing implementation is used. It is possible to cross
1756      * a geo-fence without notification, but the system will do its best
1757      * to detect, using {@link LocationRequest} as a hint to trade-off
1758      * accuracy and power.
1759      *
1760      * <p> The power required by the geofence engine can depend on many factors,
1761      * such as quality and interval requested in {@link LocationRequest},
1762      * distance to nearest geofence and current device velocity.
1763      *
1764      * @param request quality of service required, null for default low power
1765      * @param fence a geographical description of the geofence area
1766      * @param intent pending intent to receive geofence updates
1767      *
1768      * @throws IllegalArgumentException if fence is null
1769      * @throws IllegalArgumentException if intent is null
1770      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1771      * permission is not present
1772      *
1773      * @hide
1774      */
1775     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
addGeofence( @onNull LocationRequest request, @NonNull Geofence fence, @NonNull PendingIntent intent)1776     public void addGeofence(
1777             @NonNull LocationRequest request,
1778             @NonNull Geofence fence,
1779             @NonNull PendingIntent intent) {
1780         Preconditions.checkArgument(request != null, "invalid null location request");
1781         Preconditions.checkArgument(fence != null, "invalid null geofence");
1782         Preconditions.checkArgument(intent != null, "invalid null pending intent");
1783         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1784             Preconditions.checkArgument(intent.isTargetedToPackage(),
1785                     "pending intent must be targeted to a package");
1786         }
1787 
1788         try {
1789             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
1790                     mContext.getAttributionTag());
1791         } catch (RemoteException e) {
1792             throw e.rethrowFromSystemServer();
1793         }
1794     }
1795 
1796     /**
1797      * Remove a single geofence.
1798      *
1799      * <p>This removes only the specified geofence associated with the
1800      * specified pending intent. All other geofences remain unchanged.
1801      *
1802      * @param fence a geofence previously passed to {@link #addGeofence}
1803      * @param intent a pending intent previously passed to {@link #addGeofence}
1804      *
1805      * @throws IllegalArgumentException if fence is null
1806      * @throws IllegalArgumentException if intent is null
1807      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1808      * permission is not present
1809      *
1810      * @hide
1811      */
removeGeofence(@onNull Geofence fence, @NonNull PendingIntent intent)1812     public void removeGeofence(@NonNull Geofence fence, @NonNull PendingIntent intent) {
1813         Preconditions.checkArgument(fence != null, "invalid null geofence");
1814         Preconditions.checkArgument(intent != null, "invalid null pending intent");
1815         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1816             Preconditions.checkArgument(intent.isTargetedToPackage(),
1817                     "pending intent must be targeted to a package");
1818         }
1819 
1820         try {
1821             mService.removeGeofence(fence, intent, mContext.getPackageName());
1822         } catch (RemoteException e) {
1823             throw e.rethrowFromSystemServer();
1824         }
1825     }
1826 
1827     /**
1828      * Remove all geofences registered to the specified pending intent.
1829      *
1830      * @param intent a pending intent previously passed to {@link #addGeofence}
1831      *
1832      * @throws IllegalArgumentException if intent is null
1833      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
1834      * permission is not present
1835      *
1836      * @hide
1837      */
removeAllGeofences(@onNull PendingIntent intent)1838     public void removeAllGeofences(@NonNull PendingIntent intent) {
1839         Preconditions.checkArgument(intent != null, "invalid null pending intent");
1840         if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
1841             Preconditions.checkArgument(intent.isTargetedToPackage(),
1842                     "pending intent must be targeted to a package");
1843         }
1844 
1845         try {
1846             mService.removeGeofence(null, intent, mContext.getPackageName());
1847         } catch (RemoteException e) {
1848             throw e.rethrowFromSystemServer();
1849         }
1850     }
1851 
1852     // ================= GNSS APIs =================
1853 
1854     /**
1855      * Returns the supported capabilities of the GNSS chipset.
1856      */
getGnssCapabilities()1857     public @NonNull GnssCapabilities getGnssCapabilities() {
1858         try {
1859             long gnssCapabilities = mService.getGnssCapabilities();
1860             if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) {
1861                 gnssCapabilities = 0L;
1862             }
1863             return GnssCapabilities.of(gnssCapabilities);
1864         } catch (RemoteException e) {
1865             throw e.rethrowFromSystemServer();
1866         }
1867     }
1868 
1869     /**
1870      * Returns the model year of the GNSS hardware and software build. More details, such as build
1871      * date, may be available in {@link #getGnssHardwareModelName()}. May return 0 if the model year
1872      * is less than 2016.
1873      */
getGnssYearOfHardware()1874     public int getGnssYearOfHardware() {
1875         try {
1876             return mService.getGnssYearOfHardware();
1877         } catch (RemoteException e) {
1878             throw e.rethrowFromSystemServer();
1879         }
1880     }
1881 
1882     /**
1883      * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware
1884      * driver.
1885      *
1886      * <p> No device-specific serial number or ID is returned from this API.
1887      *
1888      * <p> Will return null when the GNSS hardware abstraction layer does not support providing
1889      * this value.
1890      */
1891     @Nullable
getGnssHardwareModelName()1892     public String getGnssHardwareModelName() {
1893         try {
1894             return mService.getGnssHardwareModelName();
1895         } catch (RemoteException e) {
1896             throw e.rethrowFromSystemServer();
1897         }
1898     }
1899 
1900     /**
1901      * Retrieves information about the current status of the GPS engine. This should only be called
1902      * from within the {@link GpsStatus.Listener#onGpsStatusChanged} callback to ensure that the
1903      * data is copied atomically.
1904      *
1905      * The caller may either pass in an existing {@link GpsStatus} object to be overwritten, or pass
1906      * null to create a new {@link GpsStatus} object.
1907      *
1908      * @param status object containing GPS status details, or null.
1909      * @return status object containing updated GPS status.
1910      *
1911      * @deprecated GpsStatus APIs are deprecated, use {@link GnssStatus} APIs instead. No longer
1912      * supported in apps targeting S and above.
1913      */
1914     @Deprecated
1915     @RequiresPermission(ACCESS_FINE_LOCATION)
getGpsStatus(@ullable GpsStatus status)1916     public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
1917         if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
1918             throw new UnsupportedOperationException(
1919                     "GpsStatus APIs not supported, please use GnssStatus APIs instead");
1920         }
1921 
1922         GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus();
1923         int ttff = mGnssStatusListenerManager.getTtff();
1924 
1925         // even though this method is marked nullable, there are legacy applications that expect
1926         // this to never return null, so avoid breaking those apps
1927         if (gnssStatus != null) {
1928             if (status == null) {
1929                 status = GpsStatus.create(gnssStatus, ttff);
1930             } else {
1931                 status.setStatus(gnssStatus, ttff);
1932             }
1933         } else if (status == null) {
1934             status = GpsStatus.createEmpty();
1935         }
1936         return status;
1937     }
1938 
1939     /**
1940      * Adds a GPS status listener.
1941      *
1942      * @param listener GPS status listener object to register
1943      * @return true if the listener was successfully added
1944      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1945      *
1946      * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead. No longer
1947      * supported in apps targeting S and above.
1948      */
1949     @Deprecated
1950     @RequiresPermission(ACCESS_FINE_LOCATION)
addGpsStatusListener(GpsStatus.Listener listener)1951     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
1952         if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
1953             throw new UnsupportedOperationException(
1954                     "GpsStatus APIs not supported, please use GnssStatus APIs instead");
1955         }
1956 
1957         try {
1958             return mGnssStatusListenerManager.addListener(listener,
1959                     new HandlerExecutor(new Handler()));
1960         } catch (RemoteException e) {
1961             throw e.rethrowFromSystemServer();
1962         }
1963     }
1964 
1965     /**
1966      * Removes a GPS status listener.
1967      *
1968      * @param listener GPS status listener object to remove
1969      *
1970      * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead. No longer
1971      * supported in apps targeting S and above.
1972      */
1973     @Deprecated
removeGpsStatusListener(GpsStatus.Listener listener)1974     public void removeGpsStatusListener(GpsStatus.Listener listener) {
1975         if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
1976             throw new UnsupportedOperationException(
1977                     "GpsStatus APIs not supported, please use GnssStatus APIs instead");
1978         }
1979 
1980         try {
1981             mGnssStatusListenerManager.removeListener(listener);
1982         } catch (RemoteException e) {
1983             throw e.rethrowFromSystemServer();
1984         }
1985     }
1986 
1987     /**
1988      * Registers a GNSS status callback.
1989      *
1990      * @param callback GNSS status callback object to register
1991      * @return true if the listener was successfully added
1992      *
1993      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1994      *
1995      * @deprecated Use {@link #registerGnssStatusCallback(GnssStatus.Callback, Handler)} or {@link
1996      * #registerGnssStatusCallback(Executor, GnssStatus.Callback)} instead.
1997      */
1998     @Deprecated
1999     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback(@onNull GnssStatus.Callback callback)2000     public boolean registerGnssStatusCallback(@NonNull GnssStatus.Callback callback) {
2001         return registerGnssStatusCallback(callback, null);
2002     }
2003 
2004     /**
2005      * Registers a GNSS status callback.
2006      *
2007      * @param callback GNSS status callback object to register
2008      * @param handler  a handler with a looper that the callback runs on
2009      * @return true if the listener was successfully added
2010      *
2011      * @throws IllegalArgumentException if callback is null
2012      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2013      */
2014     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback( @onNull GnssStatus.Callback callback, @Nullable Handler handler)2015     public boolean registerGnssStatusCallback(
2016             @NonNull GnssStatus.Callback callback, @Nullable Handler handler) {
2017         if (handler == null) {
2018             handler = new Handler();
2019         }
2020 
2021         try {
2022             return mGnssStatusListenerManager.addListener(callback, handler);
2023         } catch (RemoteException e) {
2024             throw e.rethrowFromSystemServer();
2025         }
2026     }
2027 
2028     /**
2029      * Registers a GNSS status callback.
2030      *
2031      * @param executor the executor that the callback runs on
2032      * @param callback GNSS status callback object to register
2033      * @return true if the listener was successfully added
2034      *
2035      * @throws IllegalArgumentException if executor is null
2036      * @throws IllegalArgumentException if callback is null
2037      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2038      */
2039     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssStatusCallback( @onNull @allbackExecutor Executor executor, @NonNull GnssStatus.Callback callback)2040     public boolean registerGnssStatusCallback(
2041             @NonNull @CallbackExecutor Executor executor,
2042             @NonNull GnssStatus.Callback callback) {
2043         try {
2044             return mGnssStatusListenerManager.addListener(callback, executor);
2045         } catch (RemoteException e) {
2046             throw e.rethrowFromSystemServer();
2047         }
2048     }
2049 
2050     /**
2051      * Removes a GNSS status callback.
2052      *
2053      * @param callback GNSS status callback object to remove
2054      */
unregisterGnssStatusCallback(@onNull GnssStatus.Callback callback)2055     public void unregisterGnssStatusCallback(@NonNull GnssStatus.Callback callback) {
2056         try {
2057             mGnssStatusListenerManager.removeListener(callback);
2058         } catch (RemoteException e) {
2059             throw e.rethrowFromSystemServer();
2060         }
2061     }
2062 
2063     /**
2064      * No-op method to keep backward-compatibility.
2065      *
2066      * @deprecated Use {@link #addNmeaListener} instead.
2067      */
2068     @Deprecated
2069     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(@onNull GpsStatus.NmeaListener listener)2070     public boolean addNmeaListener(@NonNull GpsStatus.NmeaListener listener) {
2071         return false;
2072     }
2073 
2074     /**
2075      * No-op method to keep backward-compatibility.
2076      *
2077      * @deprecated Use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
2078      */
2079     @Deprecated
removeNmeaListener(@onNull GpsStatus.NmeaListener listener)2080     public void removeNmeaListener(@NonNull GpsStatus.NmeaListener listener) {}
2081 
2082     /**
2083      * Adds an NMEA listener.
2084      *
2085      * @param listener a {@link OnNmeaMessageListener} object to register
2086      * @return true if the listener was successfully added
2087      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2088      * @deprecated Use {@link #addNmeaListener(OnNmeaMessageListener, Handler)} or {@link
2089      * #addNmeaListener(Executor, OnNmeaMessageListener)} instead.
2090      */
2091     @Deprecated
2092     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener(@onNull OnNmeaMessageListener listener)2093     public boolean addNmeaListener(@NonNull OnNmeaMessageListener listener) {
2094         return addNmeaListener(listener, null);
2095     }
2096 
2097     /**
2098      * Adds an NMEA listener.
2099      *
2100      * @param listener a {@link OnNmeaMessageListener} object to register
2101      * @param handler  a handler with the looper that the listener runs on.
2102      * @return true if the listener was successfully added
2103      *
2104      * @throws IllegalArgumentException if listener is null
2105      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2106      */
2107     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener( @onNull OnNmeaMessageListener listener, @Nullable Handler handler)2108     public boolean addNmeaListener(
2109             @NonNull OnNmeaMessageListener listener, @Nullable Handler handler) {
2110         if (handler == null) {
2111             handler = new Handler();
2112         }
2113         try {
2114             return mGnssStatusListenerManager.addListener(listener, handler);
2115         } catch (RemoteException e) {
2116             throw e.rethrowFromSystemServer();
2117         }
2118     }
2119 
2120     /**
2121      * Adds an NMEA listener.
2122      *
2123      * @param listener a {@link OnNmeaMessageListener} object to register
2124      * @param executor the {@link Executor} that the listener runs on.
2125      * @return true if the listener was successfully added
2126      *
2127      * @throws IllegalArgumentException if executor is null
2128      * @throws IllegalArgumentException if listener is null
2129      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2130      */
2131     @RequiresPermission(ACCESS_FINE_LOCATION)
addNmeaListener( @onNull @allbackExecutor Executor executor, @NonNull OnNmeaMessageListener listener)2132     public boolean addNmeaListener(
2133             @NonNull @CallbackExecutor Executor executor,
2134             @NonNull OnNmeaMessageListener listener) {
2135         try {
2136             return mGnssStatusListenerManager.addListener(listener, executor);
2137         } catch (RemoteException e) {
2138             throw e.rethrowFromSystemServer();
2139         }
2140     }
2141 
2142     /**
2143      * Removes an NMEA listener.
2144      *
2145      * @param listener a {@link OnNmeaMessageListener} object to remove
2146      */
removeNmeaListener(@onNull OnNmeaMessageListener listener)2147     public void removeNmeaListener(@NonNull OnNmeaMessageListener listener) {
2148         try {
2149             mGnssStatusListenerManager.removeListener(listener);
2150         } catch (RemoteException e) {
2151             throw e.rethrowFromSystemServer();
2152         }
2153     }
2154 
2155     /**
2156      * No-op method to keep backward-compatibility.
2157      *
2158      * @hide
2159      * @deprecated Use {@link #registerGnssMeasurementsCallback} instead.
2160      * @removed
2161      */
2162     @Deprecated
2163     @SystemApi
addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)2164     public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
2165         return false;
2166     }
2167 
2168     /**
2169      * No-op method to keep backward-compatibility.
2170      *
2171      * @hide
2172      * @deprecated Use {@link #unregisterGnssMeasurementsCallback} instead.
2173      * @removed
2174      */
2175     @Deprecated
2176     @SystemApi
removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)2177     public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {}
2178 
2179     /**
2180      * Registers a GPS Measurement callback which will run on a binder thread.
2181      *
2182      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2183      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2184      * @deprecated Use {@link
2185      * #registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback, Handler)} or {@link
2186      * #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)} instead.
2187      */
2188     @Deprecated
2189     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssMeasurementsCallback( @onNull GnssMeasurementsEvent.Callback callback)2190     public boolean registerGnssMeasurementsCallback(
2191             @NonNull GnssMeasurementsEvent.Callback callback) {
2192         return registerGnssMeasurementsCallback(Runnable::run, callback);
2193     }
2194 
2195     /**
2196      * Registers a GPS Measurement callback.
2197      *
2198      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2199      * @param handler  the handler that the callback runs on.
2200      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2201      *
2202      * @throws IllegalArgumentException if callback is null
2203      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2204      */
2205     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssMeasurementsCallback( @onNull GnssMeasurementsEvent.Callback callback, @Nullable Handler handler)2206     public boolean registerGnssMeasurementsCallback(
2207             @NonNull GnssMeasurementsEvent.Callback callback, @Nullable Handler handler) {
2208         if (handler == null) {
2209             handler = new Handler();
2210         }
2211         try {
2212             return mGnssMeasurementsListenerManager.addListener(callback, handler);
2213         } catch (RemoteException e) {
2214             throw e.rethrowFromSystemServer();
2215         }
2216     }
2217 
2218     /**
2219      * Registers a GPS Measurement callback.
2220      *
2221      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2222      * @param executor the executor that the callback runs on.
2223      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2224      *
2225      * @throws IllegalArgumentException if executor is null
2226      * @throws IllegalArgumentException if callback is null
2227      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2228      */
2229     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssMeasurementsCallback( @onNull @allbackExecutor Executor executor, @NonNull GnssMeasurementsEvent.Callback callback)2230     public boolean registerGnssMeasurementsCallback(
2231             @NonNull @CallbackExecutor Executor executor,
2232             @NonNull GnssMeasurementsEvent.Callback callback) {
2233         try {
2234             return mGnssMeasurementsListenerManager.addListener(callback, executor);
2235         } catch (RemoteException e) {
2236             throw e.rethrowFromSystemServer();
2237         }
2238     }
2239 
2240     /**
2241      * Registers a GNSS Measurement callback.
2242      *
2243      * @param request  extra parameters to pass to GNSS measurement provider. For example, if {@link
2244      *                 GnssRequest#isFullTracking()} is true, GNSS chipset switches off duty
2245      *                 cycling.
2246      * @param executor the executor that the callback runs on.
2247      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
2248      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2249      * @throws IllegalArgumentException if request is null
2250      * @throws IllegalArgumentException if executor is null
2251      * @throws IllegalArgumentException if callback is null
2252      * @throws SecurityException        if the ACCESS_FINE_LOCATION permission is not present
2253      * @hide
2254      */
2255     @SystemApi
2256     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE})
registerGnssMeasurementsCallback( @onNull GnssRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull GnssMeasurementsEvent.Callback callback)2257     public boolean registerGnssMeasurementsCallback(
2258             @NonNull GnssRequest request,
2259             @NonNull @CallbackExecutor Executor executor,
2260             @NonNull GnssMeasurementsEvent.Callback callback) {
2261         Preconditions.checkArgument(request != null, "invalid null request");
2262         try {
2263             return mGnssMeasurementsListenerManager.addListener(request, callback, executor);
2264         } catch (RemoteException e) {
2265             throw e.rethrowFromSystemServer();
2266         }
2267     }
2268 
2269     /**
2270      * Injects GNSS measurement corrections into the GNSS chipset.
2271      *
2272      * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
2273      *     measurement corrections to be injected into the GNSS chipset.
2274      *
2275      * @throws IllegalArgumentException if measurementCorrections is null
2276      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2277      * @hide
2278      */
2279     @SystemApi
2280     @RequiresPermission(ACCESS_FINE_LOCATION)
injectGnssMeasurementCorrections( @onNull GnssMeasurementCorrections measurementCorrections)2281     public void injectGnssMeasurementCorrections(
2282             @NonNull GnssMeasurementCorrections measurementCorrections) {
2283         Preconditions.checkArgument(measurementCorrections != null);
2284         try {
2285             mService.injectGnssMeasurementCorrections(
2286                     measurementCorrections, mContext.getPackageName());
2287         } catch (RemoteException e) {
2288             throw e.rethrowFromSystemServer();
2289         }
2290     }
2291 
2292     /**
2293      * Unregisters a GPS Measurement callback.
2294      *
2295      * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
2296      */
unregisterGnssMeasurementsCallback( @onNull GnssMeasurementsEvent.Callback callback)2297     public void unregisterGnssMeasurementsCallback(
2298             @NonNull GnssMeasurementsEvent.Callback callback) {
2299         try {
2300             mGnssMeasurementsListenerManager.removeListener(callback);
2301         } catch (RemoteException e) {
2302             throw e.rethrowFromSystemServer();
2303         }
2304     }
2305 
2306     /**
2307      * Registers a Gnss Antenna Info listener. Only expect results if
2308      * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported.
2309      *
2310      * @param executor the executor that the listener runs on.
2311      * @param listener a {@link GnssAntennaInfo.Listener} object to register.
2312      * @return {@code true} if the listener was added successfully, {@code false} otherwise.
2313      *
2314      * @throws IllegalArgumentException if executor is null
2315      * @throws IllegalArgumentException if listener is null
2316      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2317      */
2318     @RequiresPermission(ACCESS_FINE_LOCATION)
registerAntennaInfoListener( @onNull @allbackExecutor Executor executor, @NonNull GnssAntennaInfo.Listener listener)2319     public boolean registerAntennaInfoListener(
2320             @NonNull @CallbackExecutor Executor executor,
2321             @NonNull GnssAntennaInfo.Listener listener) {
2322         try {
2323             return mGnssAntennaInfoListenerManager.addListener(listener, executor);
2324         } catch (RemoteException e) {
2325             throw e.rethrowFromSystemServer();
2326         }
2327     }
2328 
2329     /**
2330      * Unregisters a GNSS Antenna Info listener.
2331      *
2332      * @param listener a {@link GnssAntennaInfo.Listener} object to remove.
2333      */
unregisterAntennaInfoListener(@onNull GnssAntennaInfo.Listener listener)2334     public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) {
2335         try {
2336             mGnssAntennaInfoListenerManager.removeListener(listener);
2337         } catch (RemoteException e) {
2338             throw e.rethrowFromSystemServer();
2339         }
2340     }
2341 
2342     /**
2343      * No-op method to keep backward-compatibility.
2344      *
2345      * @hide
2346      * @deprecated Use {@link #registerGnssNavigationMessageCallback} instead.
2347      * @removed
2348      */
2349     @Deprecated
2350     @SystemApi
addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)2351     public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
2352         return false;
2353     }
2354 
2355     /**
2356      * No-op method to keep backward-compatibility.
2357      *
2358      * @hide
2359      * @deprecated Use {@link #unregisterGnssNavigationMessageCallback} instead.
2360      * @removed
2361      */
2362     @Deprecated
2363     @SystemApi
removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)2364     public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {}
2365 
2366     /**
2367      * Registers a GNSS Navigation Message callback which will run on a binder thread.
2368      *
2369      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
2370      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2371      * @deprecated Use {@link
2372      * #registerGnssNavigationMessageCallback(GnssNavigationMessage.Callback, Handler)} or {@link
2373      * #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} instead.
2374      */
2375     @Deprecated
registerGnssNavigationMessageCallback( @onNull GnssNavigationMessage.Callback callback)2376     public boolean registerGnssNavigationMessageCallback(
2377             @NonNull GnssNavigationMessage.Callback callback) {
2378         return registerGnssNavigationMessageCallback(Runnable::run, callback);
2379     }
2380 
2381     /**
2382      * Registers a GNSS Navigation Message callback.
2383      *
2384      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
2385      * @param handler  the handler that the callback runs on.
2386      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2387      *
2388      * @throws IllegalArgumentException if callback is null
2389      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2390      */
2391     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssNavigationMessageCallback( @onNull GnssNavigationMessage.Callback callback, @Nullable Handler handler)2392     public boolean registerGnssNavigationMessageCallback(
2393             @NonNull GnssNavigationMessage.Callback callback, @Nullable Handler handler) {
2394         if (handler == null) {
2395             handler = new Handler();
2396         }
2397 
2398         try {
2399             return mGnssNavigationMessageListenerTransport.addListener(callback, handler);
2400         } catch (RemoteException e) {
2401             throw e.rethrowFromSystemServer();
2402         }
2403     }
2404 
2405     /**
2406      * Registers a GNSS Navigation Message callback.
2407      *
2408      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
2409      * @param executor the looper that the callback runs on.
2410      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
2411      *
2412      * @throws IllegalArgumentException if executor is null
2413      * @throws IllegalArgumentException if callback is null
2414      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
2415      */
2416     @RequiresPermission(ACCESS_FINE_LOCATION)
registerGnssNavigationMessageCallback( @onNull @allbackExecutor Executor executor, @NonNull GnssNavigationMessage.Callback callback)2417     public boolean registerGnssNavigationMessageCallback(
2418             @NonNull @CallbackExecutor Executor executor,
2419             @NonNull GnssNavigationMessage.Callback callback) {
2420         try {
2421             return mGnssNavigationMessageListenerTransport.addListener(callback, executor);
2422         } catch (RemoteException e) {
2423             throw e.rethrowFromSystemServer();
2424         }
2425     }
2426 
2427     /**
2428      * Unregisters a GNSS Navigation Message callback.
2429      *
2430      * @param callback a {@link GnssNavigationMessage.Callback} object to remove.
2431      */
unregisterGnssNavigationMessageCallback( @onNull GnssNavigationMessage.Callback callback)2432     public void unregisterGnssNavigationMessageCallback(
2433             @NonNull GnssNavigationMessage.Callback callback) {
2434         try {
2435             mGnssNavigationMessageListenerTransport.removeListener(callback);
2436         } catch (RemoteException e) {
2437             throw e.rethrowFromSystemServer();
2438         }
2439     }
2440 
2441     /**
2442      * Returns the batch size (in number of Location objects) that are supported by the batching
2443      * interface.
2444      *
2445      * @return Maximum number of location objects that can be returned
2446      * @hide
2447      */
2448     @SystemApi
2449     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
getGnssBatchSize()2450     public int getGnssBatchSize() {
2451         try {
2452             return mService.getGnssBatchSize(mContext.getPackageName());
2453         } catch (RemoteException e) {
2454             throw e.rethrowFromSystemServer();
2455         }
2456     }
2457 
2458     /**
2459      * Start hardware-batching of GNSS locations. This API is primarily used when the AP is
2460      * asleep and the device can batch GNSS locations in the hardware.
2461      *
2462      * Note this is designed (as was the fused location interface before it) for a single user
2463      * SystemApi - requests are not consolidated.  Care should be taken when the System switches
2464      * users that may have different batching requests, to stop hardware batching for one user, and
2465      * restart it for the next.
2466      *
2467      * @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested
2468      *                    within the batch
2469      * @param wakeOnFifoFull True if the hardware batching should flush the locations in a
2470      *                       a callback to the listener, when it's internal buffer is full.  If
2471      *                       set to false, the oldest location information is, instead,
2472      *                       dropped when the buffer is full.
2473      * @param callback The listener on which to return the batched locations
2474      * @param handler The handler on which to process the callback
2475      *
2476      * @return True if batching was successfully started
2477      * @hide
2478      */
2479     @SystemApi
2480     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull, @NonNull BatchedLocationCallback callback, @Nullable Handler handler)2481     public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
2482             @NonNull BatchedLocationCallback callback, @Nullable Handler handler) {
2483         if (handler == null) {
2484             handler = new Handler();
2485         }
2486 
2487         synchronized (mBatchedLocationCallbackManager) {
2488             try {
2489                 if (mBatchedLocationCallbackManager.addListener(callback, handler)) {
2490                     return mService.startGnssBatch(periodNanos, wakeOnFifoFull,
2491                             mContext.getPackageName(), mContext.getAttributionTag());
2492                 }
2493                 return false;
2494             } catch (RemoteException e) {
2495                 throw e.rethrowFromSystemServer();
2496             }
2497         }
2498     }
2499 
2500     /**
2501      * Flush the batched GNSS locations.
2502      * All GNSS locations currently ready in the batch are returned via the callback sent in
2503      * startGnssBatch(), and the buffer containing the batched locations is cleared.
2504      *
2505      * @hide
2506      */
2507     @SystemApi
2508     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
flushGnssBatch()2509     public void flushGnssBatch() {
2510         try {
2511             mService.flushGnssBatch(mContext.getPackageName());
2512         } catch (RemoteException e) {
2513             throw e.rethrowFromSystemServer();
2514         }
2515     }
2516 
2517     /**
2518      * Stop batching locations. This API is primarily used when the AP is
2519      * asleep and the device can batch locations in the hardware.
2520      *
2521      * @param callback the specific callback class to remove from the transport layer
2522      *
2523      * @return True if batching was successfully started
2524      * @hide
2525      */
2526     @SystemApi
2527     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
unregisterGnssBatchedLocationCallback( @onNull BatchedLocationCallback callback)2528     public boolean unregisterGnssBatchedLocationCallback(
2529             @NonNull BatchedLocationCallback callback) {
2530         synchronized (mBatchedLocationCallbackManager) {
2531             try {
2532                 mBatchedLocationCallbackManager.removeListener(callback);
2533                 mService.stopGnssBatch();
2534                 return true;
2535             } catch (RemoteException e) {
2536                 throw e.rethrowFromSystemServer();
2537             }
2538         }
2539     }
2540 
2541     private static class GetCurrentLocationTransport extends ILocationListener.Stub implements
2542             AlarmManager.OnAlarmListener, CancellationSignal.OnCancelListener {
2543 
2544         @GuardedBy("this")
2545         @Nullable
2546         private Executor mExecutor;
2547 
2548         @GuardedBy("this")
2549         @Nullable
2550         private Consumer<Location> mConsumer;
2551 
2552         @GuardedBy("this")
2553         @Nullable
2554         private AlarmManager mAlarmManager;
2555 
2556         @GuardedBy("this")
2557         @Nullable
2558         private ICancellationSignal mRemoteCancellationSignal;
2559 
GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer)2560         private GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) {
2561             Preconditions.checkArgument(executor != null, "illegal null executor");
2562             Preconditions.checkArgument(consumer != null, "illegal null consumer");
2563             mExecutor = executor;
2564             mConsumer = consumer;
2565             mAlarmManager = null;
2566             mRemoteCancellationSignal = null;
2567         }
2568 
getListenerId()2569         public String getListenerId() {
2570             return AppOpsManager.toReceiverId(mConsumer);
2571         }
2572 
register(AlarmManager alarmManager, CancellationSignal cancellationSignal, ICancellationSignal remoteCancellationSignal)2573         public synchronized void register(AlarmManager alarmManager,
2574                 CancellationSignal cancellationSignal,
2575                 ICancellationSignal remoteCancellationSignal) {
2576             if (mConsumer == null) {
2577                 return;
2578             }
2579 
2580             mAlarmManager = alarmManager;
2581             mAlarmManager.set(
2582                     ELAPSED_REALTIME,
2583                     SystemClock.elapsedRealtime() + GET_CURRENT_LOCATION_MAX_TIMEOUT_MS,
2584                     "GetCurrentLocation",
2585                     this,
2586                     null);
2587 
2588             if (cancellationSignal != null) {
2589                 cancellationSignal.setOnCancelListener(this);
2590             }
2591 
2592             mRemoteCancellationSignal = remoteCancellationSignal;
2593         }
2594 
2595         @Override
onCancel()2596         public void onCancel() {
2597             synchronized (this) {
2598                 mRemoteCancellationSignal = null;
2599             }
2600             remove();
2601         }
2602 
remove()2603         private Consumer<Location> remove() {
2604             Consumer<Location> consumer;
2605             ICancellationSignal cancellationSignal;
2606             synchronized (this) {
2607                 mExecutor = null;
2608                 consumer = mConsumer;
2609                 mConsumer = null;
2610 
2611                 if (mAlarmManager != null) {
2612                     mAlarmManager.cancel(this);
2613                     mAlarmManager = null;
2614                 }
2615 
2616                 // ensure only one cancel event will go through
2617                 cancellationSignal = mRemoteCancellationSignal;
2618                 mRemoteCancellationSignal = null;
2619             }
2620 
2621             if (cancellationSignal != null) {
2622                 try {
2623                     cancellationSignal.cancel();
2624                 } catch (RemoteException e) {
2625                     // ignore
2626                 }
2627             }
2628 
2629             return consumer;
2630         }
2631 
fail()2632         public void fail() {
2633             deliverResult(null);
2634         }
2635 
2636         @Override
onAlarm()2637         public void onAlarm() {
2638             synchronized (this) {
2639                 // save ourselves a pointless x-process call to cancel the alarm
2640                 mAlarmManager = null;
2641             }
2642 
2643             deliverResult(null);
2644         }
2645 
2646         @Override
onLocationChanged(Location location)2647         public void onLocationChanged(Location location) {
2648             deliverResult(location);
2649         }
2650 
2651         @Override
onProviderEnabled(String provider)2652         public void onProviderEnabled(String provider) {}
2653 
2654         @Override
onProviderDisabled(String provider)2655         public void onProviderDisabled(String provider) {
2656             // in the event of the provider being disabled it is unlikely that we will get further
2657             // locations, so fail early so the client isn't left waiting hopelessly
2658             deliverResult(null);
2659         }
2660 
2661         @Override
onRemoved()2662         public void onRemoved() {
2663             deliverResult(null);
2664         }
2665 
deliverResult(@ullable Location location)2666         private synchronized void deliverResult(@Nullable Location location) {
2667             if (mExecutor == null) {
2668                 return;
2669             }
2670 
2671             PooledRunnable runnable =
2672                     obtainRunnable(GetCurrentLocationTransport::acceptResult, this, location)
2673                             .recycleOnUse();
2674             try {
2675                 mExecutor.execute(runnable);
2676             } catch (RejectedExecutionException e) {
2677                 runnable.recycle();
2678                 throw e;
2679             }
2680         }
2681 
acceptResult(Location location)2682         private void acceptResult(Location location) {
2683             Consumer<Location> consumer = remove();
2684             if (consumer != null) {
2685                 consumer.accept(location);
2686             }
2687         }
2688     }
2689 
2690     private class LocationListenerTransport extends ILocationListener.Stub {
2691 
2692         private final LocationListener mListener;
2693         @Nullable private volatile Executor mExecutor = null;
2694 
LocationListenerTransport(@onNull LocationListener listener)2695         private LocationListenerTransport(@NonNull LocationListener listener) {
2696             Preconditions.checkArgument(listener != null, "invalid null listener");
2697             mListener = listener;
2698         }
2699 
getKey()2700         public LocationListener getKey() {
2701             return mListener;
2702         }
2703 
getListenerId()2704         public String getListenerId() {
2705             return AppOpsManager.toReceiverId(mListener);
2706         }
2707 
register(@onNull Executor executor)2708         public void register(@NonNull Executor executor) {
2709             Preconditions.checkArgument(executor != null, "invalid null executor");
2710             mExecutor = executor;
2711         }
2712 
unregister()2713         public void unregister() {
2714             mExecutor = null;
2715         }
2716 
2717         @Override
onLocationChanged(Location location)2718         public void onLocationChanged(Location location) {
2719             Executor currentExecutor = mExecutor;
2720             if (currentExecutor == null) {
2721                 return;
2722             }
2723 
2724             PooledRunnable runnable =
2725                     obtainRunnable(LocationListenerTransport::acceptLocation, this, currentExecutor,
2726                             location).recycleOnUse();
2727             try {
2728                 currentExecutor.execute(runnable);
2729             } catch (RejectedExecutionException e) {
2730                 runnable.recycle();
2731                 locationCallbackFinished();
2732                 throw e;
2733             }
2734         }
2735 
acceptLocation(Executor currentExecutor, Location location)2736         private void acceptLocation(Executor currentExecutor, Location location) {
2737             try {
2738                 if (currentExecutor != mExecutor) {
2739                     return;
2740                 }
2741 
2742                 // we may be under the binder identity if a direct executor is used
2743                 long identity = Binder.clearCallingIdentity();
2744                 try {
2745                     mListener.onLocationChanged(location);
2746                 } finally {
2747                     Binder.restoreCallingIdentity(identity);
2748                 }
2749             } finally {
2750                 locationCallbackFinished();
2751             }
2752         }
2753 
2754         @Override
onProviderEnabled(String provider)2755         public void onProviderEnabled(String provider) {
2756             Executor currentExecutor = mExecutor;
2757             if (currentExecutor == null) {
2758                 return;
2759             }
2760 
2761             PooledRunnable runnable =
2762                     obtainRunnable(LocationListenerTransport::acceptProviderChange, this,
2763                             currentExecutor, provider, true).recycleOnUse();
2764             try {
2765                 currentExecutor.execute(runnable);
2766             } catch (RejectedExecutionException e) {
2767                 runnable.recycle();
2768                 locationCallbackFinished();
2769                 throw e;
2770             }
2771         }
2772 
2773         @Override
onProviderDisabled(String provider)2774         public void onProviderDisabled(String provider) {
2775             Executor currentExecutor = mExecutor;
2776             if (currentExecutor == null) {
2777                 return;
2778             }
2779 
2780             PooledRunnable runnable =
2781                     obtainRunnable(LocationListenerTransport::acceptProviderChange, this,
2782                             currentExecutor, provider, false).recycleOnUse();
2783             try {
2784                 currentExecutor.execute(runnable);
2785             } catch (RejectedExecutionException e) {
2786                 runnable.recycle();
2787                 locationCallbackFinished();
2788                 throw e;
2789             }
2790         }
2791 
acceptProviderChange(Executor currentExecutor, String provider, boolean enabled)2792         private void acceptProviderChange(Executor currentExecutor, String provider,
2793                 boolean enabled) {
2794             try {
2795                 if (currentExecutor != mExecutor) {
2796                     return;
2797                 }
2798 
2799                 // we may be under the binder identity if a direct executor is used
2800                 long identity = Binder.clearCallingIdentity();
2801                 try {
2802                     if (enabled) {
2803                         mListener.onProviderEnabled(provider);
2804                     } else {
2805                         mListener.onProviderDisabled(provider);
2806                     }
2807                 } finally {
2808                     Binder.restoreCallingIdentity(identity);
2809                 }
2810             } finally {
2811                 locationCallbackFinished();
2812             }
2813         }
2814 
2815         @Override
onRemoved()2816         public void onRemoved() {
2817             // TODO: onRemoved is necessary to GC hanging listeners, but introduces some interesting
2818             //  broken edge cases. luckily these edge cases are quite unlikely. consider the
2819             //  following interleaving for instance:
2820             //    1) client adds single shot location request (A)
2821             //    2) client gets removal callback, and schedules it for execution
2822             //    3) client replaces single shot request with a different location request (B)
2823             //    4) prior removal callback is executed, removing location request (B) incorrectly
2824             //  what's needed is a way to identify which listener a callback belongs to. currently
2825             //  we reuse the same transport object for the same listeners (so that we don't leak
2826             //  transport objects on the server side). there seem to be two solutions:
2827             //    1) when reregistering a request, first unregister the current transport, then
2828             //       register with a new transport object (never reuse transport objects) - the
2829             //       downside is that this breaks the server's knowledge that the request is the
2830             //       same object, and thus breaks optimizations such as reusing the same transport
2831             //       state.
2832             //    2) pass some other type of marker in addition to the transport (for example an
2833             //       incrementing integer representing the transport "version"), and pass this
2834             //       marker back into callbacks so that each callback knows which transport
2835             //       "version" it belongs to and can not execute itself if the version does not
2836             //       match.
2837             //  (1) seems like the preferred solution as it's simpler to implement and the above
2838             //  mentioned server optimizations are not terribly important (they can be bypassed by
2839             //  clients that use a new listener every time anyways).
2840 
2841             Executor currentExecutor = mExecutor;
2842             if (currentExecutor == null) {
2843                 // we've already been unregistered, no work to do anyways
2844                 return;
2845             }
2846 
2847             // must be executed on the same executor so callback execution cannot be reordered
2848             currentExecutor.execute(() -> {
2849                 if (currentExecutor != mExecutor) {
2850                     return;
2851                 }
2852 
2853                 unregister();
2854                 synchronized (mListeners) {
2855                     mListeners.remove(mListener, this);
2856                 }
2857             });
2858         }
2859 
locationCallbackFinished()2860         private void locationCallbackFinished() {
2861             try {
2862                 mService.locationCallbackFinished(this);
2863             } catch (RemoteException e) {
2864                 throw e.rethrowFromSystemServer();
2865             }
2866         }
2867     }
2868 
2869     private static class NmeaAdapter extends GnssStatus.Callback implements OnNmeaMessageListener {
2870 
2871         private final OnNmeaMessageListener mListener;
2872 
NmeaAdapter(OnNmeaMessageListener listener)2873         private NmeaAdapter(OnNmeaMessageListener listener) {
2874             mListener = listener;
2875         }
2876 
2877         @Override
onNmeaMessage(String message, long timestamp)2878         public void onNmeaMessage(String message, long timestamp) {
2879             mListener.onNmeaMessage(message, timestamp);
2880         }
2881     }
2882 
2883     private class GnssStatusListenerManager extends
2884             AbstractListenerManager<Void, GnssStatus.Callback> {
2885         @Nullable
2886         private IGnssStatusListener mListenerTransport;
2887 
2888         @Nullable
2889         private volatile GnssStatus mGnssStatus;
2890         private volatile int mTtff;
2891 
getGnssStatus()2892         public GnssStatus getGnssStatus() {
2893             return mGnssStatus;
2894         }
2895 
getTtff()2896         public int getTtff() {
2897             return mTtff;
2898         }
2899 
addListener(@onNull GpsStatus.Listener listener, @NonNull Executor executor)2900         public boolean addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor)
2901                 throws RemoteException {
2902             return addInternal(null, listener, executor);
2903         }
2904 
addListener(@onNull OnNmeaMessageListener listener, @NonNull Handler handler)2905         public boolean addListener(@NonNull OnNmeaMessageListener listener,
2906                 @NonNull Handler handler)
2907                 throws RemoteException {
2908             return addInternal(null, listener, handler);
2909         }
2910 
addListener(@onNull OnNmeaMessageListener listener, @NonNull Executor executor)2911         public boolean addListener(@NonNull OnNmeaMessageListener listener,
2912                 @NonNull Executor executor)
2913                 throws RemoteException {
2914             return addInternal(null, listener, executor);
2915         }
2916 
2917         @Override
convertKey(Object listener)2918         protected GnssStatus.Callback convertKey(Object listener) {
2919             if (listener instanceof GnssStatus.Callback) {
2920                 return (GnssStatus.Callback) listener;
2921             } else if (listener instanceof GpsStatus.Listener) {
2922                 return new GnssStatus.Callback() {
2923                     private final GpsStatus.Listener mGpsListener = (GpsStatus.Listener) listener;
2924 
2925                     @Override
2926                     public void onStarted() {
2927                         mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
2928                     }
2929 
2930                     @Override
2931                     public void onStopped() {
2932                         mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
2933                     }
2934 
2935                     @Override
2936                     public void onFirstFix(int ttffMillis) {
2937                         mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
2938                     }
2939 
2940                     @Override
2941                     public void onSatelliteStatusChanged(GnssStatus status) {
2942                         mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
2943                     }
2944                 };
2945             } else if (listener instanceof OnNmeaMessageListener) {
2946                 return new NmeaAdapter((OnNmeaMessageListener) listener);
2947             } else {
2948                 throw new IllegalStateException();
2949             }
2950         }
2951 
2952         @Override
registerService(Void ignored)2953         protected boolean registerService(Void ignored) throws RemoteException {
2954             Preconditions.checkState(mListenerTransport == null);
2955 
2956             GnssStatusListener transport = new GnssStatusListener();
2957             if (mService.registerGnssStatusCallback(transport, mContext.getPackageName(),
2958                     mContext.getAttributionTag())) {
2959                 mListenerTransport = transport;
2960                 return true;
2961             } else {
2962                 return false;
2963             }
2964         }
2965 
2966         @Override
unregisterService()2967         protected void unregisterService() throws RemoteException {
2968             if (mListenerTransport != null) {
2969                 mService.unregisterGnssStatusCallback(mListenerTransport);
2970                 mListenerTransport = null;
2971             }
2972         }
2973 
2974         private class GnssStatusListener extends IGnssStatusListener.Stub {
2975             @Override
onGnssStarted()2976             public void onGnssStarted() {
2977                 execute(GnssStatus.Callback::onStarted);
2978             }
2979 
2980             @Override
onGnssStopped()2981             public void onGnssStopped() {
2982                 execute(GnssStatus.Callback::onStopped);
2983             }
2984 
2985             @Override
onFirstFix(int ttff)2986             public void onFirstFix(int ttff) {
2987                 mTtff = ttff;
2988                 execute((callback) -> callback.onFirstFix(ttff));
2989             }
2990 
2991             @Override
onSvStatusChanged(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations, float[] azimuths, float[] carrierFreqs, float[] basebandCn0s)2992             public void onSvStatusChanged(int svCount, int[] svidWithFlags, float[] cn0s,
2993                     float[] elevations, float[] azimuths, float[] carrierFreqs,
2994                     float[] basebandCn0s) {
2995                 GnssStatus localStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0s,
2996                         elevations, azimuths, carrierFreqs, basebandCn0s);
2997                 mGnssStatus = localStatus;
2998                 execute((callback) -> callback.onSatelliteStatusChanged(localStatus));
2999             }
3000 
3001             @Override
onNmeaReceived(long timestamp, String nmea)3002             public void onNmeaReceived(long timestamp, String nmea) {
3003                 execute((callback) -> {
3004                     if (callback instanceof NmeaAdapter) {
3005                         ((NmeaAdapter) callback).onNmeaMessage(nmea, timestamp);
3006                     }
3007                 });
3008             }
3009         }
3010     }
3011 
3012     private class GnssMeasurementsListenerManager extends
3013             AbstractListenerManager<GnssRequest, GnssMeasurementsEvent.Callback> {
3014 
3015         @Nullable
3016         private IGnssMeasurementsListener mListenerTransport;
3017 
3018         @Override
registerService(GnssRequest request)3019         protected boolean registerService(GnssRequest request) throws RemoteException {
3020             Preconditions.checkState(mListenerTransport == null);
3021 
3022             GnssMeasurementsListener transport = new GnssMeasurementsListener();
3023             if (mService.addGnssMeasurementsListener(request, transport, mContext.getPackageName(),
3024                     mContext.getAttributionTag())) {
3025                 mListenerTransport = transport;
3026                 return true;
3027             } else {
3028                 return false;
3029             }
3030         }
3031 
3032         @Override
unregisterService()3033         protected void unregisterService() throws RemoteException {
3034             if (mListenerTransport != null) {
3035                 mService.removeGnssMeasurementsListener(mListenerTransport);
3036                 mListenerTransport = null;
3037             }
3038         }
3039 
3040         @Override
3041         @Nullable
merge(@onNull List<GnssRequest> requests)3042         protected GnssRequest merge(@NonNull List<GnssRequest> requests) {
3043             Preconditions.checkArgument(!requests.isEmpty());
3044             for (GnssRequest request : requests) {
3045                 if (request != null && request.isFullTracking()) {
3046                     return request;
3047                 }
3048             }
3049             return requests.get(0);
3050         }
3051 
3052         private class GnssMeasurementsListener extends IGnssMeasurementsListener.Stub {
3053             @Override
onGnssMeasurementsReceived(final GnssMeasurementsEvent event)3054             public void onGnssMeasurementsReceived(final GnssMeasurementsEvent event) {
3055                 execute((callback) -> callback.onGnssMeasurementsReceived(event));
3056             }
3057 
3058             @Override
onStatusChanged(int status)3059             public void onStatusChanged(int status) {
3060                 execute((callback) -> callback.onStatusChanged(status));
3061             }
3062         }
3063     }
3064 
3065     private class GnssNavigationMessageListenerManager extends
3066             AbstractListenerManager<Void, GnssNavigationMessage.Callback> {
3067 
3068         @Nullable
3069         private IGnssNavigationMessageListener mListenerTransport;
3070 
3071         @Override
registerService(Void ignored)3072         protected boolean registerService(Void ignored) throws RemoteException {
3073             Preconditions.checkState(mListenerTransport == null);
3074 
3075             GnssNavigationMessageListener transport = new GnssNavigationMessageListener();
3076             if (mService.addGnssNavigationMessageListener(transport, mContext.getPackageName(),
3077                     mContext.getAttributionTag())) {
3078                 mListenerTransport = transport;
3079                 return true;
3080             } else {
3081                 return false;
3082             }
3083         }
3084 
3085         @Override
unregisterService()3086         protected void unregisterService() throws RemoteException {
3087             if (mListenerTransport != null) {
3088                 mService.removeGnssNavigationMessageListener(mListenerTransport);
3089                 mListenerTransport = null;
3090             }
3091         }
3092 
3093         private class GnssNavigationMessageListener extends IGnssNavigationMessageListener.Stub {
3094             @Override
onGnssNavigationMessageReceived(GnssNavigationMessage event)3095             public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {
3096                 execute((listener) -> listener.onGnssNavigationMessageReceived(event));
3097             }
3098 
3099             @Override
onStatusChanged(int status)3100             public void onStatusChanged(int status) {
3101                 execute((listener) -> listener.onStatusChanged(status));
3102             }
3103         }
3104     }
3105 
3106     private class GnssAntennaInfoListenerManager extends
3107             AbstractListenerManager<Void, GnssAntennaInfo.Listener> {
3108 
3109         @Nullable
3110         private IGnssAntennaInfoListener mListenerTransport;
3111 
3112         @Override
registerService(Void ignored)3113         protected boolean registerService(Void ignored) throws RemoteException {
3114             Preconditions.checkState(mListenerTransport == null);
3115 
3116             GnssAntennaInfoListener transport = new GnssAntennaInfoListener();
3117             if (mService.addGnssAntennaInfoListener(transport, mContext.getPackageName(),
3118                     mContext.getAttributionTag())) {
3119                 mListenerTransport = transport;
3120                 return true;
3121             } else {
3122                 return false;
3123             }
3124         }
3125 
3126         @Override
unregisterService()3127         protected void unregisterService() throws RemoteException {
3128             if (mListenerTransport != null) {
3129                 mService.removeGnssAntennaInfoListener(mListenerTransport);
3130                 mListenerTransport = null;
3131             }
3132         }
3133 
3134         private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub {
3135             @Override
onGnssAntennaInfoReceived(final List<GnssAntennaInfo> gnssAntennaInfos)3136             public void onGnssAntennaInfoReceived(final List<GnssAntennaInfo> gnssAntennaInfos) {
3137                 execute((callback) -> callback.onGnssAntennaInfoReceived(gnssAntennaInfos));
3138             }
3139         }
3140 
3141     }
3142 
3143     private class BatchedLocationCallbackManager extends
3144             AbstractListenerManager<Void, BatchedLocationCallback> {
3145 
3146         @Nullable
3147         private IBatchedLocationCallback mListenerTransport;
3148 
3149         @Override
registerService(Void ignored)3150         protected boolean registerService(Void ignored) throws RemoteException {
3151             Preconditions.checkState(mListenerTransport == null);
3152 
3153             BatchedLocationCallback transport = new BatchedLocationCallback();
3154             if (mService.addGnssBatchingCallback(transport, mContext.getPackageName(),
3155                     mContext.getAttributionTag())) {
3156                 mListenerTransport = transport;
3157                 return true;
3158             } else {
3159                 return false;
3160             }
3161         }
3162 
3163         @Override
unregisterService()3164         protected void unregisterService() throws RemoteException {
3165             if (mListenerTransport != null) {
3166                 mService.removeGnssBatchingCallback();
3167                 mListenerTransport = null;
3168             }
3169         }
3170 
3171         private class BatchedLocationCallback extends IBatchedLocationCallback.Stub {
3172             @Override
onLocationBatch(List<Location> locations)3173             public void onLocationBatch(List<Location> locations) {
3174                 execute((listener) -> listener.onLocationBatch(locations));
3175             }
3176 
3177         }
3178     }
3179 
3180     /**
3181      * @hide
3182      */
3183     public static final String CACHE_KEY_LOCATION_ENABLED_PROPERTY =
3184             "cache_key.location_enabled";
3185 
3186     /**
3187      * @hide
3188      */
invalidateLocalLocationEnabledCaches()3189     public static void invalidateLocalLocationEnabledCaches() {
3190         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_LOCATION_ENABLED_PROPERTY);
3191     }
3192 
3193     /**
3194      * @hide
3195      */
disableLocalLocationEnabledCaches()3196     public void disableLocalLocationEnabledCaches() {
3197         synchronized (mLock) {
3198             mLocationEnabledCache = null;
3199         }
3200     }
3201 }
3202