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