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