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