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