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