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