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