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