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