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 com.android.internal.location.ProviderProperties; 20 21import android.Manifest; 22import android.annotation.RequiresPermission; 23import android.annotation.SuppressLint; 24import android.annotation.SystemApi; 25import android.annotation.SystemService; 26import android.annotation.TestApi; 27import android.app.PendingIntent; 28import android.content.Context; 29import android.content.Intent; 30import android.os.Build; 31import android.os.Bundle; 32import android.os.Handler; 33import android.os.Looper; 34import android.os.Message; 35import android.os.RemoteException; 36import android.util.Log; 37 38import java.util.ArrayList; 39import java.util.HashMap; 40import java.util.List; 41 42import static android.Manifest.permission.ACCESS_COARSE_LOCATION; 43import static android.Manifest.permission.ACCESS_FINE_LOCATION; 44 45/** 46 * This class provides access to the system location services. These 47 * services allow applications to obtain periodic updates of the 48 * device's geographical location, or to fire an application-specified 49 * {@link Intent} when the device enters the proximity of a given 50 * geographical location. 51 * 52 * <p class="note">Unless noted, all Location API methods require 53 * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or 54 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. 55 * If your application only has the coarse permission then it will not have 56 * access to the GPS or passive location providers. Other providers will still 57 * return location results, but the update rate will be throttled and the exact 58 * location will be obfuscated to a coarse level of accuracy. 59 */ 60@SystemService(Context.LOCATION_SERVICE) 61public class LocationManager { 62 private static final String TAG = "LocationManager"; 63 64 private final Context mContext; 65 private final ILocationManager mService; 66 private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport; 67 private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport; 68 private final BatchedLocationCallbackTransport mBatchedLocationCallbackTransport; 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<GnssStatus.Callback, GnssStatusListenerTransport> mGnssStatusListeners = 74 new HashMap<>(); 75 private final HashMap<OnNmeaMessageListener, GnssStatusListenerTransport> mGnssNmeaListeners = 76 new HashMap<>(); 77 private GnssStatus mGnssStatus; 78 private int mTimeToFirstFix; 79 80 /** 81 * Name of the network location provider. 82 * <p>This provider determines location based on 83 * availability of cell tower and WiFi access points. Results are retrieved 84 * by means of a network lookup. 85 */ 86 public static final String NETWORK_PROVIDER = "network"; 87 88 /** 89 * Name of the GPS location provider. 90 * 91 * <p>This provider determines location using 92 * satellites. Depending on conditions, this provider may take a while to return 93 * a location fix. Requires the permission 94 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}. 95 * 96 * <p> The extras Bundle for the GPS location provider can contain the 97 * following key/value pairs: 98 * <ul> 99 * <li> satellites - the number of satellites used to derive the fix 100 * </ul> 101 */ 102 public static final String GPS_PROVIDER = "gps"; 103 104 /** 105 * A special location provider for receiving locations without actually initiating 106 * a location fix. 107 * 108 * <p>This provider can be used to passively receive location updates 109 * when other applications or services request them without actually requesting 110 * the locations yourself. This provider will return locations generated by other 111 * providers. You can query the {@link Location#getProvider()} method to determine 112 * the origin of the location update. Requires the permission 113 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is 114 * not enabled this provider might only return coarse fixes. 115 */ 116 public static final String PASSIVE_PROVIDER = "passive"; 117 118 /** 119 * Name of the Fused location provider. 120 * 121 * <p>This provider combines inputs for all possible location sources 122 * to provide the best possible Location fix. It is implicitly 123 * used for all API's that involve the {@link LocationRequest} 124 * object. 125 * 126 * @hide 127 */ 128 public static final String FUSED_PROVIDER = "fused"; 129 130 /** 131 * Key used for the Bundle extra holding a boolean indicating whether 132 * a proximity alert is entering (true) or exiting (false).. 133 */ 134 public static final String KEY_PROXIMITY_ENTERING = "entering"; 135 136 /** 137 * Key used for a Bundle extra holding an Integer status value 138 * when a status change is broadcast using a PendingIntent. 139 */ 140 public static final String KEY_STATUS_CHANGED = "status"; 141 142 /** 143 * Key used for a Bundle extra holding an Boolean status value 144 * when a provider enabled/disabled event is broadcast using a PendingIntent. 145 */ 146 public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; 147 148 /** 149 * Key used for a Bundle extra holding a Location value 150 * when a location change is broadcast using a PendingIntent. 151 */ 152 public static final String KEY_LOCATION_CHANGED = "location"; 153 154 /** 155 * Broadcast intent action indicating that the GPS has either been 156 * enabled or disabled. An intent extra provides this state as a boolean, 157 * where {@code true} means enabled. 158 * @see #EXTRA_GPS_ENABLED 159 * 160 * @hide 161 */ 162 public static final String GPS_ENABLED_CHANGE_ACTION = 163 "android.location.GPS_ENABLED_CHANGE"; 164 165 /** 166 * Broadcast intent action when the configured location providers 167 * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the 168 * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION} 169 * instead. 170 */ 171 public static final String PROVIDERS_CHANGED_ACTION = 172 "android.location.PROVIDERS_CHANGED"; 173 174 /** 175 * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes. 176 * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API. 177 * If you're interacting with {@link #isProviderEnabled(String)}, use 178 * {@link #PROVIDERS_CHANGED_ACTION} instead. 179 * 180 * In the future, there may be mode changes that do not result in 181 * {@link #PROVIDERS_CHANGED_ACTION} broadcasts. 182 */ 183 public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; 184 185 /** 186 * Broadcast intent action indicating that the GPS has either started or 187 * stopped receiving GPS fixes. An intent extra provides this state as a 188 * boolean, where {@code true} means that the GPS is actively receiving fixes. 189 * @see #EXTRA_GPS_ENABLED 190 * 191 * @hide 192 */ 193 public static final String GPS_FIX_CHANGE_ACTION = 194 "android.location.GPS_FIX_CHANGE"; 195 196 /** 197 * The lookup key for a boolean that indicates whether GPS is enabled or 198 * disabled. {@code true} means GPS is enabled. Retrieve it with 199 * {@link android.content.Intent#getBooleanExtra(String,boolean)}. 200 * 201 * @hide 202 */ 203 public static final String EXTRA_GPS_ENABLED = "enabled"; 204 205 /** 206 * Broadcast intent action indicating that a high power location requests 207 * has either started or stopped being active. The current state of 208 * active location requests should be read from AppOpsManager using 209 * {@code OP_MONITOR_HIGH_POWER_LOCATION}. 210 * 211 * @hide 212 */ 213 public static final String HIGH_POWER_REQUEST_CHANGE_ACTION = 214 "android.location.HIGH_POWER_REQUEST_CHANGE"; 215 216 // Map from LocationListeners to their associated ListenerTransport objects 217 private HashMap<LocationListener,ListenerTransport> mListeners = 218 new HashMap<LocationListener,ListenerTransport>(); 219 220 private class ListenerTransport extends ILocationListener.Stub { 221 private static final int TYPE_LOCATION_CHANGED = 1; 222 private static final int TYPE_STATUS_CHANGED = 2; 223 private static final int TYPE_PROVIDER_ENABLED = 3; 224 private static final int TYPE_PROVIDER_DISABLED = 4; 225 226 private LocationListener mListener; 227 private final Handler mListenerHandler; 228 229 ListenerTransport(LocationListener listener, Looper looper) { 230 mListener = listener; 231 232 if (looper == null) { 233 mListenerHandler = new Handler() { 234 @Override 235 public void handleMessage(Message msg) { 236 _handleMessage(msg); 237 } 238 }; 239 } else { 240 mListenerHandler = new Handler(looper) { 241 @Override 242 public void handleMessage(Message msg) { 243 _handleMessage(msg); 244 } 245 }; 246 } 247 } 248 249 @Override 250 public void onLocationChanged(Location location) { 251 Message msg = Message.obtain(); 252 msg.what = TYPE_LOCATION_CHANGED; 253 msg.obj = location; 254 mListenerHandler.sendMessage(msg); 255 } 256 257 @Override 258 public void onStatusChanged(String provider, int status, Bundle extras) { 259 Message msg = Message.obtain(); 260 msg.what = TYPE_STATUS_CHANGED; 261 Bundle b = new Bundle(); 262 b.putString("provider", provider); 263 b.putInt("status", status); 264 if (extras != null) { 265 b.putBundle("extras", extras); 266 } 267 msg.obj = b; 268 mListenerHandler.sendMessage(msg); 269 } 270 271 @Override 272 public void onProviderEnabled(String provider) { 273 Message msg = Message.obtain(); 274 msg.what = TYPE_PROVIDER_ENABLED; 275 msg.obj = provider; 276 mListenerHandler.sendMessage(msg); 277 } 278 279 @Override 280 public void onProviderDisabled(String provider) { 281 Message msg = Message.obtain(); 282 msg.what = TYPE_PROVIDER_DISABLED; 283 msg.obj = provider; 284 mListenerHandler.sendMessage(msg); 285 } 286 287 private void _handleMessage(Message msg) { 288 switch (msg.what) { 289 case TYPE_LOCATION_CHANGED: 290 Location location = new Location((Location) msg.obj); 291 mListener.onLocationChanged(location); 292 break; 293 case TYPE_STATUS_CHANGED: 294 Bundle b = (Bundle) msg.obj; 295 String provider = b.getString("provider"); 296 int status = b.getInt("status"); 297 Bundle extras = b.getBundle("extras"); 298 mListener.onStatusChanged(provider, status, extras); 299 break; 300 case TYPE_PROVIDER_ENABLED: 301 mListener.onProviderEnabled((String) msg.obj); 302 break; 303 case TYPE_PROVIDER_DISABLED: 304 mListener.onProviderDisabled((String) msg.obj); 305 break; 306 } 307 try { 308 mService.locationCallbackFinished(this); 309 } catch (RemoteException e) { 310 throw e.rethrowFromSystemServer(); 311 } 312 } 313 } 314 315 /** 316 * @hide - hide this constructor because it has a parameter 317 * of type ILocationManager, which is a system private class. The 318 * right way to create an instance of this class is using the 319 * factory Context.getSystemService. 320 */ 321 public LocationManager(Context context, ILocationManager service) { 322 mService = service; 323 mContext = context; 324 mGnssMeasurementCallbackTransport = 325 new GnssMeasurementCallbackTransport(mContext, mService); 326 mGnssNavigationMessageCallbackTransport = 327 new GnssNavigationMessageCallbackTransport(mContext, mService); 328 mBatchedLocationCallbackTransport = 329 new BatchedLocationCallbackTransport(mContext, mService); 330 331 } 332 333 private LocationProvider createProvider(String name, ProviderProperties properties) { 334 return new LocationProvider(name, properties); 335 } 336 337 /** 338 * Returns a list of the names of all known location providers. 339 * <p>All providers are returned, including ones that are not permitted to 340 * be accessed by the calling activity or are currently disabled. 341 * 342 * @return list of Strings containing names of the provider 343 */ 344 public List<String> getAllProviders() { 345 try { 346 return mService.getAllProviders(); 347 } catch (RemoteException e) { 348 throw e.rethrowFromSystemServer(); 349 } 350 } 351 352 /** 353 * Returns a list of the names of location providers. 354 * 355 * @param enabledOnly if true then only the providers which are currently 356 * enabled are returned. 357 * @return list of Strings containing names of the providers 358 */ 359 public List<String> getProviders(boolean enabledOnly) { 360 try { 361 return mService.getProviders(null, enabledOnly); 362 } catch (RemoteException e) { 363 throw e.rethrowFromSystemServer(); 364 } 365 } 366 367 /** 368 * Returns the information associated with the location provider of the 369 * given name, or null if no provider exists by that name. 370 * 371 * @param name the provider name 372 * @return a LocationProvider, or null 373 * 374 * @throws IllegalArgumentException if name is null or does not exist 375 * @throws SecurityException if the caller is not permitted to access the 376 * given provider. 377 */ 378 public LocationProvider getProvider(String name) { 379 checkProvider(name); 380 try { 381 ProviderProperties properties = mService.getProviderProperties(name); 382 if (properties == null) { 383 return null; 384 } 385 return createProvider(name, properties); 386 } catch (RemoteException e) { 387 throw e.rethrowFromSystemServer(); 388 } 389 } 390 391 /** 392 * Returns a list of the names of LocationProviders that satisfy the given 393 * criteria, or null if none do. Only providers that are permitted to be 394 * accessed by the calling activity will be returned. 395 * 396 * @param criteria the criteria that the returned providers must match 397 * @param enabledOnly if true then only the providers which are currently 398 * enabled are returned. 399 * @return list of Strings containing names of the providers 400 */ 401 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 402 checkCriteria(criteria); 403 try { 404 return mService.getProviders(criteria, enabledOnly); 405 } catch (RemoteException e) { 406 throw e.rethrowFromSystemServer(); 407 } 408 } 409 410 /** 411 * Returns the name of the provider that best meets the given criteria. Only providers 412 * that are permitted to be accessed by the calling activity will be 413 * returned. If several providers meet the criteria, the one with the best 414 * accuracy is returned. If no provider meets the criteria, 415 * the criteria are loosened in the following sequence: 416 * 417 * <ul> 418 * <li> power requirement 419 * <li> accuracy 420 * <li> bearing 421 * <li> speed 422 * <li> altitude 423 * </ul> 424 * 425 * <p> Note that the requirement on monetary cost is not removed 426 * in this process. 427 * 428 * @param criteria the criteria that need to be matched 429 * @param enabledOnly if true then only a provider that is currently enabled is returned 430 * @return name of the provider that best matches the requirements 431 */ 432 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 433 checkCriteria(criteria); 434 try { 435 return mService.getBestProvider(criteria, enabledOnly); 436 } catch (RemoteException e) { 437 throw e.rethrowFromSystemServer(); 438 } 439 } 440 441 /** 442 * Register for location updates using the named provider, and a 443 * pending intent. 444 * 445 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 446 * for more detail on how to use this method. 447 * 448 * @param provider the name of the provider with which to register 449 * @param minTime minimum time interval between location updates, in milliseconds 450 * @param minDistance minimum distance between location updates, in meters 451 * @param listener a {@link LocationListener} whose 452 * {@link LocationListener#onLocationChanged} method will be called for 453 * each location update 454 * 455 * @throws IllegalArgumentException if provider is null or doesn't exist 456 * on this device 457 * @throws IllegalArgumentException if listener is null 458 * @throws RuntimeException if the calling thread has no Looper 459 * @throws SecurityException if no suitable permission is present 460 */ 461 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 462 public void requestLocationUpdates(String provider, long minTime, float minDistance, 463 LocationListener listener) { 464 checkProvider(provider); 465 checkListener(listener); 466 467 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 468 provider, minTime, minDistance, false); 469 requestLocationUpdates(request, listener, null, null); 470 } 471 472 /** 473 * Register for location updates using the named provider, and a callback on 474 * the specified looper thread. 475 * 476 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 477 * for more detail on how to use this method. 478 * 479 * @param provider the name of the provider with which to register 480 * @param minTime minimum time interval between location updates, in milliseconds 481 * @param minDistance minimum distance between location updates, in meters 482 * @param listener a {@link LocationListener} whose 483 * {@link LocationListener#onLocationChanged} method will be called for 484 * each location update 485 * @param looper a Looper object whose message queue will be used to 486 * implement the callback mechanism, or null to make callbacks on the calling 487 * thread 488 * 489 * @throws IllegalArgumentException if provider is null or doesn't exist 490 * @throws IllegalArgumentException if listener is null 491 * @throws SecurityException if no suitable permission is present 492 */ 493 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 494 public void requestLocationUpdates(String provider, long minTime, float minDistance, 495 LocationListener listener, Looper looper) { 496 checkProvider(provider); 497 checkListener(listener); 498 499 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 500 provider, minTime, minDistance, false); 501 requestLocationUpdates(request, listener, looper, null); 502 } 503 504 /** 505 * Register for location updates using a Criteria, and a callback 506 * on the specified looper thread. 507 * 508 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 509 * for more detail on how to use this method. 510 * 511 * @param minTime minimum time interval between location updates, in milliseconds 512 * @param minDistance minimum distance between location updates, in meters 513 * @param criteria contains parameters for the location manager to choose the 514 * appropriate provider and parameters to compute the location 515 * @param listener a {@link LocationListener} whose 516 * {@link LocationListener#onLocationChanged} method will be called for 517 * each location update 518 * @param looper a Looper object whose message queue will be used to 519 * implement the callback mechanism, or null to make callbacks on the calling 520 * thread 521 * 522 * @throws IllegalArgumentException if criteria is null 523 * @throws IllegalArgumentException if listener is null 524 * @throws SecurityException if no suitable permission is present 525 */ 526 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 527 public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, 528 LocationListener listener, Looper looper) { 529 checkCriteria(criteria); 530 checkListener(listener); 531 532 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 533 criteria, minTime, minDistance, false); 534 requestLocationUpdates(request, listener, looper, null); 535 } 536 537 /** 538 * Register for location updates using the named provider, and a 539 * pending intent. 540 * 541 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 542 * for more detail on how to use this method. 543 * 544 * @param provider the name of the provider with which to register 545 * @param minTime minimum time interval between location updates, in milliseconds 546 * @param minDistance minimum distance between location updates, in meters 547 * @param intent a {@link PendingIntent} to be sent for each location update 548 * 549 * @throws IllegalArgumentException if provider is null or doesn't exist 550 * on this device 551 * @throws IllegalArgumentException if intent is null 552 * @throws SecurityException if no suitable permission is present 553 */ 554 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 555 public void requestLocationUpdates(String provider, long minTime, float minDistance, 556 PendingIntent intent) { 557 checkProvider(provider); 558 checkPendingIntent(intent); 559 560 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 561 provider, minTime, minDistance, false); 562 requestLocationUpdates(request, null, null, intent); 563 } 564 565 /** 566 * Register for location updates using a Criteria and pending intent. 567 * 568 * <p>The <code>requestLocationUpdates()</code> and 569 * <code>requestSingleUpdate()</code> register the current activity to be 570 * updated periodically by the named provider, or by the provider matching 571 * the specified {@link Criteria}, with location and status updates. 572 * 573 * <p> It may take a while to receive the first location update. If 574 * an immediate location is required, applications may use the 575 * {@link #getLastKnownLocation(String)} method. 576 * 577 * <p> Location updates are received either by {@link LocationListener} 578 * callbacks, or by broadcast intents to a supplied {@link PendingIntent}. 579 * 580 * <p> If the caller supplied a pending intent, then location updates 581 * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a 582 * {@link android.location.Location} value. 583 * 584 * <p> The location update interval can be controlled using the minTime parameter. 585 * The elapsed time between location updates will never be less than 586 * minTime, although it can be more depending on the Location Provider 587 * implementation and the update interval requested by other applications. 588 * 589 * <p> Choosing a sensible value for minTime is important to conserve 590 * battery life. Each location update requires power from 591 * GPS, WIFI, Cell and other radios. Select a minTime value as high as 592 * possible while still providing a reasonable user experience. 593 * If your application is not in the foreground and showing 594 * location to the user then your application should avoid using an active 595 * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}), 596 * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes) 597 * or greater. If your application is in the foreground and showing 598 * location to the user then it is appropriate to select a faster 599 * update interval. 600 * 601 * <p> The minDistance parameter can also be used to control the 602 * frequency of location updates. If it is greater than 0 then the 603 * location provider will only send your application an update when 604 * the location has changed by at least minDistance meters, AND 605 * at least minTime milliseconds have passed. However it is more 606 * difficult for location providers to save power using the minDistance 607 * parameter, so minTime should be the primary tool to conserving battery 608 * life. 609 * 610 * <p> If your application wants to passively observe location 611 * updates triggered by other applications, but not consume 612 * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER} 613 * This provider does not actively turn on or modify active location 614 * providers, so you do not need to be as careful about minTime and 615 * minDistance. However if your application performs heavy work 616 * on a location update (such as network activity) then you should 617 * select non-zero values for minTime and/or minDistance to rate-limit 618 * your update frequency in the case another application enables a 619 * location provider with extremely fast updates. 620 * 621 * <p>In case the provider is disabled by the user, updates will stop, 622 * and a provider availability update will be sent. 623 * As soon as the provider is enabled again, 624 * location updates will immediately resume and a provider availability 625 * update sent. Providers can also send status updates, at any time, 626 * with extra's specific to the provider. If a callback was supplied 627 * then status and availability updates are via 628 * {@link LocationListener#onProviderDisabled}, 629 * {@link LocationListener#onProviderEnabled} or 630 * {@link LocationListener#onStatusChanged}. Alternately, if a 631 * pending intent was supplied then status and availability updates 632 * are broadcast intents with extra keys of 633 * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}. 634 * 635 * <p> If a {@link LocationListener} is used but with no Looper specified 636 * then the calling thread must already 637 * be a {@link android.os.Looper} thread such as the main thread of the 638 * calling Activity. If a Looper is specified with a {@link LocationListener} 639 * then callbacks are made on the supplied Looper thread. 640 * 641 * <p class="note"> Prior to Jellybean, the minTime parameter was 642 * only a hint, and some location provider implementations ignored it. 643 * From Jellybean and onwards it is mandatory for Android compatible 644 * devices to observe both the minTime and minDistance parameters. 645 * 646 * @param minTime minimum time interval between location updates, in milliseconds 647 * @param minDistance minimum distance between location updates, in meters 648 * @param criteria contains parameters for the location manager to choose the 649 * appropriate provider and parameters to compute the location 650 * @param intent a {@link PendingIntent} to be sent for each location update 651 * 652 * @throws IllegalArgumentException if criteria is null 653 * @throws IllegalArgumentException if intent is null 654 * @throws SecurityException if no suitable permission is present 655 */ 656 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 657 public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, 658 PendingIntent intent) { 659 checkCriteria(criteria); 660 checkPendingIntent(intent); 661 662 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 663 criteria, minTime, minDistance, false); 664 requestLocationUpdates(request, null, null, intent); 665 } 666 667 /** 668 * Register for a single location update using the named provider and 669 * a callback. 670 * 671 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 672 * for more detail on how to use this method. 673 * 674 * @param provider the name of the provider with which to register 675 * @param listener a {@link LocationListener} whose 676 * {@link LocationListener#onLocationChanged} method will be called when 677 * the location update is available 678 * @param looper a Looper object whose message queue will be used to 679 * implement the callback mechanism, or null to make callbacks on the calling 680 * thread 681 * 682 * @throws IllegalArgumentException if provider is null or doesn't exist 683 * @throws IllegalArgumentException if listener is null 684 * @throws SecurityException if no suitable permission is present 685 */ 686 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 687 public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) { 688 checkProvider(provider); 689 checkListener(listener); 690 691 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 692 provider, 0, 0, true); 693 requestLocationUpdates(request, listener, looper, null); 694 } 695 696 /** 697 * Register for a single location update using a Criteria and 698 * a callback. 699 * 700 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 701 * for more detail on how to use this method. 702 * 703 * @param criteria contains parameters for the location manager to choose the 704 * appropriate provider and parameters to compute the location 705 * @param listener a {@link LocationListener} whose 706 * {@link LocationListener#onLocationChanged} method will be called when 707 * the location update is available 708 * @param looper a Looper object whose message queue will be used to 709 * implement the callback mechanism, or null to make callbacks on the calling 710 * thread 711 * 712 * @throws IllegalArgumentException if criteria is null 713 * @throws IllegalArgumentException if listener is null 714 * @throws SecurityException if no suitable permission is present 715 */ 716 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 717 public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) { 718 checkCriteria(criteria); 719 checkListener(listener); 720 721 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 722 criteria, 0, 0, true); 723 requestLocationUpdates(request, listener, looper, null); 724 } 725 726 /** 727 * Register for a single location update using a named provider and pending intent. 728 * 729 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 730 * for more detail on how to use this method. 731 * 732 * @param provider the name of the provider with which to register 733 * @param intent a {@link PendingIntent} to be sent for the location update 734 * 735 * @throws IllegalArgumentException if provider is null or doesn't exist 736 * @throws IllegalArgumentException if intent is null 737 * @throws SecurityException if no suitable permission is present 738 */ 739 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 740 public void requestSingleUpdate(String provider, PendingIntent intent) { 741 checkProvider(provider); 742 checkPendingIntent(intent); 743 744 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 745 provider, 0, 0, true); 746 requestLocationUpdates(request, null, null, intent); 747 } 748 749 /** 750 * Register for a single location update using a Criteria and pending intent. 751 * 752 * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)} 753 * for more detail on how to use this method. 754 * 755 * @param criteria contains parameters for the location manager to choose the 756 * appropriate provider and parameters to compute the location 757 * @param intent a {@link PendingIntent} to be sent for the location update 758 * 759 * @throws IllegalArgumentException if provider is null or doesn't exist 760 * @throws IllegalArgumentException if intent is null 761 * @throws SecurityException if no suitable permission is present 762 */ 763 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 764 public void requestSingleUpdate(Criteria criteria, PendingIntent intent) { 765 checkCriteria(criteria); 766 checkPendingIntent(intent); 767 768 LocationRequest request = LocationRequest.createFromDeprecatedCriteria( 769 criteria, 0, 0, true); 770 requestLocationUpdates(request, null, null, intent); 771 } 772 773 /** 774 * Register for fused location updates using a LocationRequest and callback. 775 * 776 * <p>Upon a location update, the system delivers the new {@link Location} to the 777 * provided {@link LocationListener}, by calling its {@link 778 * LocationListener#onLocationChanged} method.</p> 779 * 780 * <p>The system will automatically select and enable the best providers 781 * to compute a location for your application. It may use only passive 782 * locations, or just a single location source, or it may fuse together 783 * multiple location sources in order to produce the best possible 784 * result, depending on the quality of service requested in the 785 * {@link LocationRequest}. 786 * 787 * <p>LocationRequest can be null, in which case the system will choose 788 * default, low power parameters for location updates. You will occasionally 789 * receive location updates as available, without a major power impact on the 790 * system. If your application just needs an occasional location update 791 * without any strict demands, then pass a null LocationRequest. 792 * 793 * <p>Only one LocationRequest can be registered for each unique callback 794 * or pending intent. So a subsequent request with the same callback or 795 * pending intent will over-write the previous LocationRequest. 796 * 797 * <p> If a pending intent is supplied then location updates 798 * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a 799 * {@link android.location.Location} value. If a callback is supplied 800 * then location updates are made using the 801 * {@link LocationListener#onLocationChanged} callback, on the specified 802 * Looper thread. If a {@link LocationListener} is used 803 * but with a null Looper then the calling thread must already 804 * be a {@link android.os.Looper} thread (such as the main thread) and 805 * callbacks will occur on this thread. 806 * 807 * <p> Provider status updates and availability updates are deprecated 808 * because the system is performing provider fusion on the applications 809 * behalf. So {@link LocationListener#onProviderDisabled}, 810 * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged} 811 * will not be called, and intents with extra keys of 812 * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not 813 * be received. 814 * 815 * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}. 816 * 817 * @param request quality of service required, null for default low power 818 * @param listener a {@link LocationListener} whose 819 * {@link LocationListener#onLocationChanged} method will be called when 820 * the location update is available 821 * @param looper a Looper object whose message queue will be used to 822 * implement the callback mechanism, or null to make callbacks on the calling 823 * thread 824 * 825 * @throws IllegalArgumentException if listener is null 826 * @throws SecurityException if no suitable permission is present 827 * 828 * @hide 829 */ 830 @SystemApi 831 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 832 public void requestLocationUpdates(LocationRequest request, LocationListener listener, 833 Looper looper) { 834 checkListener(listener); 835 requestLocationUpdates(request, listener, looper, null); 836 } 837 838 839 /** 840 * Register for fused location updates using a LocationRequest and a pending intent. 841 * 842 * <p>Upon a location update, the system delivers the new {@link Location} with your provided 843 * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED} 844 * in the intent's extras.</p> 845 * 846 * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}. 847 * 848 * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} 849 * for more detail. 850 * 851 * @param request quality of service required, null for default low power 852 * @param intent a {@link PendingIntent} to be sent for the location update 853 * 854 * @throws IllegalArgumentException if intent is null 855 * @throws SecurityException if no suitable permission is present 856 * 857 * @hide 858 */ 859 @SystemApi 860 @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION}) 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 GnssStatus.Callback mGnssCallback; 1402 private final OnNmeaMessageListener mGnssNmeaListener; 1403 1404 private class GnssHandler extends Handler { 1405 public GnssHandler(Handler handler) { 1406 super(handler != null ? handler.getLooper() : Looper.myLooper()); 1407 } 1408 1409 @Override 1410 public void handleMessage(Message msg) { 1411 switch (msg.what) { 1412 case NMEA_RECEIVED: 1413 synchronized (mNmeaBuffer) { 1414 int length = mNmeaBuffer.size(); 1415 for (int i = 0; i < length; i++) { 1416 Nmea nmea = mNmeaBuffer.get(i); 1417 mGnssNmeaListener.onNmeaMessage(nmea.mNmea, nmea.mTimestamp); 1418 } 1419 mNmeaBuffer.clear(); 1420 } 1421 break; 1422 case GpsStatus.GPS_EVENT_STARTED: 1423 mGnssCallback.onStarted(); 1424 break; 1425 case GpsStatus.GPS_EVENT_STOPPED: 1426 mGnssCallback.onStopped(); 1427 break; 1428 case GpsStatus.GPS_EVENT_FIRST_FIX: 1429 mGnssCallback.onFirstFix(mTimeToFirstFix); 1430 break; 1431 case GpsStatus.GPS_EVENT_SATELLITE_STATUS: 1432 mGnssCallback.onSatelliteStatusChanged(mGnssStatus); 1433 break; 1434 default: 1435 break; 1436 } 1437 } 1438 } 1439 1440 private final Handler mGnssHandler; 1441 1442 // This must not equal any of the GpsStatus event IDs 1443 private static final int NMEA_RECEIVED = 1000; 1444 1445 private class Nmea { 1446 long mTimestamp; 1447 String mNmea; 1448 1449 Nmea(long timestamp, String nmea) { 1450 mTimestamp = timestamp; 1451 mNmea = nmea; 1452 } 1453 } 1454 private final ArrayList<Nmea> mNmeaBuffer; 1455 1456 GnssStatusListenerTransport(GpsStatus.Listener listener) { 1457 this(listener, null); 1458 } 1459 1460 GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) { 1461 mGpsListener = listener; 1462 mGnssHandler = new GnssHandler(handler); 1463 mGpsNmeaListener = null; 1464 mNmeaBuffer = null; 1465 mGnssCallback = mGpsListener != null ? new GnssStatus.Callback() { 1466 @Override 1467 public void onStarted() { 1468 mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED); 1469 } 1470 1471 @Override 1472 public void onStopped() { 1473 mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED); 1474 } 1475 1476 @Override 1477 public void onFirstFix(int ttff) { 1478 mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX); 1479 } 1480 1481 @Override 1482 public void onSatelliteStatusChanged(GnssStatus status) { 1483 mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS); 1484 } 1485 } : null; 1486 mGnssNmeaListener = null; 1487 } 1488 1489 GnssStatusListenerTransport(GpsStatus.NmeaListener listener) { 1490 this(listener, null); 1491 } 1492 1493 GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) { 1494 mGpsListener = null; 1495 mGnssHandler = new GnssHandler(handler); 1496 mGpsNmeaListener = listener; 1497 mNmeaBuffer = new ArrayList<Nmea>(); 1498 mGnssCallback = null; 1499 mGnssNmeaListener = mGpsNmeaListener != null ? new OnNmeaMessageListener() { 1500 @Override 1501 public void onNmeaMessage(String nmea, long timestamp) { 1502 mGpsNmeaListener.onNmeaReceived(timestamp, nmea); 1503 } 1504 } : null; 1505 } 1506 1507 GnssStatusListenerTransport(GnssStatus.Callback callback) { 1508 this(callback, null); 1509 } 1510 1511 GnssStatusListenerTransport(GnssStatus.Callback callback, Handler handler) { 1512 mGnssCallback = callback; 1513 mGnssHandler = new GnssHandler(handler); 1514 mGnssNmeaListener = null; 1515 mNmeaBuffer = null; 1516 mGpsListener = null; 1517 mGpsNmeaListener = null; 1518 } 1519 1520 GnssStatusListenerTransport(OnNmeaMessageListener listener) { 1521 this(listener, null); 1522 } 1523 1524 GnssStatusListenerTransport(OnNmeaMessageListener listener, Handler handler) { 1525 mGnssCallback = null; 1526 mGnssHandler = new GnssHandler(handler); 1527 mGnssNmeaListener = listener; 1528 mGpsListener = null; 1529 mGpsNmeaListener = null; 1530 mNmeaBuffer = new ArrayList<Nmea>(); 1531 } 1532 1533 @Override 1534 public void onGnssStarted() { 1535 if (mGnssCallback != null) { 1536 Message msg = Message.obtain(); 1537 msg.what = GpsStatus.GPS_EVENT_STARTED; 1538 mGnssHandler.sendMessage(msg); 1539 } 1540 } 1541 1542 @Override 1543 public void onGnssStopped() { 1544 if (mGnssCallback != null) { 1545 Message msg = Message.obtain(); 1546 msg.what = GpsStatus.GPS_EVENT_STOPPED; 1547 mGnssHandler.sendMessage(msg); 1548 } 1549 } 1550 1551 @Override 1552 public void onFirstFix(int ttff) { 1553 if (mGnssCallback != null) { 1554 mTimeToFirstFix = ttff; 1555 Message msg = Message.obtain(); 1556 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; 1557 mGnssHandler.sendMessage(msg); 1558 } 1559 } 1560 1561 @Override 1562 public void onSvStatusChanged(int svCount, int[] prnWithFlags, 1563 float[] cn0s, float[] elevations, float[] azimuths, float[] carrierFreqs) { 1564 if (mGnssCallback != null) { 1565 mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths, 1566 carrierFreqs); 1567 1568 Message msg = Message.obtain(); 1569 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; 1570 // remove any SV status messages already in the queue 1571 mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); 1572 mGnssHandler.sendMessage(msg); 1573 } 1574 } 1575 1576 @Override 1577 public void onNmeaReceived(long timestamp, String nmea) { 1578 if (mGnssNmeaListener != null) { 1579 synchronized (mNmeaBuffer) { 1580 mNmeaBuffer.add(new Nmea(timestamp, nmea)); 1581 } 1582 Message msg = Message.obtain(); 1583 msg.what = NMEA_RECEIVED; 1584 // remove any NMEA_RECEIVED messages already in the queue 1585 mGnssHandler.removeMessages(NMEA_RECEIVED); 1586 mGnssHandler.sendMessage(msg); 1587 } 1588 } 1589 } 1590 1591 /** 1592 * Adds a GPS status listener. 1593 * 1594 * @param listener GPS status listener object to register 1595 * 1596 * @return true if the listener was successfully added 1597 * 1598 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1599 * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead. 1600 */ 1601 @Deprecated 1602 @RequiresPermission(ACCESS_FINE_LOCATION) 1603 public boolean addGpsStatusListener(GpsStatus.Listener listener) { 1604 boolean result; 1605 1606 if (mGpsStatusListeners.get(listener) != null) { 1607 // listener is already registered 1608 return true; 1609 } 1610 try { 1611 GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener); 1612 result = mService.registerGnssStatusCallback(transport, mContext.getPackageName()); 1613 if (result) { 1614 mGpsStatusListeners.put(listener, transport); 1615 } 1616 } catch (RemoteException e) { 1617 throw e.rethrowFromSystemServer(); 1618 } 1619 1620 return result; 1621 } 1622 1623 /** 1624 * Removes a GPS status listener. 1625 * 1626 * @param listener GPS status listener object to remove 1627 * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead. 1628 */ 1629 @Deprecated 1630 public void removeGpsStatusListener(GpsStatus.Listener listener) { 1631 try { 1632 GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener); 1633 if (transport != null) { 1634 mService.unregisterGnssStatusCallback(transport); 1635 } 1636 } catch (RemoteException e) { 1637 throw e.rethrowFromSystemServer(); 1638 } 1639 } 1640 1641 /** 1642 * Registers a GNSS status callback. 1643 * 1644 * @param callback GNSS status callback object to register 1645 * 1646 * @return true if the listener was successfully added 1647 * 1648 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1649 */ 1650 @RequiresPermission(ACCESS_FINE_LOCATION) 1651 public boolean registerGnssStatusCallback(GnssStatus.Callback callback) { 1652 return registerGnssStatusCallback(callback, null); 1653 } 1654 1655 /** 1656 * Registers a GNSS status callback. 1657 * 1658 * @param callback GNSS status callback object to register 1659 * @param handler the handler that the callback runs on. 1660 * 1661 * @return true if the listener was successfully added 1662 * 1663 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1664 */ 1665 @RequiresPermission(ACCESS_FINE_LOCATION) 1666 public boolean registerGnssStatusCallback(GnssStatus.Callback callback, Handler handler) { 1667 boolean result; 1668 if (mGnssStatusListeners.get(callback) != null) { 1669 // listener is already registered 1670 return true; 1671 } 1672 try { 1673 GnssStatusListenerTransport transport = 1674 new GnssStatusListenerTransport(callback, handler); 1675 result = mService.registerGnssStatusCallback(transport, mContext.getPackageName()); 1676 if (result) { 1677 mGnssStatusListeners.put(callback, transport); 1678 } 1679 } catch (RemoteException e) { 1680 throw e.rethrowFromSystemServer(); 1681 } 1682 1683 return result; 1684 } 1685 1686 /** 1687 * Removes a GNSS status callback. 1688 * 1689 * @param callback GNSS status callback object to remove 1690 */ 1691 public void unregisterGnssStatusCallback(GnssStatus.Callback callback) { 1692 try { 1693 GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback); 1694 if (transport != null) { 1695 mService.unregisterGnssStatusCallback(transport); 1696 } 1697 } catch (RemoteException e) { 1698 throw e.rethrowFromSystemServer(); 1699 } 1700 } 1701 1702 /** 1703 * Adds an NMEA listener. 1704 * 1705 * @param listener a {@link GpsStatus.NmeaListener} object to register 1706 * 1707 * @return true if the listener was successfully added 1708 * 1709 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1710 * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead. 1711 */ 1712 @Deprecated 1713 @RequiresPermission(ACCESS_FINE_LOCATION) 1714 public boolean addNmeaListener(GpsStatus.NmeaListener listener) { 1715 boolean result; 1716 1717 if (mGpsNmeaListeners.get(listener) != null) { 1718 // listener is already registered 1719 return true; 1720 } 1721 try { 1722 GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener); 1723 result = mService.registerGnssStatusCallback(transport, mContext.getPackageName()); 1724 if (result) { 1725 mGpsNmeaListeners.put(listener, transport); 1726 } 1727 } catch (RemoteException e) { 1728 throw e.rethrowFromSystemServer(); 1729 } 1730 1731 return result; 1732 } 1733 1734 /** 1735 * Removes an NMEA listener. 1736 * 1737 * @param listener a {@link GpsStatus.NmeaListener} object to remove 1738 * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead. 1739 */ 1740 @Deprecated 1741 public void removeNmeaListener(GpsStatus.NmeaListener listener) { 1742 try { 1743 GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener); 1744 if (transport != null) { 1745 mService.unregisterGnssStatusCallback(transport); 1746 } 1747 } catch (RemoteException e) { 1748 throw e.rethrowFromSystemServer(); 1749 } 1750 } 1751 1752 /** 1753 * Adds an NMEA listener. 1754 * 1755 * @param listener a {@link OnNmeaMessageListener} object to register 1756 * 1757 * @return true if the listener was successfully added 1758 * 1759 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1760 */ 1761 @RequiresPermission(ACCESS_FINE_LOCATION) 1762 public boolean addNmeaListener(OnNmeaMessageListener listener) { 1763 return addNmeaListener(listener, null); 1764 } 1765 1766 /** 1767 * Adds an NMEA listener. 1768 * 1769 * @param listener a {@link OnNmeaMessageListener} object to register 1770 * @param handler the handler that the listener runs on. 1771 * 1772 * @return true if the listener was successfully added 1773 * 1774 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1775 */ 1776 @RequiresPermission(ACCESS_FINE_LOCATION) 1777 public boolean addNmeaListener(OnNmeaMessageListener listener, Handler handler) { 1778 boolean result; 1779 1780 if (mGpsNmeaListeners.get(listener) != null) { 1781 // listener is already registered 1782 return true; 1783 } 1784 try { 1785 GnssStatusListenerTransport transport = 1786 new GnssStatusListenerTransport(listener, handler); 1787 result = mService.registerGnssStatusCallback(transport, mContext.getPackageName()); 1788 if (result) { 1789 mGnssNmeaListeners.put(listener, transport); 1790 } 1791 } catch (RemoteException e) { 1792 throw e.rethrowFromSystemServer(); 1793 } 1794 1795 return result; 1796 } 1797 1798 /** 1799 * Removes an NMEA listener. 1800 * 1801 * @param listener a {@link OnNmeaMessageListener} object to remove 1802 */ 1803 public void removeNmeaListener(OnNmeaMessageListener listener) { 1804 try { 1805 GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener); 1806 if (transport != null) { 1807 mService.unregisterGnssStatusCallback(transport); 1808 } 1809 } catch (RemoteException e) { 1810 throw e.rethrowFromSystemServer(); 1811 } 1812 } 1813 1814 /** 1815 * No-op method to keep backward-compatibility. 1816 * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead. 1817 * @hide 1818 * @deprecated Not supported anymore. 1819 */ 1820 @Deprecated 1821 @SystemApi 1822 @SuppressLint("Doclava125") 1823 public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) { 1824 return false; 1825 } 1826 1827 /** 1828 * Registers a GPS Measurement callback. 1829 * 1830 * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. 1831 * @return {@code true} if the callback was added successfully, {@code false} otherwise. 1832 */ 1833 @RequiresPermission(ACCESS_FINE_LOCATION) 1834 public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) { 1835 return registerGnssMeasurementsCallback(callback, null); 1836 } 1837 1838 /** 1839 * Registers a GPS Measurement callback. 1840 * 1841 * @param callback a {@link GnssMeasurementsEvent.Callback} object to register. 1842 * @param handler the handler that the callback runs on. 1843 * @return {@code true} if the callback was added successfully, {@code false} otherwise. 1844 */ 1845 @RequiresPermission(ACCESS_FINE_LOCATION) 1846 public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback, 1847 Handler handler) { 1848 return mGnssMeasurementCallbackTransport.add(callback, handler); 1849 } 1850 1851 /** 1852 * No-op method to keep backward-compatibility. 1853 * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead. 1854 * @hide 1855 * @deprecated use {@link #unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback)} 1856 * instead. 1857 */ 1858 @Deprecated 1859 @SystemApi 1860 @SuppressLint("Doclava125") 1861 public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) { 1862 } 1863 1864 /** 1865 * Unregisters a GPS Measurement callback. 1866 * 1867 * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove. 1868 */ 1869 public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) { 1870 mGnssMeasurementCallbackTransport.remove(callback); 1871 } 1872 1873 /** 1874 * No-op method to keep backward-compatibility. 1875 * Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead. 1876 * @hide 1877 * @deprecated Not supported anymore. 1878 */ 1879 @Deprecated 1880 @SystemApi 1881 @SuppressLint("Doclava125") 1882 public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) { 1883 return false; 1884 } 1885 1886 /** 1887 * No-op method to keep backward-compatibility. 1888 * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead. 1889 * @hide 1890 * @deprecated use 1891 * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)} 1892 * instead 1893 */ 1894 @Deprecated 1895 @SystemApi 1896 @SuppressLint("Doclava125") 1897 public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) { 1898 } 1899 1900 /** 1901 * Registers a GNSS Navigation Message callback. 1902 * 1903 * @param callback a {@link GnssNavigationMessage.Callback} object to register. 1904 * @return {@code true} if the callback was added successfully, {@code false} otherwise. 1905 */ 1906 public boolean registerGnssNavigationMessageCallback( 1907 GnssNavigationMessage.Callback callback) { 1908 return registerGnssNavigationMessageCallback(callback, null); 1909 } 1910 1911 /** 1912 * Registers a GNSS Navigation Message callback. 1913 * 1914 * @param callback a {@link GnssNavigationMessage.Callback} object to register. 1915 * @param handler the handler that the callback runs on. 1916 * @return {@code true} if the callback was added successfully, {@code false} otherwise. 1917 */ 1918 @RequiresPermission(ACCESS_FINE_LOCATION) 1919 public boolean registerGnssNavigationMessageCallback( 1920 GnssNavigationMessage.Callback callback, Handler handler) { 1921 return mGnssNavigationMessageCallbackTransport.add(callback, handler); 1922 } 1923 1924 /** 1925 * Unregisters a GNSS Navigation Message callback. 1926 * 1927 * @param callback a {@link GnssNavigationMessage.Callback} object to remove. 1928 */ 1929 public void unregisterGnssNavigationMessageCallback( 1930 GnssNavigationMessage.Callback callback) { 1931 mGnssNavigationMessageCallbackTransport.remove(callback); 1932 } 1933 1934 /** 1935 * Retrieves information about the current status of the GPS engine. 1936 * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} 1937 * callback to ensure that the data is copied atomically. 1938 * 1939 * The caller may either pass in a {@link GpsStatus} object to set with the latest 1940 * status information, or pass null to create a new {@link GpsStatus} object. 1941 * 1942 * @param status object containing GPS status details, or null. 1943 * @return status object containing updated GPS status. 1944 */ 1945 @Deprecated 1946 @RequiresPermission(ACCESS_FINE_LOCATION) 1947 public GpsStatus getGpsStatus(GpsStatus status) { 1948 if (status == null) { 1949 status = new GpsStatus(); 1950 } 1951 // When mGnssStatus is null, that means that this method is called outside 1952 // onGpsStatusChanged(). Return an empty status to maintain backwards compatibility. 1953 if (mGnssStatus != null) { 1954 status.setStatus(mGnssStatus, mTimeToFirstFix); 1955 } 1956 return status; 1957 } 1958 1959 /** 1960 * Returns the system information of the GPS hardware. 1961 * May return 0 if GPS hardware is earlier than 2016. 1962 * @hide 1963 */ 1964 @TestApi 1965 public int getGnssYearOfHardware() { 1966 try { 1967 return mService.getGnssYearOfHardware(); 1968 } catch (RemoteException e) { 1969 throw e.rethrowFromSystemServer(); 1970 } 1971 } 1972 1973 /** 1974 * Returns the batch size (in number of Location objects) that are supported by the batching 1975 * interface. 1976 * 1977 * @return Maximum number of location objects that can be returned 1978 * @hide 1979 */ 1980 @SystemApi 1981 @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) 1982 public int getGnssBatchSize() { 1983 try { 1984 return mService.getGnssBatchSize(mContext.getPackageName()); 1985 } catch (RemoteException e) { 1986 throw e.rethrowFromSystemServer(); 1987 } 1988 } 1989 1990 /** 1991 * Start hardware-batching of GNSS locations. This API is primarily used when the AP is 1992 * asleep and the device can batch GNSS locations in the hardware. 1993 * 1994 * Note this is designed (as was the fused location interface before it) for a single user 1995 * SystemApi - requests are not consolidated. Care should be taken when the System switches 1996 * users that may have different batching requests, to stop hardware batching for one user, and 1997 * restart it for the next. 1998 * 1999 * @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested 2000 * within the batch 2001 * @param wakeOnFifoFull True if the hardware batching should flush the locations in a 2002 * a callback to the listener, when it's internal buffer is full. If 2003 * set to false, the oldest location information is, instead, 2004 * dropped when the buffer is full. 2005 * @param callback The listener on which to return the batched locations 2006 * @param handler The handler on which to process the callback 2007 * 2008 * @return True if batching was successfully started 2009 * @hide 2010 */ 2011 @SystemApi 2012 @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) 2013 public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull, 2014 BatchedLocationCallback callback, Handler handler) { 2015 mBatchedLocationCallbackTransport.add(callback, handler); 2016 2017 try { 2018 return mService.startGnssBatch(periodNanos, wakeOnFifoFull, mContext.getPackageName()); 2019 } catch (RemoteException e) { 2020 throw e.rethrowFromSystemServer(); 2021 } 2022 } 2023 2024 /** 2025 * Flush the batched GNSS locations. 2026 * All GNSS locations currently ready in the batch are returned via the callback sent in 2027 * startGnssBatch(), and the buffer containing the batched locations is cleared. 2028 * 2029 * @hide 2030 */ 2031 @SystemApi 2032 @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) 2033 public void flushGnssBatch() { 2034 try { 2035 mService.flushGnssBatch(mContext.getPackageName()); 2036 } catch (RemoteException e) { 2037 throw e.rethrowFromSystemServer(); 2038 } 2039 } 2040 2041 /** 2042 * Stop batching locations. This API is primarily used when the AP is 2043 * asleep and the device can batch locations in the hardware. 2044 * 2045 * @param callback the specific callback class to remove from the transport layer 2046 * 2047 * @return True if batching was successfully started 2048 * @hide 2049 */ 2050 @SystemApi 2051 @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) 2052 public boolean unregisterGnssBatchedLocationCallback(BatchedLocationCallback callback) { 2053 2054 mBatchedLocationCallbackTransport.remove(callback); 2055 2056 try { 2057 return mService.stopGnssBatch(); 2058 } catch (RemoteException e) { 2059 throw e.rethrowFromSystemServer(); 2060 } 2061 } 2062 2063 /** 2064 * Sends additional commands to a location provider. 2065 * Can be used to support provider specific extensions to the Location Manager API 2066 * 2067 * @param provider name of the location provider. 2068 * @param command name of the command to send to the provider. 2069 * @param extras optional arguments for the command (or null). 2070 * The provider may optionally fill the extras Bundle with results from the command. 2071 * 2072 * @return true if the command succeeds. 2073 */ 2074 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 2075 try { 2076 return mService.sendExtraCommand(provider, command, extras); 2077 } catch (RemoteException e) { 2078 throw e.rethrowFromSystemServer(); 2079 } 2080 } 2081 2082 /** 2083 * Used by NetInitiatedActivity to report user response 2084 * for network initiated GPS fix requests. 2085 * 2086 * @hide 2087 */ 2088 public boolean sendNiResponse(int notifId, int userResponse) { 2089 try { 2090 return mService.sendNiResponse(notifId, userResponse); 2091 } catch (RemoteException e) { 2092 throw e.rethrowFromSystemServer(); 2093 } 2094 } 2095 2096 private static void checkProvider(String provider) { 2097 if (provider == null) { 2098 throw new IllegalArgumentException("invalid provider: " + provider); 2099 } 2100 } 2101 2102 private static void checkCriteria(Criteria criteria) { 2103 if (criteria == null) { 2104 throw new IllegalArgumentException("invalid criteria: " + criteria); 2105 } 2106 } 2107 2108 private static void checkListener(LocationListener listener) { 2109 if (listener == null) { 2110 throw new IllegalArgumentException("invalid listener: " + listener); 2111 } 2112 } 2113 2114 private void checkPendingIntent(PendingIntent intent) { 2115 if (intent == null) { 2116 throw new IllegalArgumentException("invalid pending intent: " + intent); 2117 } 2118 if (!intent.isTargetedToPackage()) { 2119 IllegalArgumentException e = new IllegalArgumentException( 2120 "pending intent must be targeted to package"); 2121 if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) { 2122 throw e; 2123 } else { 2124 Log.w(TAG, e); 2125 } 2126 } 2127 } 2128 2129 private static void checkGeofence(Geofence fence) { 2130 if (fence == null) { 2131 throw new IllegalArgumentException("invalid geofence: " + fence); 2132 } 2133 } 2134} 2135