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