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