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