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