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