LocationManagerService.java revision 61fc286e8f7e33d0dd2a1e72ae9ef73ed3f42a00
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import java.io.BufferedReader; 20import java.io.File; 21import java.io.FileDescriptor; 22import java.io.FileReader; 23import java.io.FileWriter; 24import java.io.IOException; 25import java.io.PrintWriter; 26import java.util.ArrayList; 27import java.util.HashMap; 28import java.util.HashSet; 29import java.util.List; 30import java.util.Map; 31import java.util.Observable; 32import java.util.Observer; 33import java.util.Set; 34import java.util.regex.Pattern; 35 36import android.app.AlarmManager; 37import android.app.PendingIntent; 38import android.content.BroadcastReceiver; 39import android.content.ContentQueryMap; 40import android.content.ContentResolver; 41import android.content.Context; 42import android.content.Intent; 43import android.content.IntentFilter; 44import android.content.pm.PackageManager; 45import android.database.Cursor; 46import android.location.Address; 47import android.location.IGeocodeProvider; 48import android.location.IGpsStatusListener; 49import android.location.ILocationCollector; 50import android.location.ILocationListener; 51import android.location.ILocationManager; 52import android.location.ILocationProvider; 53import android.location.Location; 54import android.location.LocationManager; 55import android.location.LocationProvider; 56import android.location.LocationProviderImpl; 57import android.net.ConnectivityManager; 58import android.net.Uri; 59import android.os.Binder; 60import android.os.Bundle; 61import android.os.Handler; 62import android.os.IBinder; 63import android.os.Message; 64import android.os.PowerManager; 65import android.os.Process; 66import android.os.RemoteException; 67import android.os.SystemClock; 68import android.provider.Settings; 69import android.util.Config; 70import android.util.Log; 71import android.util.PrintWriterPrinter; 72import android.util.SparseIntArray; 73 74import com.android.internal.location.GpsLocationProvider; 75import com.android.internal.location.LocationProviderProxy; 76import com.android.internal.location.MockProvider; 77import com.android.internal.location.TrackProvider; 78import com.android.server.am.BatteryStatsService; 79 80/** 81 * The service class that manages LocationProviders and issues location 82 * updates and alerts. 83 * 84 * {@hide} 85 */ 86public class LocationManagerService extends ILocationManager.Stub { 87 private static final String TAG = "LocationManagerService"; 88 private static final boolean LOCAL_LOGV = false; 89 90 // Minimum time interval between last known location writes, in milliseconds. 91 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L; 92 93 // Max time to hold wake lock for, in milliseconds. 94 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L; 95 96 // Time to wait after releasing a wake lock for clients to process location update, 97 // in milliseconds. 98 private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L; 99 100 // The last time a location was written, by provider name. 101 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>(); 102 103 private static final Pattern PATTERN_COMMA = Pattern.compile(","); 104 105 private static final String ACCESS_FINE_LOCATION = 106 android.Manifest.permission.ACCESS_FINE_LOCATION; 107 private static final String ACCESS_COARSE_LOCATION = 108 android.Manifest.permission.ACCESS_COARSE_LOCATION; 109 private static final String ACCESS_MOCK_LOCATION = 110 android.Manifest.permission.ACCESS_MOCK_LOCATION; 111 private static final String ACCESS_LOCATION_EXTRA_COMMANDS = 112 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; 113 114 // Set of providers that are explicitly enabled 115 private final Set<String> mEnabledProviders = new HashSet<String>(); 116 117 // Set of providers that are explicitly disabled 118 private final Set<String> mDisabledProviders = new HashSet<String>(); 119 120 // Locations, status values, and extras for mock providers 121 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>(); 122 123 private static boolean sProvidersLoaded = false; 124 125 private final Context mContext; 126 private GpsLocationProvider mGpsLocationProvider; 127 private LocationProviderProxy mNetworkLocationProvider; 128 private IGeocodeProvider mGeocodeProvider; 129 private LocationWorkerHandler mLocationHandler; 130 131 // Handler messages 132 private static final int MESSAGE_LOCATION_CHANGED = 1; 133 private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2; 134 private static final int MESSAGE_RELEASE_WAKE_LOCK = 3; 135 136 // Alarm manager and wakelock variables 137 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT"; 138 private final static String WAKELOCK_KEY = "LocationManagerService"; 139 private AlarmManager mAlarmManager; 140 private long mAlarmInterval = 0; 141 private PowerManager.WakeLock mWakeLock = null; 142 private long mWakeLockAcquireTime = 0; 143 private boolean mWakeLockGpsReceived = true; 144 private boolean mWakeLockNetworkReceived = true; 145 146 /** 147 * List of all receivers. 148 */ 149 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>(); 150 151 /** 152 * Object used internally for synchronization 153 */ 154 private final Object mLock = new Object(); 155 156 /** 157 * Mapping from provider name to all its UpdateRecords 158 */ 159 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = 160 new HashMap<String,ArrayList<UpdateRecord>>(); 161 162 // Proximity listeners 163 private Receiver mProximityListener = null; 164 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts = 165 new HashMap<PendingIntent,ProximityAlert>(); 166 private HashSet<ProximityAlert> mProximitiesEntered = 167 new HashSet<ProximityAlert>(); 168 169 // Last known location for each provider 170 private HashMap<String,Location> mLastKnownLocation = 171 new HashMap<String,Location>(); 172 173 // Location collector 174 private ILocationCollector mCollector; 175 176 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 177 178 // for Settings change notification 179 private ContentQueryMap mSettings; 180 181 /** 182 * A wrapper class holding either an ILocationListener or a PendingIntent to receive 183 * location updates. 184 */ 185 private final class Receiver implements IBinder.DeathRecipient { 186 final ILocationListener mListener; 187 final PendingIntent mPendingIntent; 188 final Object mKey; 189 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>(); 190 191 Receiver(ILocationListener listener) { 192 mListener = listener; 193 mPendingIntent = null; 194 mKey = listener.asBinder(); 195 } 196 197 Receiver(PendingIntent intent) { 198 mPendingIntent = intent; 199 mListener = null; 200 mKey = intent; 201 } 202 203 @Override 204 public boolean equals(Object otherObj) { 205 if (otherObj instanceof Receiver) { 206 return mKey.equals( 207 ((Receiver)otherObj).mKey); 208 } 209 return false; 210 } 211 212 @Override 213 public int hashCode() { 214 return mKey.hashCode(); 215 } 216 217 218 @Override 219 public String toString() { 220 if (mListener != null) { 221 return "Receiver{" 222 + Integer.toHexString(System.identityHashCode(this)) 223 + " Listener " + mKey + "}"; 224 } else { 225 return "Receiver{" 226 + Integer.toHexString(System.identityHashCode(this)) 227 + " Intent " + mKey + "}"; 228 } 229 } 230 231 public boolean isListener() { 232 return mListener != null; 233 } 234 235 public boolean isPendingIntent() { 236 return mPendingIntent != null; 237 } 238 239 public ILocationListener getListener() { 240 if (mListener != null) { 241 return mListener; 242 } 243 throw new IllegalStateException("Request for non-existent listener"); 244 } 245 246 public PendingIntent getPendingIntent() { 247 if (mPendingIntent != null) { 248 return mPendingIntent; 249 } 250 throw new IllegalStateException("Request for non-existent intent"); 251 } 252 253 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) { 254 if (mListener != null) { 255 try { 256 mListener.onStatusChanged(provider, status, extras); 257 } catch (RemoteException e) { 258 return false; 259 } 260 } else { 261 Intent statusChanged = new Intent(); 262 statusChanged.putExtras(extras); 263 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status); 264 try { 265 mPendingIntent.send(mContext, 0, statusChanged, null, null); 266 } catch (PendingIntent.CanceledException e) { 267 return false; 268 } 269 } 270 return true; 271 } 272 273 public boolean callLocationChangedLocked(Location location) { 274 if (mListener != null) { 275 try { 276 mListener.onLocationChanged(location); 277 } catch (RemoteException e) { 278 return false; 279 } 280 } else { 281 Intent locationChanged = new Intent(); 282 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); 283 try { 284 mPendingIntent.send(mContext, 0, locationChanged, null, null); 285 } catch (PendingIntent.CanceledException e) { 286 return false; 287 } 288 } 289 return true; 290 } 291 292 public void binderDied() { 293 if (LOCAL_LOGV) { 294 Log.v(TAG, "Location listener died"); 295 } 296 synchronized (mLock) { 297 removeUpdatesLocked(this); 298 } 299 } 300 } 301 302 private final class SettingsObserver implements Observer { 303 public void update(Observable o, Object arg) { 304 synchronized (mLock) { 305 updateProvidersLocked(); 306 } 307 } 308 } 309 310 private Location readLastKnownLocationLocked(String provider) { 311 Location location = null; 312 String s = null; 313 try { 314 File f = new File(LocationManager.SYSTEM_DIR + "/location." 315 + provider); 316 if (!f.exists()) { 317 return null; 318 } 319 BufferedReader reader = new BufferedReader(new FileReader(f), 256); 320 s = reader.readLine(); 321 } catch (IOException e) { 322 Log.w(TAG, "Unable to read last known location", e); 323 } 324 325 if (s == null) { 326 return null; 327 } 328 try { 329 String[] tokens = PATTERN_COMMA.split(s); 330 int idx = 0; 331 long time = Long.parseLong(tokens[idx++]); 332 double latitude = Double.parseDouble(tokens[idx++]); 333 double longitude = Double.parseDouble(tokens[idx++]); 334 double altitude = Double.parseDouble(tokens[idx++]); 335 float bearing = Float.parseFloat(tokens[idx++]); 336 float speed = Float.parseFloat(tokens[idx++]); 337 338 location = new Location(provider); 339 location.setTime(time); 340 location.setLatitude(latitude); 341 location.setLongitude(longitude); 342 location.setAltitude(altitude); 343 location.setBearing(bearing); 344 location.setSpeed(speed); 345 } catch (NumberFormatException nfe) { 346 Log.e(TAG, "NumberFormatException reading last known location", nfe); 347 return null; 348 } 349 350 return location; 351 } 352 353 private void writeLastKnownLocationLocked(String provider, 354 Location location) { 355 long now = SystemClock.elapsedRealtime(); 356 Long last = mLastWriteTime.get(provider); 357 if ((last != null) 358 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) { 359 return; 360 } 361 mLastWriteTime.put(provider, now); 362 363 StringBuilder sb = new StringBuilder(100); 364 sb.append(location.getTime()); 365 sb.append(','); 366 sb.append(location.getLatitude()); 367 sb.append(','); 368 sb.append(location.getLongitude()); 369 sb.append(','); 370 sb.append(location.getAltitude()); 371 sb.append(','); 372 sb.append(location.getBearing()); 373 sb.append(','); 374 sb.append(location.getSpeed()); 375 376 FileWriter writer = null; 377 try { 378 File d = new File(LocationManager.SYSTEM_DIR); 379 if (!d.exists()) { 380 if (!d.mkdirs()) { 381 Log.w(TAG, "Unable to create directory to write location"); 382 return; 383 } 384 } 385 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider); 386 writer = new FileWriter(f); 387 writer.write(sb.toString()); 388 } catch (IOException e) { 389 Log.w(TAG, "Unable to write location", e); 390 } finally { 391 if (writer != null) { 392 try { 393 writer.close(); 394 } catch (IOException e) { 395 Log.w(TAG, "Exception closing file", e); 396 } 397 } 398 } 399 } 400 401 /** 402 * Load providers from /data/location/<provider_name>/ 403 * class 404 * kml 405 * nmea 406 * track 407 * location 408 * properties 409 */ 410 private void loadProviders() { 411 synchronized (mLock) { 412 if (sProvidersLoaded) { 413 return; 414 } 415 416 // Load providers 417 loadProvidersLocked(); 418 sProvidersLoaded = true; 419 } 420 } 421 422 private void loadProvidersLocked() { 423 try { 424 _loadProvidersLocked(); 425 } catch (Exception e) { 426 Log.e(TAG, "Exception loading providers:", e); 427 } 428 } 429 430 private void _loadProvidersLocked() { 431 // Attempt to load "real" providers first 432 if (GpsLocationProvider.isSupported()) { 433 // Create a gps location provider 434 mGpsLocationProvider = new GpsLocationProvider(mContext, this); 435 LocationProviderImpl.addProvider(mGpsLocationProvider); 436 } 437 438 // Load fake providers if real providers are not available 439 File f = new File(LocationManager.PROVIDER_DIR); 440 if (f.isDirectory()) { 441 File[] subdirs = f.listFiles(); 442 for (int i = 0; i < subdirs.length; i++) { 443 if (!subdirs[i].isDirectory()) { 444 continue; 445 } 446 447 String name = subdirs[i].getName(); 448 449 if (LOCAL_LOGV) { 450 Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath()); 451 Log.v(TAG, "name = " + name); 452 } 453 454 // Don't create a fake provider if a real provider exists 455 if (LocationProviderImpl.getProvider(name) == null) { 456 LocationProviderImpl provider = null; 457 try { 458 File classFile = new File(subdirs[i], "class"); 459 // Look for a 'class' file 460 provider = LocationProviderImpl.loadFromClass(classFile); 461 462 // Look for an 'kml', 'nmea', or 'track' file 463 if (provider == null) { 464 // Load properties from 'properties' file, if present 465 File propertiesFile = new File(subdirs[i], "properties"); 466 467 if (propertiesFile.exists()) { 468 provider = new TrackProvider(name, this); 469 ((TrackProvider)provider).readProperties(propertiesFile); 470 471 File kmlFile = new File(subdirs[i], "kml"); 472 if (kmlFile.exists()) { 473 ((TrackProvider) provider).readKml(kmlFile); 474 } else { 475 File nmeaFile = new File(subdirs[i], "nmea"); 476 if (nmeaFile.exists()) { 477 ((TrackProvider) provider).readNmea(name, nmeaFile); 478 } else { 479 File trackFile = new File(subdirs[i], "track"); 480 if (trackFile.exists()) { 481 ((TrackProvider) provider).readTrack(trackFile); 482 } 483 } 484 } 485 } 486 } 487 if (provider != null) { 488 LocationProviderImpl.addProvider(provider); 489 } 490 // Grab the initial location of a TrackProvider and 491 // store it as the last known location for that provider 492 if (provider instanceof TrackProvider) { 493 TrackProvider tp = (TrackProvider) provider; 494 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation()); 495 } 496 } catch (Exception e) { 497 Log.e(TAG, "Exception loading provder " + name, e); 498 } 499 } 500 } 501 } 502 503 updateProvidersLocked(); 504 } 505 506 /** 507 * @param context the context that the LocationManagerService runs in 508 */ 509 public LocationManagerService(Context context) { 510 super(); 511 mContext = context; 512 mLocationHandler = new LocationWorkerHandler(); 513 514 if (LOCAL_LOGV) { 515 Log.v(TAG, "Constructed LocationManager Service"); 516 } 517 518 // Alarm manager, needs to be done before calling loadProviders() below 519 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 520 521 // Create a wake lock, needs to be done before calling loadProviders() below 522 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 523 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 524 525 // Load providers 526 loadProviders(); 527 528 // Register for Network (Wifi or Mobile) updates 529 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver(); 530 IntentFilter networkIntentFilter = new IntentFilter(); 531 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 532 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION); 533 context.registerReceiver(networkReceiver, networkIntentFilter); 534 535 // Register for power updates 536 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver(); 537 IntentFilter intentFilter = new IntentFilter(); 538 intentFilter.addAction(ALARM_INTENT); 539 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 540 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 541 context.registerReceiver(powerStateReceiver, intentFilter); 542 543 // listen for settings changes 544 ContentResolver resolver = mContext.getContentResolver(); 545 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null, 546 "(" + Settings.System.NAME + "=?)", 547 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 548 null); 549 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler); 550 SettingsObserver settingsObserver = new SettingsObserver(); 551 mSettings.addObserver(settingsObserver); 552 } 553 554 public void setNetworkLocationProvider(ILocationProvider provider) { 555 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 556 throw new SecurityException( 557 "Installing location providers outside of the system is not supported"); 558 } 559 560 synchronized (mLock) { 561 mNetworkLocationProvider = 562 new LocationProviderProxy(LocationManager.NETWORK_PROVIDER, this, provider); 563 LocationProviderImpl.addProvider(mNetworkLocationProvider); 564 updateProvidersLocked(); 565 566 // notify NetworkLocationProvider of any events it might have missed 567 mNetworkLocationProvider.updateNetworkState(mNetworkState); 568 } 569 } 570 571 public void setLocationCollector(ILocationCollector collector) { 572 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 573 throw new SecurityException( 574 "Installing location collectors outside of the system is not supported"); 575 } 576 577 mCollector = collector; 578 } 579 580 public void setGeocodeProvider(IGeocodeProvider provider) { 581 if (Binder.getCallingUid() != Process.SYSTEM_UID) { 582 throw new SecurityException( 583 "Installing location providers outside of the system is not supported"); 584 } 585 586 mGeocodeProvider = provider; 587 } 588 589 private boolean isAllowedBySettingsLocked(String provider) { 590 if (mEnabledProviders.contains(provider)) { 591 return true; 592 } 593 if (mDisabledProviders.contains(provider)) { 594 return false; 595 } 596 // Use system settings 597 ContentResolver resolver = mContext.getContentResolver(); 598 String allowedProviders = Settings.Secure.getString(resolver, 599 Settings.Secure.LOCATION_PROVIDERS_ALLOWED); 600 601 return ((allowedProviders != null) && (allowedProviders.contains(provider))); 602 } 603 604 private void checkPermissionsSafe(String provider) { 605 if (LocationManager.GPS_PROVIDER.equals(provider) 606 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 607 != PackageManager.PERMISSION_GRANTED)) { 608 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 609 } 610 if (LocationManager.NETWORK_PROVIDER.equals(provider) 611 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 612 != PackageManager.PERMISSION_GRANTED) 613 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 614 != PackageManager.PERMISSION_GRANTED)) { 615 throw new SecurityException( 616 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 617 } 618 } 619 620 private boolean isAllowedProviderSafe(String provider) { 621 if (LocationManager.GPS_PROVIDER.equals(provider) 622 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 623 != PackageManager.PERMISSION_GRANTED)) { 624 return false; 625 } 626 if (LocationManager.NETWORK_PROVIDER.equals(provider) 627 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 628 != PackageManager.PERMISSION_GRANTED) 629 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 630 != PackageManager.PERMISSION_GRANTED)) { 631 return false; 632 } 633 634 return true; 635 } 636 637 public List<String> getAllProviders() { 638 try { 639 synchronized (mLock) { 640 return _getAllProvidersLocked(); 641 } 642 } catch (SecurityException se) { 643 throw se; 644 } catch (Exception e) { 645 Log.e(TAG, "getAllProviders got exception:", e); 646 return null; 647 } 648 } 649 650 private List<String> _getAllProvidersLocked() { 651 if (LOCAL_LOGV) { 652 Log.v(TAG, "getAllProviders"); 653 } 654 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 655 ArrayList<String> out = new ArrayList<String>(providers.size()); 656 657 for (LocationProviderImpl p : providers) { 658 out.add(p.getName()); 659 } 660 return out; 661 } 662 663 public List<String> getProviders(boolean enabledOnly) { 664 try { 665 synchronized (mLock) { 666 return _getProvidersLocked(enabledOnly); 667 } 668 } catch (SecurityException se) { 669 throw se; 670 } catch (Exception e) { 671 Log.e(TAG, "getProviders got exception:", e); 672 return null; 673 } 674 } 675 676 private List<String> _getProvidersLocked(boolean enabledOnly) { 677 if (LOCAL_LOGV) { 678 Log.v(TAG, "getProviders"); 679 } 680 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 681 ArrayList<String> out = new ArrayList<String>(); 682 683 for (LocationProviderImpl p : providers) { 684 String name = p.getName(); 685 if (isAllowedProviderSafe(name)) { 686 if (enabledOnly && !isAllowedBySettingsLocked(name)) { 687 continue; 688 } 689 out.add(name); 690 } 691 } 692 return out; 693 } 694 695 private void updateProvidersLocked() { 696 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { 697 boolean isEnabled = p.isEnabled(); 698 String name = p.getName(); 699 boolean shouldBeEnabled = isAllowedBySettingsLocked(name); 700 701 if (isEnabled && !shouldBeEnabled) { 702 updateProviderListenersLocked(name, false); 703 } else if (!isEnabled && shouldBeEnabled) { 704 updateProviderListenersLocked(name, true); 705 } 706 707 } 708 } 709 710 private void updateProviderListenersLocked(String provider, boolean enabled) { 711 int listeners = 0; 712 713 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 714 if (p == null) { 715 return; 716 } 717 718 ArrayList<Receiver> deadReceivers = null; 719 720 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 721 if (records != null) { 722 final int N = records.size(); 723 for (int i=0; i<N; i++) { 724 UpdateRecord record = records.get(i); 725 // Sends a notification message to the receiver 726 try { 727 Receiver receiver = record.mReceiver; 728 if (receiver.isListener()) { 729 if (enabled) { 730 receiver.getListener().onProviderEnabled(provider); 731 } else { 732 receiver.getListener().onProviderDisabled(provider); 733 } 734 } else { 735 Intent providerIntent = new Intent(); 736 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 737 try { 738 receiver.getPendingIntent().send(mContext, 0, 739 providerIntent, null, null); 740 } catch (PendingIntent.CanceledException e) { 741 if (deadReceivers == null) { 742 deadReceivers = new ArrayList<Receiver>(); 743 deadReceivers.add(receiver); 744 } 745 } 746 } 747 } catch (RemoteException e) { 748 // The death link will clean this up. 749 } 750 listeners++; 751 } 752 } 753 754 if (deadReceivers != null) { 755 for (int i=deadReceivers.size()-1; i>=0; i--) { 756 removeUpdatesLocked(deadReceivers.get(i)); 757 } 758 } 759 760 if (enabled) { 761 p.enable(); 762 if (listeners > 0) { 763 p.setMinTime(getMinTimeLocked(provider)); 764 p.enableLocationTracking(true); 765 updateWakelockStatusLocked(); 766 } 767 } else { 768 p.enableLocationTracking(false); 769 p.disable(); 770 updateWakelockStatusLocked(); 771 } 772 } 773 774 private long getMinTimeLocked(String provider) { 775 long minTime = Long.MAX_VALUE; 776 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 777 if (records != null) { 778 for (int i=records.size()-1; i>=0; i--) { 779 minTime = Math.min(minTime, records.get(i).mMinTime); 780 } 781 } 782 return minTime; 783 } 784 785 private class UpdateRecord { 786 final String mProvider; 787 final Receiver mReceiver; 788 final long mMinTime; 789 final float mMinDistance; 790 final int mUid; 791 Location mLastFixBroadcast; 792 long mLastStatusBroadcast; 793 794 /** 795 * Note: must be constructed with lock held. 796 */ 797 UpdateRecord(String provider, long minTime, float minDistance, 798 Receiver receiver, int uid) { 799 mProvider = provider; 800 mReceiver = receiver; 801 mMinTime = minTime; 802 mMinDistance = minDistance; 803 mUid = uid; 804 805 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 806 if (records == null) { 807 records = new ArrayList<UpdateRecord>(); 808 mRecordsByProvider.put(provider, records); 809 } 810 if (!records.contains(this)) { 811 records.add(this); 812 } 813 } 814 815 /** 816 * Method to be called when a record will no longer be used. Calling this multiple times 817 * must have the same effect as calling it once. 818 */ 819 void disposeLocked() { 820 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 821 records.remove(this); 822 } 823 824 @Override 825 public String toString() { 826 return "UpdateRecord{" 827 + Integer.toHexString(System.identityHashCode(this)) 828 + " " + mProvider + " " + mReceiver + "}"; 829 } 830 831 void dump(PrintWriter pw, String prefix) { 832 pw.println(prefix + this); 833 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver); 834 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance); 835 pw.println(prefix + "mUid=" + mUid); 836 pw.println(prefix + "mLastFixBroadcast:"); 837 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " "); 838 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast); 839 } 840 841 /** 842 * Calls dispose(). 843 */ 844 @Override protected void finalize() { 845 synchronized (mLock) { 846 disposeLocked(); 847 } 848 } 849 } 850 851 private Receiver getReceiver(ILocationListener listener) { 852 IBinder binder = listener.asBinder(); 853 Receiver receiver = mReceivers.get(binder); 854 if (receiver == null) { 855 receiver = new Receiver(listener); 856 mReceivers.put(binder, receiver); 857 858 try { 859 if (receiver.isListener()) { 860 receiver.getListener().asBinder().linkToDeath(receiver, 0); 861 } 862 } catch (RemoteException e) { 863 Log.e(TAG, "linkToDeath failed:", e); 864 return null; 865 } 866 } 867 return receiver; 868 } 869 870 private Receiver getReceiver(PendingIntent intent) { 871 Receiver receiver = mReceivers.get(intent); 872 if (receiver == null) { 873 receiver = new Receiver(intent); 874 mReceivers.put(intent, receiver); 875 } 876 return receiver; 877 } 878 879 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) { 880 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 881 if (records != null) { 882 for (int i = records.size() - 1; i >= 0; i--) { 883 UpdateRecord record = records.get(i); 884 if (record.mUid == uid && record.mReceiver != excludedReceiver) { 885 return true; 886 } 887 } 888 } 889 if (LocationManager.GPS_PROVIDER.equals(provider) || 890 LocationManager.NETWORK_PROVIDER.equals(provider)) { 891 for (ProximityAlert alert : mProximityAlerts.values()) { 892 if (alert.mUid == uid) { 893 return true; 894 } 895 } 896 } 897 return false; 898 } 899 900 public void requestLocationUpdates(String provider, 901 long minTime, float minDistance, ILocationListener listener) { 902 903 try { 904 synchronized (mLock) { 905 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener)); 906 } 907 } catch (SecurityException se) { 908 throw se; 909 } catch (Exception e) { 910 Log.e(TAG, "requestUpdates got exception:", e); 911 } 912 } 913 914 public void requestLocationUpdatesPI(String provider, 915 long minTime, float minDistance, PendingIntent intent) { 916 try { 917 synchronized (mLock) { 918 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent)); 919 } 920 } catch (SecurityException se) { 921 throw se; 922 } catch (Exception e) { 923 Log.e(TAG, "requestUpdates got exception:", e); 924 } 925 } 926 927 private void requestLocationUpdatesLocked(String provider, 928 long minTime, float minDistance, Receiver receiver) { 929 if (LOCAL_LOGV) { 930 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver); 931 } 932 933 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 934 if (impl == null) { 935 throw new IllegalArgumentException("provider=" + provider); 936 } 937 938 checkPermissionsSafe(provider); 939 940 // so wakelock calls will succeed 941 final int callingUid = Binder.getCallingUid(); 942 boolean newUid = !providerHasListener(provider, callingUid, null); 943 long identity = Binder.clearCallingIdentity(); 944 try { 945 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid); 946 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r); 947 if (oldRecord != null) { 948 oldRecord.disposeLocked(); 949 } 950 951 if (newUid) { 952 impl.addListener(callingUid); 953 } 954 955 boolean isProviderEnabled = isAllowedBySettingsLocked(provider); 956 if (isProviderEnabled) { 957 long minTimeForProvider = getMinTimeLocked(provider); 958 impl.setMinTime(minTimeForProvider); 959 impl.enableLocationTracking(true); 960 updateWakelockStatusLocked(); 961 } else { 962 try { 963 // Notify the listener that updates are currently disabled 964 if (receiver.isListener()) { 965 receiver.getListener().onProviderDisabled(provider); 966 } 967 } catch(RemoteException e) { 968 Log.w(TAG, "RemoteException calling onProviderDisabled on " + 969 receiver.getListener()); 970 } 971 } 972 } finally { 973 Binder.restoreCallingIdentity(identity); 974 } 975 } 976 977 public void removeUpdates(ILocationListener listener) { 978 try { 979 synchronized (mLock) { 980 removeUpdatesLocked(getReceiver(listener)); 981 } 982 } catch (SecurityException se) { 983 throw se; 984 } catch (Exception e) { 985 Log.e(TAG, "removeUpdates got exception:", e); 986 } 987 } 988 989 public void removeUpdatesPI(PendingIntent intent) { 990 try { 991 synchronized (mLock) { 992 removeUpdatesLocked(getReceiver(intent)); 993 } 994 } catch (SecurityException se) { 995 throw se; 996 } catch (Exception e) { 997 Log.e(TAG, "removeUpdates got exception:", e); 998 } 999 } 1000 1001 private void removeUpdatesLocked(Receiver receiver) { 1002 if (LOCAL_LOGV) { 1003 Log.v(TAG, "_removeUpdates: listener = " + receiver); 1004 } 1005 1006 // so wakelock calls will succeed 1007 final int callingUid = Binder.getCallingUid(); 1008 long identity = Binder.clearCallingIdentity(); 1009 try { 1010 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) { 1011 receiver.getListener().asBinder().unlinkToDeath(receiver, 0); 1012 } 1013 1014 // Record which providers were associated with this listener 1015 HashSet<String> providers = new HashSet<String>(); 1016 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords; 1017 if (oldRecords != null) { 1018 // Call dispose() on the obsolete update records. 1019 for (UpdateRecord record : oldRecords.values()) { 1020 if (!providerHasListener(record.mProvider, callingUid, receiver)) { 1021 LocationProviderImpl impl = 1022 LocationProviderImpl.getProvider(record.mProvider); 1023 if (impl != null) { 1024 impl.removeListener(callingUid); 1025 } 1026 } 1027 record.disposeLocked(); 1028 } 1029 // Accumulate providers 1030 providers.addAll(oldRecords.keySet()); 1031 } 1032 1033 // See if the providers associated with this listener have any 1034 // other listeners; if one does, inform it of the new smallest minTime 1035 // value; if one does not, disable location tracking for it 1036 for (String provider : providers) { 1037 // If provider is already disabled, don't need to do anything 1038 if (!isAllowedBySettingsLocked(provider)) { 1039 continue; 1040 } 1041 1042 boolean hasOtherListener = false; 1043 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1044 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1045 hasOtherListener = true; 1046 } 1047 1048 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1049 if (p != null) { 1050 if (hasOtherListener) { 1051 p.setMinTime(getMinTimeLocked(provider)); 1052 } else { 1053 p.enableLocationTracking(false); 1054 } 1055 } 1056 } 1057 1058 updateWakelockStatusLocked(); 1059 } finally { 1060 Binder.restoreCallingIdentity(identity); 1061 } 1062 } 1063 1064 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1065 if (mGpsLocationProvider == null) { 1066 return false; 1067 } 1068 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != 1069 PackageManager.PERMISSION_GRANTED) { 1070 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1071 } 1072 1073 try { 1074 mGpsLocationProvider.addGpsStatusListener(listener); 1075 } catch (RemoteException e) { 1076 Log.w(TAG, "RemoteException in addGpsStatusListener"); 1077 return false; 1078 } 1079 return true; 1080 } 1081 1082 public void removeGpsStatusListener(IGpsStatusListener listener) { 1083 synchronized (mLock) { 1084 mGpsLocationProvider.removeGpsStatusListener(listener); 1085 } 1086 } 1087 1088 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1089 // first check for permission to the provider 1090 checkPermissionsSafe(provider); 1091 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1092 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1093 != PackageManager.PERMISSION_GRANTED)) { 1094 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1095 } 1096 1097 synchronized (mLock) { 1098 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 1099 if (provider == null) { 1100 return false; 1101 } 1102 1103 return impl.sendExtraCommand(command, extras); 1104 } 1105 } 1106 1107 class ProximityAlert { 1108 final int mUid; 1109 final double mLatitude; 1110 final double mLongitude; 1111 final float mRadius; 1112 final long mExpiration; 1113 final PendingIntent mIntent; 1114 final Location mLocation; 1115 1116 public ProximityAlert(int uid, double latitude, double longitude, 1117 float radius, long expiration, PendingIntent intent) { 1118 mUid = uid; 1119 mLatitude = latitude; 1120 mLongitude = longitude; 1121 mRadius = radius; 1122 mExpiration = expiration; 1123 mIntent = intent; 1124 1125 mLocation = new Location(""); 1126 mLocation.setLatitude(latitude); 1127 mLocation.setLongitude(longitude); 1128 } 1129 1130 long getExpiration() { 1131 return mExpiration; 1132 } 1133 1134 PendingIntent getIntent() { 1135 return mIntent; 1136 } 1137 1138 boolean isInProximity(double latitude, double longitude) { 1139 Location loc = new Location(""); 1140 loc.setLatitude(latitude); 1141 loc.setLongitude(longitude); 1142 1143 double radius = loc.distanceTo(mLocation); 1144 return radius <= mRadius; 1145 } 1146 1147 @Override 1148 public String toString() { 1149 return "ProximityAlert{" 1150 + Integer.toHexString(System.identityHashCode(this)) 1151 + " uid " + mUid + mIntent + "}"; 1152 } 1153 1154 void dump(PrintWriter pw, String prefix) { 1155 pw.println(prefix + this); 1156 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); 1157 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration); 1158 pw.println(prefix + "mIntent=" + mIntent); 1159 pw.println(prefix + "mLocation:"); 1160 mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); 1161 } 1162 } 1163 1164 // Listener for receiving locations to trigger proximity alerts 1165 class ProximityListener extends ILocationListener.Stub { 1166 1167 boolean isGpsAvailable = false; 1168 1169 // Note: this is called with the lock held. 1170 public void onLocationChanged(Location loc) { 1171 1172 // If Gps is available, then ignore updates from NetworkLocationProvider 1173 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1174 isGpsAvailable = true; 1175 } 1176 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1177 return; 1178 } 1179 1180 // Process proximity alerts 1181 long now = System.currentTimeMillis(); 1182 double latitude = loc.getLatitude(); 1183 double longitude = loc.getLongitude(); 1184 ArrayList<PendingIntent> intentsToRemove = null; 1185 1186 for (ProximityAlert alert : mProximityAlerts.values()) { 1187 PendingIntent intent = alert.getIntent(); 1188 long expiration = alert.getExpiration(); 1189 1190 if ((expiration == -1) || (now <= expiration)) { 1191 boolean entered = mProximitiesEntered.contains(alert); 1192 boolean inProximity = 1193 alert.isInProximity(latitude, longitude); 1194 if (!entered && inProximity) { 1195 if (LOCAL_LOGV) { 1196 Log.v(TAG, "Entered alert"); 1197 } 1198 mProximitiesEntered.add(alert); 1199 Intent enteredIntent = new Intent(); 1200 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1201 try { 1202 intent.send(mContext, 0, enteredIntent, null, null); 1203 } catch (PendingIntent.CanceledException e) { 1204 if (LOCAL_LOGV) { 1205 Log.v(TAG, "Canceled proximity alert: " + alert, e); 1206 } 1207 if (intentsToRemove == null) { 1208 intentsToRemove = new ArrayList<PendingIntent>(); 1209 } 1210 intentsToRemove.add(intent); 1211 } 1212 } else if (entered && !inProximity) { 1213 if (LOCAL_LOGV) { 1214 Log.v(TAG, "Exited alert"); 1215 } 1216 mProximitiesEntered.remove(alert); 1217 Intent exitedIntent = new Intent(); 1218 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1219 try { 1220 intent.send(mContext, 0, exitedIntent, null, null); 1221 } catch (PendingIntent.CanceledException e) { 1222 if (LOCAL_LOGV) { 1223 Log.v(TAG, "Canceled proximity alert: " + alert, e); 1224 } 1225 if (intentsToRemove == null) { 1226 intentsToRemove = new ArrayList<PendingIntent>(); 1227 } 1228 intentsToRemove.add(intent); 1229 } 1230 } 1231 } else { 1232 // Mark alert for expiration 1233 if (LOCAL_LOGV) { 1234 Log.v(TAG, "Expiring proximity alert: " + alert); 1235 } 1236 if (intentsToRemove == null) { 1237 intentsToRemove = new ArrayList<PendingIntent>(); 1238 } 1239 intentsToRemove.add(alert.getIntent()); 1240 } 1241 } 1242 1243 // Remove expired alerts 1244 if (intentsToRemove != null) { 1245 for (PendingIntent i : intentsToRemove) { 1246 mProximityAlerts.remove(i); 1247 ProximityAlert alert = mProximityAlerts.get(i); 1248 mProximitiesEntered.remove(alert); 1249 } 1250 } 1251 1252 } 1253 1254 // Note: this is called with the lock held. 1255 public void onProviderDisabled(String provider) { 1256 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1257 isGpsAvailable = false; 1258 } 1259 } 1260 1261 // Note: this is called with the lock held. 1262 public void onProviderEnabled(String provider) { 1263 // ignore 1264 } 1265 1266 // Note: this is called with the lock held. 1267 public void onStatusChanged(String provider, int status, Bundle extras) { 1268 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1269 (status != LocationProvider.AVAILABLE)) { 1270 isGpsAvailable = false; 1271 } 1272 } 1273 } 1274 1275 public void addProximityAlert(double latitude, double longitude, 1276 float radius, long expiration, PendingIntent intent) { 1277 try { 1278 synchronized (mLock) { 1279 addProximityAlertLocked(latitude, longitude, radius, expiration, intent); 1280 } 1281 } catch (SecurityException se) { 1282 throw se; 1283 } catch (Exception e) { 1284 Log.e(TAG, "addProximityAlert got exception:", e); 1285 } 1286 } 1287 1288 private void addProximityAlertLocked(double latitude, double longitude, 1289 float radius, long expiration, PendingIntent intent) { 1290 if (LOCAL_LOGV) { 1291 Log.v(TAG, "addProximityAlert: latitude = " + latitude + 1292 ", longitude = " + longitude + 1293 ", expiration = " + expiration + 1294 ", intent = " + intent); 1295 } 1296 1297 // Require ability to access all providers for now 1298 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) || 1299 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) { 1300 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1301 } 1302 1303 if (expiration != -1) { 1304 expiration += System.currentTimeMillis(); 1305 } 1306 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(), 1307 latitude, longitude, radius, expiration, intent); 1308 mProximityAlerts.put(intent, alert); 1309 1310 if (mProximityListener == null) { 1311 mProximityListener = new Receiver(new ProximityListener()); 1312 1313 LocationProvider provider = LocationProviderImpl.getProvider( 1314 LocationManager.GPS_PROVIDER); 1315 if (provider != null) { 1316 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); 1317 } 1318 1319 provider = 1320 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); 1321 if (provider != null) { 1322 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener); 1323 } 1324 } 1325 } 1326 1327 public void removeProximityAlert(PendingIntent intent) { 1328 try { 1329 synchronized (mLock) { 1330 removeProximityAlertLocked(intent); 1331 } 1332 } catch (SecurityException se) { 1333 throw se; 1334 } catch (Exception e) { 1335 Log.e(TAG, "removeProximityAlert got exception:", e); 1336 } 1337 } 1338 1339 private void removeProximityAlertLocked(PendingIntent intent) { 1340 if (LOCAL_LOGV) { 1341 Log.v(TAG, "removeProximityAlert: intent = " + intent); 1342 } 1343 1344 mProximityAlerts.remove(intent); 1345 if (mProximityAlerts.size() == 0) { 1346 removeUpdatesLocked(mProximityListener); 1347 mProximityListener = null; 1348 } 1349 } 1350 1351 /** 1352 * @return null if the provider does not exits 1353 * @throw SecurityException if the provider is not allowed to be 1354 * accessed by the caller 1355 */ 1356 public Bundle getProviderInfo(String provider) { 1357 try { 1358 synchronized (mLock) { 1359 return _getProviderInfoLocked(provider); 1360 } 1361 } catch (SecurityException se) { 1362 throw se; 1363 } catch (Exception e) { 1364 Log.e(TAG, "_getProviderInfo got exception:", e); 1365 return null; 1366 } 1367 } 1368 1369 private Bundle _getProviderInfoLocked(String provider) { 1370 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1371 if (p == null) { 1372 return null; 1373 } 1374 1375 checkPermissionsSafe(provider); 1376 1377 Bundle b = new Bundle(); 1378 b.putBoolean("network", p.requiresNetwork()); 1379 b.putBoolean("satellite", p.requiresSatellite()); 1380 b.putBoolean("cell", p.requiresCell()); 1381 b.putBoolean("cost", p.hasMonetaryCost()); 1382 b.putBoolean("altitude", p.supportsAltitude()); 1383 b.putBoolean("speed", p.supportsSpeed()); 1384 b.putBoolean("bearing", p.supportsBearing()); 1385 b.putInt("power", p.getPowerRequirement()); 1386 b.putInt("accuracy", p.getAccuracy()); 1387 1388 return b; 1389 } 1390 1391 public boolean isProviderEnabled(String provider) { 1392 try { 1393 synchronized (mLock) { 1394 return _isProviderEnabledLocked(provider); 1395 } 1396 } catch (SecurityException se) { 1397 throw se; 1398 } catch (Exception e) { 1399 Log.e(TAG, "isProviderEnabled got exception:", e); 1400 return false; 1401 } 1402 } 1403 1404 public void setLocation(Location location) { 1405 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location); 1406 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location); 1407 mLocationHandler.sendMessageAtFrontOfQueue(m); 1408 } 1409 1410 private boolean _isProviderEnabledLocked(String provider) { 1411 checkPermissionsSafe(provider); 1412 1413 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1414 if (p == null) { 1415 throw new IllegalArgumentException("provider=" + provider); 1416 } 1417 return isAllowedBySettingsLocked(provider); 1418 } 1419 1420 public Location getLastKnownLocation(String provider) { 1421 try { 1422 synchronized (mLock) { 1423 return _getLastKnownLocationLocked(provider); 1424 } 1425 } catch (SecurityException se) { 1426 throw se; 1427 } catch (Exception e) { 1428 Log.e(TAG, "getLastKnownLocation got exception:", e); 1429 return null; 1430 } 1431 } 1432 1433 private Location _getLastKnownLocationLocked(String provider) { 1434 checkPermissionsSafe(provider); 1435 1436 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1437 if (p == null) { 1438 throw new IllegalArgumentException("provider=" + provider); 1439 } 1440 1441 if (!isAllowedBySettingsLocked(provider)) { 1442 return null; 1443 } 1444 1445 Location location = mLastKnownLocation.get(provider); 1446 if (location == null) { 1447 // Get the persistent last known location for the provider 1448 location = readLastKnownLocationLocked(provider); 1449 if (location != null) { 1450 mLastKnownLocation.put(provider, location); 1451 } 1452 } 1453 1454 return location; 1455 } 1456 1457 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) { 1458 // Always broadcast the first update 1459 if (lastLoc == null) { 1460 return true; 1461 } 1462 1463 // Don't broadcast same location again regardless of condition 1464 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 1465 if (loc.getTime() == lastLoc.getTime()) { 1466 return false; 1467 } 1468 1469 // Check whether sufficient distance has been traveled 1470 double minDistance = record.mMinDistance; 1471 if (minDistance > 0.0) { 1472 if (loc.distanceTo(lastLoc) <= minDistance) { 1473 return false; 1474 } 1475 } 1476 1477 return true; 1478 } 1479 1480 private void handleLocationChangedLocked(Location location) { 1481 String provider = location.getProvider(); 1482 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); 1483 if (records == null || records.size() == 0) { 1484 return; 1485 } 1486 1487 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1488 if (p == null) { 1489 return; 1490 } 1491 1492 // Update last known location for provider 1493 Location lastLocation = mLastKnownLocation.get(provider); 1494 if (lastLocation == null) { 1495 mLastKnownLocation.put(provider, new Location(location)); 1496 } else { 1497 lastLocation.set(location); 1498 } 1499 writeLastKnownLocationLocked(provider, location); 1500 1501 if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) { 1502 mWakeLockNetworkReceived = true; 1503 } else if (p instanceof GpsLocationProvider) { 1504 // Gps location received signal is in NetworkStateBroadcastReceiver 1505 } 1506 1507 // Fetch latest status update time 1508 long newStatusUpdateTime = p.getStatusUpdateTime(); 1509 1510 // Get latest status 1511 Bundle extras = new Bundle(); 1512 int status = p.getStatus(extras); 1513 1514 ArrayList<Receiver> deadReceivers = null; 1515 1516 // Broadcast location or status to all listeners 1517 final int N = records.size(); 1518 for (int i=0; i<N; i++) { 1519 UpdateRecord r = records.get(i); 1520 Receiver receiver = r.mReceiver; 1521 1522 Location lastLoc = r.mLastFixBroadcast; 1523 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) { 1524 if (lastLoc == null) { 1525 lastLoc = new Location(location); 1526 r.mLastFixBroadcast = lastLoc; 1527 } else { 1528 lastLoc.set(location); 1529 } 1530 if (!receiver.callLocationChangedLocked(location)) { 1531 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1532 if (deadReceivers == null) { 1533 deadReceivers = new ArrayList<Receiver>(); 1534 } 1535 deadReceivers.add(receiver); 1536 } 1537 } 1538 1539 long prevStatusUpdateTime = r.mLastStatusBroadcast; 1540 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1541 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1542 1543 r.mLastStatusBroadcast = newStatusUpdateTime; 1544 if (!receiver.callStatusChangedLocked(provider, status, extras)) { 1545 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1546 if (deadReceivers == null) { 1547 deadReceivers = new ArrayList<Receiver>(); 1548 } 1549 if (!deadReceivers.contains(receiver)) { 1550 deadReceivers.add(receiver); 1551 } 1552 } 1553 } 1554 } 1555 1556 if (deadReceivers != null) { 1557 for (int i=deadReceivers.size()-1; i>=0; i--) { 1558 removeUpdatesLocked(deadReceivers.get(i)); 1559 } 1560 } 1561 } 1562 1563 private class LocationWorkerHandler extends Handler { 1564 1565 @Override 1566 public void handleMessage(Message msg) { 1567 try { 1568 if (msg.what == MESSAGE_LOCATION_CHANGED) { 1569 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!"); 1570 1571 synchronized (mLock) { 1572 Location location = (Location) msg.obj; 1573 1574 if (mCollector != null && 1575 LocationManager.GPS_PROVIDER.equals(location.getProvider())) { 1576 try { 1577 mCollector.updateLocation(location); 1578 } catch (RemoteException e) { 1579 Log.w(TAG, "mCollector.updateLocation failed"); 1580 } 1581 } 1582 1583 String provider = location.getProvider(); 1584 if (!isAllowedBySettingsLocked(provider)) { 1585 return; 1586 } 1587 1588 // Process the location fix if we're holding a wakelock 1589 if (mWakeLockAcquireTime != 0) { 1590 handleLocationChangedLocked(location); 1591 } 1592 1593 if ((mWakeLockAcquireTime != 0) && 1594 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime 1595 > MAX_TIME_FOR_WAKE_LOCK)) { 1596 1597 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1598 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1599 1600 log("LocationWorkerHandler: Exceeded max time for wake lock"); 1601 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1602 sendMessageAtFrontOfQueue(m); 1603 1604 } else if (mWakeLockAcquireTime != 0 && 1605 mWakeLockGpsReceived && mWakeLockNetworkReceived) { 1606 1607 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1608 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1609 1610 log("LocationWorkerHandler: Locations received."); 1611 mWakeLockAcquireTime = 0; 1612 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1613 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); 1614 } 1615 } 1616 1617 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) { 1618 log("LocationWorkerHandler: Acquire"); 1619 synchronized (mLock) { 1620 acquireWakeLockLocked(); 1621 } 1622 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { 1623 log("LocationWorkerHandler: Release"); 1624 1625 // Update wakelock status so the next alarm is set before releasing wakelock 1626 synchronized (mLock) { 1627 updateWakelockStatusLocked(); 1628 releaseWakeLockLocked(); 1629 } 1630 } 1631 } catch (Exception e) { 1632 // Log, don't crash! 1633 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1634 } 1635 } 1636 } 1637 1638 private class PowerStateBroadcastReceiver extends BroadcastReceiver { 1639 @Override public void onReceive(Context context, Intent intent) { 1640 String action = intent.getAction(); 1641 1642 if (action.equals(ALARM_INTENT)) { 1643 synchronized (mLock) { 1644 log("PowerStateBroadcastReceiver: Alarm received"); 1645 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1646 // Have to do this immediately, rather than posting a 1647 // message, so we execute our code while the system 1648 // is holding a wake lock until the alarm broadcast 1649 // is finished. 1650 acquireWakeLockLocked(); 1651 } 1652 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) 1653 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { 1654 synchronized (mLock) { 1655 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 1656 if (uid >= 0) { 1657 ArrayList<Receiver> removedRecs = null; 1658 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) { 1659 for (int j=i.size()-1; j>=0; j--) { 1660 UpdateRecord ur = i.get(j); 1661 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { 1662 if (removedRecs == null) { 1663 removedRecs = new ArrayList<Receiver>(); 1664 } 1665 if (!removedRecs.contains(ur.mReceiver)) { 1666 removedRecs.add(ur.mReceiver); 1667 } 1668 } 1669 } 1670 } 1671 ArrayList<ProximityAlert> removedAlerts = null; 1672 for (ProximityAlert i : mProximityAlerts.values()) { 1673 if (i.mUid == uid) { 1674 if (removedAlerts == null) { 1675 removedAlerts = new ArrayList<ProximityAlert>(); 1676 } 1677 if (!removedAlerts.contains(i)) { 1678 removedAlerts.add(i); 1679 } 1680 } 1681 } 1682 if (removedRecs != null) { 1683 for (int i=removedRecs.size()-1; i>=0; i--) { 1684 removeUpdatesLocked(removedRecs.get(i)); 1685 } 1686 } 1687 if (removedAlerts != null) { 1688 for (int i=removedAlerts.size()-1; i>=0; i--) { 1689 removeProximityAlertLocked(removedAlerts.get(i).mIntent); 1690 } 1691 } 1692 } 1693 } 1694 } 1695 } 1696 } 1697 1698 private class NetworkStateBroadcastReceiver extends BroadcastReceiver { 1699 @Override public void onReceive(Context context, Intent intent) { 1700 String action = intent.getAction(); 1701 1702 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 1703 boolean noConnectivity = 1704 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 1705 if (!noConnectivity) { 1706 mNetworkState = LocationProvider.AVAILABLE; 1707 } else { 1708 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 1709 } 1710 1711 // Notify location providers of current network state 1712 synchronized (mLock) { 1713 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 1714 for (LocationProviderImpl provider : providers) { 1715 if (provider.requiresNetwork()) { 1716 provider.updateNetworkState(mNetworkState); 1717 } 1718 } 1719 } 1720 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { 1721 1722 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, 1723 false); 1724 1725 synchronized (mLock) { 1726 if (!enabled) { 1727 // When GPS is disabled, we are OK to release wake-lock 1728 mWakeLockGpsReceived = true; 1729 } 1730 } 1731 } 1732 1733 } 1734 } 1735 1736 // Wake locks 1737 1738 private void updateWakelockStatusLocked() { 1739 log("updateWakelockStatus()"); 1740 1741 long callerId = Binder.clearCallingIdentity(); 1742 1743 boolean needsLock = false; 1744 long minTime = Integer.MAX_VALUE; 1745 1746 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { 1747 needsLock = true; 1748 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime); 1749 } 1750 1751 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) { 1752 needsLock = true; 1753 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime); 1754 } 1755 1756 PendingIntent sender = 1757 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0); 1758 1759 // Cancel existing alarm 1760 log("Cancelling existing alarm"); 1761 mAlarmManager.cancel(sender); 1762 1763 if (needsLock) { 1764 long now = SystemClock.elapsedRealtime(); 1765 mAlarmManager.set( 1766 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender); 1767 mAlarmInterval = minTime; 1768 log("Creating a new wakelock alarm with minTime = " + minTime); 1769 } else { 1770 log("No need for alarm"); 1771 mAlarmInterval = -1; 1772 1773 // Clear out existing wakelocks 1774 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1775 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1776 releaseWakeLockLocked(); 1777 } 1778 Binder.restoreCallingIdentity(callerId); 1779 } 1780 1781 private void acquireWakeLockLocked() { 1782 try { 1783 acquireWakeLockXLocked(); 1784 } catch (Exception e) { 1785 // This is to catch a runtime exception thrown when we try to release an 1786 // already released lock. 1787 Log.e(TAG, "exception in acquireWakeLock()", e); 1788 } 1789 } 1790 1791 private void acquireWakeLockXLocked() { 1792 if (mWakeLock.isHeld()) { 1793 log("Must release wakelock before acquiring"); 1794 mWakeLockAcquireTime = 0; 1795 mWakeLock.release(); 1796 } 1797 1798 boolean networkActive = (mNetworkLocationProvider != null) 1799 && mNetworkLocationProvider.isLocationTracking(); 1800 boolean gpsActive = (mGpsLocationProvider != null) 1801 && mGpsLocationProvider.isLocationTracking(); 1802 1803 boolean needsLock = networkActive || gpsActive; 1804 if (!needsLock) { 1805 log("No need for Lock!"); 1806 return; 1807 } 1808 1809 mWakeLockGpsReceived = !gpsActive; 1810 mWakeLockNetworkReceived = !networkActive; 1811 1812 // Acquire wake lock 1813 mWakeLock.acquire(); 1814 mWakeLockAcquireTime = SystemClock.elapsedRealtime(); 1815 log("Acquired wakelock"); 1816 1817 if (mNetworkLocationProvider != null) { 1818 mNetworkLocationProvider.wakeLockAcquired(); 1819 } 1820 if (mGpsLocationProvider != null) { 1821 mGpsLocationProvider.wakeLockAcquired(); 1822 } 1823 } 1824 1825 private void releaseWakeLockLocked() { 1826 try { 1827 releaseWakeLockXLocked(); 1828 } catch (Exception e) { 1829 // This is to catch a runtime exception thrown when we try to release an 1830 // already released lock. 1831 Log.e(TAG, "exception in releaseWakeLock()", e); 1832 } 1833 } 1834 1835 private void releaseWakeLockXLocked() { 1836 if (mNetworkLocationProvider != null) { 1837 mNetworkLocationProvider.wakeLockReleased(); 1838 } 1839 if (mGpsLocationProvider != null) { 1840 mGpsLocationProvider.wakeLockReleased(); 1841 } 1842 1843 // Release wake lock 1844 mWakeLockAcquireTime = 0; 1845 if (mWakeLock.isHeld()) { 1846 log("Released wakelock"); 1847 mWakeLock.release(); 1848 } else { 1849 log("Can't release wakelock again!"); 1850 } 1851 } 1852 1853 // Geocoder 1854 1855 public String getFromLocation(double latitude, double longitude, int maxResults, 1856 String language, String country, String variant, String appName, List<Address> addrs) { 1857 if (mGeocodeProvider != null) { 1858 try { 1859 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country, 1860 variant, appName, addrs); 1861 } catch (RemoteException e) { 1862 Log.e(TAG, "getFromLocation failed", e); 1863 } 1864 } 1865 return null; 1866 } 1867 1868 1869 public String getFromLocationName(String locationName, 1870 double lowerLeftLatitude, double lowerLeftLongitude, 1871 double upperRightLatitude, double upperRightLongitude, int maxResults, 1872 String language, String country, String variant, String appName, List<Address> addrs) { 1873 1874 if (mGeocodeProvider != null) { 1875 try { 1876 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude, 1877 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 1878 maxResults, language, country, variant, appName, addrs); 1879 } catch (RemoteException e) { 1880 Log.e(TAG, "getFromLocationName failed", e); 1881 } 1882 } 1883 return null; 1884 } 1885 1886 // Mock Providers 1887 1888 private void checkMockPermissionsSafe() { 1889 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 1890 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1; 1891 if (!allowMocks) { 1892 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 1893 } 1894 1895 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 1896 PackageManager.PERMISSION_GRANTED) { 1897 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 1898 } 1899 } 1900 1901 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 1902 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 1903 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 1904 checkMockPermissionsSafe(); 1905 1906 synchronized (mLock) { 1907 MockProvider provider = new MockProvider(name, this, 1908 requiresNetwork, requiresSatellite, 1909 requiresCell, hasMonetaryCost, supportsAltitude, 1910 supportsSpeed, supportsBearing, powerRequirement, accuracy); 1911 if (LocationProviderImpl.getProvider(name) != null) { 1912 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 1913 } 1914 LocationProviderImpl.addProvider(provider); 1915 mMockProviders.put(name, provider); 1916 updateProvidersLocked(); 1917 } 1918 } 1919 1920 public void removeTestProvider(String provider) { 1921 checkMockPermissionsSafe(); 1922 synchronized (mLock) { 1923 MockProvider mockProvider = mMockProviders.get(provider); 1924 if (mockProvider == null) { 1925 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1926 } 1927 LocationProviderImpl.removeProvider(mockProvider); 1928 mMockProviders.remove(mockProvider); 1929 updateProvidersLocked(); 1930 } 1931 } 1932 1933 public void setTestProviderLocation(String provider, Location loc) { 1934 checkMockPermissionsSafe(); 1935 synchronized (mLock) { 1936 MockProvider mockProvider = mMockProviders.get(provider); 1937 if (mockProvider == null) { 1938 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1939 } 1940 mockProvider.setLocation(loc); 1941 } 1942 } 1943 1944 public void clearTestProviderLocation(String provider) { 1945 checkMockPermissionsSafe(); 1946 synchronized (mLock) { 1947 MockProvider mockProvider = mMockProviders.get(provider); 1948 if (mockProvider == null) { 1949 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1950 } 1951 mockProvider.clearLocation(); 1952 } 1953 } 1954 1955 public void setTestProviderEnabled(String provider, boolean enabled) { 1956 checkMockPermissionsSafe(); 1957 synchronized (mLock) { 1958 MockProvider mockProvider = mMockProviders.get(provider); 1959 if (mockProvider == null) { 1960 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1961 } 1962 if (enabled) { 1963 mockProvider.enable(); 1964 mEnabledProviders.add(provider); 1965 mDisabledProviders.remove(provider); 1966 } else { 1967 mockProvider.disable(); 1968 mEnabledProviders.remove(provider); 1969 mDisabledProviders.add(provider); 1970 } 1971 updateProvidersLocked(); 1972 } 1973 } 1974 1975 public void clearTestProviderEnabled(String provider) { 1976 checkMockPermissionsSafe(); 1977 synchronized (mLock) { 1978 MockProvider mockProvider = mMockProviders.get(provider); 1979 if (mockProvider == null) { 1980 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1981 } 1982 mEnabledProviders.remove(provider); 1983 mDisabledProviders.remove(provider); 1984 updateProvidersLocked(); 1985 } 1986 } 1987 1988 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1989 checkMockPermissionsSafe(); 1990 synchronized (mLock) { 1991 MockProvider mockProvider = mMockProviders.get(provider); 1992 if (mockProvider == null) { 1993 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 1994 } 1995 mockProvider.setStatus(status, extras, updateTime); 1996 } 1997 } 1998 1999 public void clearTestProviderStatus(String provider) { 2000 checkMockPermissionsSafe(); 2001 synchronized (mLock) { 2002 MockProvider mockProvider = mMockProviders.get(provider); 2003 if (mockProvider == null) { 2004 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2005 } 2006 mockProvider.clearStatus(); 2007 } 2008 } 2009 2010 private void log(String log) { 2011 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2012 Log.d(TAG, log); 2013 } 2014 } 2015 2016 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2017 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2018 != PackageManager.PERMISSION_GRANTED) { 2019 pw.println("Permission Denial: can't dump AlarmManager from from pid=" 2020 + Binder.getCallingPid() 2021 + ", uid=" + Binder.getCallingUid()); 2022 return; 2023 } 2024 2025 synchronized (mLock) { 2026 pw.println("Current Location Manager state:"); 2027 pw.println(" sProvidersLoaded=" + sProvidersLoaded); 2028 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider); 2029 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider); 2030 pw.println(" mCollector=" + mCollector); 2031 pw.println(" mAlarmInterval=" + mAlarmInterval 2032 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime); 2033 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived 2034 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived); 2035 pw.println(" Listeners:"); 2036 int N = mReceivers.size(); 2037 for (int i=0; i<N; i++) { 2038 pw.println(" " + mReceivers.get(i)); 2039 } 2040 pw.println(" Location Listeners:"); 2041 for (Receiver i : mReceivers.values()) { 2042 pw.println(" " + i + ":"); 2043 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) { 2044 pw.println(" " + j.getKey() + ":"); 2045 j.getValue().dump(pw, " "); 2046 } 2047 } 2048 pw.println(" Records by Provider:"); 2049 for (Map.Entry<String, ArrayList<UpdateRecord>> i 2050 : mRecordsByProvider.entrySet()) { 2051 pw.println(" " + i.getKey() + ":"); 2052 for (UpdateRecord j : i.getValue()) { 2053 pw.println(" " + j + ":"); 2054 j.dump(pw, " "); 2055 } 2056 } 2057 pw.println(" Last Known Locations:"); 2058 for (Map.Entry<String, Location> i 2059 : mLastKnownLocation.entrySet()) { 2060 pw.println(" " + i.getKey() + ":"); 2061 i.getValue().dump(new PrintWriterPrinter(pw), " "); 2062 } 2063 if (mProximityAlerts.size() > 0) { 2064 pw.println(" Proximity Alerts:"); 2065 for (Map.Entry<PendingIntent, ProximityAlert> i 2066 : mProximityAlerts.entrySet()) { 2067 pw.println(" " + i.getKey() + ":"); 2068 i.getValue().dump(pw, " "); 2069 } 2070 } 2071 if (mProximitiesEntered.size() > 0) { 2072 pw.println(" Proximities Entered:"); 2073 for (ProximityAlert i : mProximitiesEntered) { 2074 pw.println(" " + i + ":"); 2075 i.dump(pw, " "); 2076 } 2077 } 2078 pw.println(" mProximityListener=" + mProximityListener); 2079 if (mEnabledProviders.size() > 0) { 2080 pw.println(" Enabled Providers:"); 2081 for (String i : mEnabledProviders) { 2082 pw.println(" " + i); 2083 } 2084 2085 } 2086 if (mDisabledProviders.size() > 0) { 2087 pw.println(" Disabled Providers:"); 2088 for (String i : mDisabledProviders) { 2089 pw.println(" " + i); 2090 } 2091 2092 } 2093 if (mMockProviders.size() > 0) { 2094 pw.println(" Mock Providers:"); 2095 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { 2096 i.getValue().dump(pw, " "); 2097 } 2098 } 2099 } 2100 } 2101} 2102