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