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