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 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 ListenerTransport(LocationListener listener, Looper looper)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 onLocationChanged(Location location)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 onStatusChanged(String provider, int status, Bundle extras)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 onProviderEnabled(String provider)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 onProviderDisabled(String provider)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 _handleMessage(Message msg)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 */ LocationManager(Context context, ILocationManager service)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 createProvider(String name, ProviderProperties properties)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 */ getAllProviders()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 */ getProviders(boolean enabledOnly)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 */ getProvider(String name)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 */ getProviders(Criteria criteria, boolean enabledOnly)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 */ getBestProvider(Criteria criteria, boolean enabledOnly)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}) requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)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}) requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener, Looper looper)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}) requestLocationUpdates(long minTime, float minDistance, Criteria criteria, LocationListener listener, Looper looper)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}) requestLocationUpdates(String provider, long minTime, float minDistance, PendingIntent intent)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}) requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent)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}) requestSingleUpdate(String provider, LocationListener listener, Looper looper)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}) requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper)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}) requestSingleUpdate(String provider, PendingIntent intent)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}) requestSingleUpdate(Criteria criteria, PendingIntent intent)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}) requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper)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}) requestLocationUpdates(LocationRequest request, PendingIntent intent)861 public void requestLocationUpdates(LocationRequest request, PendingIntent intent) { 862 checkPendingIntent(intent); 863 requestLocationUpdates(request, null, null, intent); 864 } 865 wrapListener(LocationListener listener, Looper looper)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 requestLocationUpdates(LocationRequest request, LocationListener listener, Looper looper, PendingIntent intent)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 */ removeUpdates(LocationListener listener)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 */ removeUpdates(PendingIntent intent)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}) addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntent intent)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}) addGeofence(LocationRequest request, Geofence fence, PendingIntent intent)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 */ removeProximityAlert(PendingIntent intent)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 */ removeGeofence(Geofence fence, PendingIntent intent)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 */ removeAllGeofences(PendingIntent intent)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 */ isProviderEnabled(String provider)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 */ getLastLocation()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}) getLastKnownLocation(String provider)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 */ addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy)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 */ removeTestProvider(String provider)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 */ setTestProviderLocation(String provider, Location loc)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 */ clearTestProviderLocation(String provider)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 */ setTestProviderEnabled(String provider, boolean enabled)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 */ clearTestProviderEnabled(String provider)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 */ setTestProviderStatus(String provider, int status, Bundle extras, long updateTime)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 */ clearTestProviderStatus(String provider)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 { GnssHandler(Handler handler)1405 public GnssHandler(Handler handler) { 1406 super(handler != null ? handler.getLooper() : Looper.myLooper()); 1407 } 1408 1409 @Override handleMessage(Message msg)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 Nmea(long timestamp, String nmea)1449 Nmea(long timestamp, String nmea) { 1450 mTimestamp = timestamp; 1451 mNmea = nmea; 1452 } 1453 } 1454 private final ArrayList<Nmea> mNmeaBuffer; 1455 GnssStatusListenerTransport(GpsStatus.Listener listener)1456 GnssStatusListenerTransport(GpsStatus.Listener listener) { 1457 this(listener, null); 1458 } 1459 GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler)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 GnssStatusListenerTransport(GpsStatus.NmeaListener listener)1489 GnssStatusListenerTransport(GpsStatus.NmeaListener listener) { 1490 this(listener, null); 1491 } 1492 GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler)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 GnssStatusListenerTransport(GnssStatus.Callback callback)1507 GnssStatusListenerTransport(GnssStatus.Callback callback) { 1508 this(callback, null); 1509 } 1510 GnssStatusListenerTransport(GnssStatus.Callback callback, Handler handler)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 GnssStatusListenerTransport(OnNmeaMessageListener listener)1520 GnssStatusListenerTransport(OnNmeaMessageListener listener) { 1521 this(listener, null); 1522 } 1523 GnssStatusListenerTransport(OnNmeaMessageListener listener, Handler handler)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 onGnssStarted()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 onGnssStopped()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 onFirstFix(int ttff)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 onSvStatusChanged(int svCount, int[] prnWithFlags, float[] cn0s, float[] elevations, float[] azimuths, float[] carrierFreqs)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 onNmeaReceived(long timestamp, String nmea)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) addGpsStatusListener(GpsStatus.Listener listener)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 removeGpsStatusListener(GpsStatus.Listener listener)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) registerGnssStatusCallback(GnssStatus.Callback callback)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) registerGnssStatusCallback(GnssStatus.Callback callback, Handler handler)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 */ unregisterGnssStatusCallback(GnssStatus.Callback callback)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) addNmeaListener(GpsStatus.NmeaListener listener)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 removeNmeaListener(GpsStatus.NmeaListener listener)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) addNmeaListener(OnNmeaMessageListener listener)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) addNmeaListener(OnNmeaMessageListener listener, Handler handler)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 */ removeNmeaListener(OnNmeaMessageListener listener)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") addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)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) registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback)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) registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback, Handler handler)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") removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener)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 */ unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback)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") addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)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") removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener)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 */ registerGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback)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) registerGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback, Handler handler)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 */ unregisterGnssNavigationMessageCallback( GnssNavigationMessage.Callback callback)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) getGpsStatus(GpsStatus status)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 getGnssYearOfHardware()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) getGnssBatchSize()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) registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull, BatchedLocationCallback callback, Handler handler)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) flushGnssBatch()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) unregisterGnssBatchedLocationCallback(BatchedLocationCallback callback)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 */ sendExtraCommand(String provider, String command, Bundle extras)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 */ sendNiResponse(int notifId, int userResponse)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 checkProvider(String provider)2096 private static void checkProvider(String provider) { 2097 if (provider == null) { 2098 throw new IllegalArgumentException("invalid provider: " + provider); 2099 } 2100 } 2101 checkCriteria(Criteria criteria)2102 private static void checkCriteria(Criteria criteria) { 2103 if (criteria == null) { 2104 throw new IllegalArgumentException("invalid criteria: " + criteria); 2105 } 2106 } 2107 checkListener(LocationListener listener)2108 private static void checkListener(LocationListener listener) { 2109 if (listener == null) { 2110 throw new IllegalArgumentException("invalid listener: " + listener); 2111 } 2112 } 2113 checkPendingIntent(PendingIntent intent)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 checkGeofence(Geofence fence)2129 private static void checkGeofence(Geofence fence) { 2130 if (fence == null) { 2131 throw new IllegalArgumentException("invalid geofence: " + fence); 2132 } 2133 } 2134 } 2135