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 * <receiver android:name="com.example.android.footer.MyFooterInjector"> 294 * <intent-filter> 295 * <action android:name="com.android.settings.location.INJECT_FOOTER" /> 296 * </intent-filter> 297 * <meta-data 298 * android:name="com.android.settings.location.FOOTER_STRING" 299 * android:resource="@string/my_injected_footer_string" /> 300 * </receiver> 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