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