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