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