LocationManagerService.java revision d24b8183b93e781080b2c16c487e60d51c12da31
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_SET_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 setNetworkLocationProvider(INetworkLocationProvider provider) { 569 mLocationHandler.removeMessages(MESSAGE_SET_NETWORK_LOCATION_PROVIDER); 570 Message m = Message.obtain(mLocationHandler, 571 MESSAGE_SET_NETWORK_LOCATION_PROVIDER, provider); 572 mLocationHandler.sendMessageAtFrontOfQueue(m); 573 } 574 575 public void setLocationCollector(ILocationCollector collector) { 576 mCollector = collector; 577 if (mGpsLocationProvider != null) { 578 mGpsLocationProvider.setLocationCollector(mCollector); 579 } 580 } 581 582 private WifiManager.WifiLock getWifiWakelock() { 583 if (mWifiLock == null && mWifiManager != null) { 584 mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY); 585 mWifiLock.setReferenceCounted(false); 586 } 587 return mWifiLock; 588 } 589 590 private boolean isAllowedBySettings(String provider) { 591 if (mEnabledProviders.contains(provider)) { 592 return true; 593 } 594 if (mDisabledProviders.contains(provider)) { 595 return false; 596 } 597 // Use system settings 598 ContentResolver resolver = mContext.getContentResolver(); 599 String allowedProviders = Settings.Secure.getString(resolver, 600 Settings.Secure.LOCATION_PROVIDERS_ALLOWED); 601 602 return ((allowedProviders != null) && (allowedProviders.contains(provider))); 603 } 604 605 private void checkPermissions(String provider) { 606 if (LocationManager.GPS_PROVIDER.equals(provider) 607 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 608 != PackageManager.PERMISSION_GRANTED)) { 609 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 610 } 611 if (LocationManager.NETWORK_PROVIDER.equals(provider) 612 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 613 != PackageManager.PERMISSION_GRANTED) 614 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 615 != PackageManager.PERMISSION_GRANTED)) { 616 throw new SecurityException( 617 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); 618 } 619 } 620 621 private boolean isAllowedProvider(String provider) { 622 if (LocationManager.GPS_PROVIDER.equals(provider) 623 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 624 != PackageManager.PERMISSION_GRANTED)) { 625 return false; 626 } 627 if (LocationManager.NETWORK_PROVIDER.equals(provider) 628 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) 629 != PackageManager.PERMISSION_GRANTED) 630 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) 631 != PackageManager.PERMISSION_GRANTED)) { 632 return false; 633 } 634 635 return true; 636 } 637 638 private String[] getPackageNames() { 639 // Since a single UID may correspond to multiple packages, this can only be used as an 640 // approximation for tracking 641 return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid()); 642 } 643 644 public List<String> getAllProviders() { 645 try { 646 return _getAllProviders(); 647 } catch (SecurityException se) { 648 throw se; 649 } catch (Exception e) { 650 Log.e(TAG, "getAllProviders got exception:", e); 651 return null; 652 } 653 } 654 655 private List<String> _getAllProviders() { 656 if (Config.LOGD) { 657 Log.d(TAG, "getAllProviders"); 658 } 659 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 660 ArrayList<String> out = new ArrayList<String>(providers.size()); 661 662 for (LocationProviderImpl p : providers) { 663 out.add(p.getName()); 664 } 665 return out; 666 } 667 668 public List<String> getProviders(boolean enabledOnly) { 669 try { 670 return _getProviders(enabledOnly); 671 } catch (SecurityException se) { 672 throw se; 673 } catch (Exception e) { 674 Log.e(TAG, "getProviders gotString exception:", e); 675 return null; 676 } 677 } 678 679 private List<String> _getProviders(boolean enabledOnly) { 680 if (Config.LOGD) { 681 Log.d(TAG, "getProviders"); 682 } 683 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 684 ArrayList<String> out = new ArrayList<String>(); 685 686 for (LocationProviderImpl p : providers) { 687 String name = p.getName(); 688 if (isAllowedProvider(name)) { 689 if (enabledOnly && !isAllowedBySettings(name)) { 690 continue; 691 } 692 out.add(name); 693 } 694 } 695 return out; 696 } 697 698 public void updateProviders() { 699 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) { 700 boolean isEnabled = p.isEnabled(); 701 String name = p.getName(); 702 boolean shouldBeEnabled = isAllowedBySettings(name); 703 704 // Collection is only allowed when network provider is being used 705 if (mCollector != null && 706 p.getName().equals(LocationManager.NETWORK_PROVIDER)) { 707 mCollector.updateNetworkProviderStatus(shouldBeEnabled); 708 } 709 710 if (isEnabled && !shouldBeEnabled) { 711 updateProviderListeners(name, false); 712 } else if (!isEnabled && shouldBeEnabled) { 713 updateProviderListeners(name, true); 714 } 715 716 } 717 } 718 719 private void updateProviderListeners(String provider, boolean enabled) { 720 int listeners = 0; 721 722 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 723 if (p == null) { 724 return; 725 } 726 727 synchronized (mRecordsByProvider) { 728 HashSet<UpdateRecord> records = mRecordsByProvider.get(provider); 729 if (records != null) { 730 for (UpdateRecord record : records) { 731 // Sends a notification message to the receiver 732 try { 733 Receiver receiver = record.mReceiver; 734 if (receiver.isListener()) { 735 if (enabled) { 736 receiver.getListener().onProviderEnabled(provider); 737 } else { 738 receiver.getListener().onProviderDisabled(provider); 739 } 740 } else { 741 PendingIntent intent = receiver.getPendingIntent(); 742 Intent providerIntent = new Intent(); 743 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled); 744 try { 745 receiver.getPendingIntent().send(mContext, 0, 746 providerIntent, null, null); 747 } catch (PendingIntent.CanceledException e) { 748 _removeUpdates(receiver); 749 } 750 } 751 } catch (RemoteException e) { 752 // The death link will clean this up. 753 } 754 listeners++; 755 } 756 } 757 } 758 759 if (enabled) { 760 p.enable(); 761 if (listeners > 0) { 762 p.setMinTime(getMinTime(provider)); 763 p.enableLocationTracking(true); 764 updateWakelockStatus(mScreenOn); 765 } 766 } else { 767 p.enableLocationTracking(false); 768 p.disable(); 769 updateWakelockStatus(mScreenOn); 770 } 771 772 if (enabled && listeners > 0) { 773 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 774 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); 775 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 776 } else { 777 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 778 } 779 } 780 781 private long getMinTime(String provider) { 782 long minTime = Long.MAX_VALUE; 783 synchronized (mRecordsByProvider) { 784 HashSet<UpdateRecord> records = mRecordsByProvider.get(provider); 785 if (records != null) { 786 for (UpdateRecord r : records) { 787 minTime = Math.min(minTime, r.mMinTime); 788 } 789 } 790 } 791 return minTime; 792 } 793 794 private class UpdateRecord { 795 String mProvider; 796 Receiver mReceiver; 797 long mMinTime; 798 float mMinDistance; 799 String[] mPackages; 800 801 UpdateRecord(String provider, long minTime, float minDistance, 802 Receiver receiver, String[] packages) { 803 mProvider = provider; 804 mReceiver = receiver; 805 mMinTime = minTime; 806 mMinDistance = minDistance; 807 mPackages = packages; 808 809 synchronized (mRecordsByProvider) { 810 HashSet<UpdateRecord> records = mRecordsByProvider.get(provider); 811 if (records == null) { 812 records = new HashSet<UpdateRecord>(); 813 mRecordsByProvider.put(provider, records); 814 } 815 records.add(this); 816 } 817 } 818 819 /** 820 * Method to be called when a record will no longer be used. Calling this multiple times 821 * must have the same effect as calling it once. 822 */ 823 public void dispose() { 824 synchronized (mRecordsByProvider) { 825 HashSet<UpdateRecord> records = mRecordsByProvider.get(this.mProvider); 826 records.remove(this); 827 } 828 } 829 830 /** 831 * Calls dispose(). 832 */ 833 @Override protected void finalize() { 834 dispose(); 835 } 836 } 837 838 public void requestLocationUpdates(String provider, 839 long minTime, float minDistance, ILocationListener listener) { 840 841 try { 842 _requestLocationUpdates(provider, minTime, minDistance, 843 new Receiver(listener)); 844 } catch (SecurityException se) { 845 throw se; 846 } catch (Exception e) { 847 Log.e(TAG, "requestUpdates got exception:", e); 848 } 849 } 850 851 public void requestLocationUpdatesPI(String provider, 852 long minTime, float minDistance, PendingIntent intent) { 853 try { 854 _requestLocationUpdates(provider, minTime, minDistance, 855 new Receiver(intent)); 856 } catch (SecurityException se) { 857 throw se; 858 } catch (Exception e) { 859 Log.e(TAG, "requestUpdates got exception:", e); 860 } 861 } 862 863 private synchronized void _requestLocationUpdates(String provider, 864 long minTime, float minDistance, Receiver receiver) { 865 Object key = receiver.getKey(); 866 if (Config.LOGD) { 867 Log.d(TAG, "_requestLocationUpdates: listener = " + key); 868 } 869 870 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 871 if (impl == null) { 872 throw new IllegalArgumentException("provider=" + provider); 873 } 874 875 checkPermissions(provider); 876 877 String[] packages = getPackageNames(); 878 879 // so wakelock calls will succeed 880 mCallingUid = getCallingUid(); 881 long identity = Binder.clearCallingIdentity(); 882 try { 883 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, packages); 884 synchronized (mLocationListeners) { 885 if (mListeners.get(key) == null) { 886 try { 887 if (receiver.isListener()) { 888 receiver.getListener().asBinder().linkToDeath(receiver, 0); 889 } 890 mListeners.put(key, receiver); 891 } catch (RemoteException e) { 892 return; 893 } 894 } 895 896 HashMap<String,UpdateRecord> records = mLocationListeners.get(key); 897 if (records == null) { 898 records = new HashMap<String,UpdateRecord>(); 899 mLocationListeners.put(key, records); 900 } 901 UpdateRecord oldRecord = records.put(provider, r); 902 if (oldRecord != null) { 903 oldRecord.dispose(); 904 } 905 906 boolean isProviderEnabled = isAllowedBySettings(provider); 907 if (isProviderEnabled) { 908 if (provider.equals(LocationManager.GPS_PROVIDER)) { 909 try { 910 mBatteryStats.noteRequestGpsOn(mCallingUid); 911 } catch (RemoteException e) { 912 Log.w(TAG, "Got RemoteException calling noteRequestGpsOff", e); 913 } 914 } 915 916 long minTimeForProvider = getMinTime(provider); 917 impl.setMinTime(minTimeForProvider); 918 impl.enableLocationTracking(true); 919 updateWakelockStatus(mScreenOn); 920 921 // Clear heartbeats if any before starting a new one 922 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 923 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider); 924 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 925 } else { 926 try { 927 // Notify the listener that updates are currently disabled 928 if (receiver.isListener()) { 929 receiver.getListener().onProviderDisabled(provider); 930 } 931 } catch(RemoteException e) { 932 Log.w(TAG, "RemoteException calling onProviderDisabled on " + 933 receiver.getListener()); 934 } 935 } 936 } 937 } finally { 938 Binder.restoreCallingIdentity(identity); 939 mCallingUid = -1; 940 } 941 } 942 943 public void removeUpdates(ILocationListener listener) { 944 try { 945 _removeUpdates(new Receiver(listener)); 946 } catch (SecurityException se) { 947 throw se; 948 } catch (Exception e) { 949 Log.e(TAG, "removeUpdates got exception:", e); 950 } 951 } 952 953 public void removeUpdatesPI(PendingIntent intent) { 954 try { 955 _removeUpdates(new Receiver(intent)); 956 } catch (SecurityException se) { 957 throw se; 958 } catch (Exception e) { 959 Log.e(TAG, "removeUpdates got exception:", e); 960 } 961 } 962 963 private synchronized void _removeUpdates(Receiver receiver) { 964 Object key = receiver.getKey(); 965 if (Config.LOGD) { 966 Log.d(TAG, "_removeUpdates: listener = " + key); 967 } 968 969 // so wakelock calls will succeed 970 mCallingUid = getCallingUid(); 971 long identity = Binder.clearCallingIdentity(); 972 try { 973 synchronized (mLocationListeners) { 974 Receiver myReceiver = mListeners.remove(key); 975 if ((myReceiver != null) && (myReceiver.isListener())) { 976 myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0); 977 } 978 979 // Record which providers were associated with this listener 980 HashSet<String> providers = new HashSet<String>(); 981 HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(key); 982 if (oldRecords != null) { 983 // Call dispose() on the obsolete update records. 984 for (UpdateRecord record : oldRecords.values()) { 985 if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) { 986 if (mNetworkLocationInterface != null) { 987 mNetworkLocationInterface.removeListener(record.mPackages); 988 } 989 } 990 record.dispose(); 991 } 992 // Accumulate providers 993 providers.addAll(oldRecords.keySet()); 994 } 995 996 if (providers.contains("gps")) { 997 try { 998 mBatteryStats.noteRequestGpsOff(mCallingUid); 999 } catch (RemoteException e) { 1000 Log.w(TAG, "Got RemoteException calling noteRequestGpsOff", e); 1001 } 1002 } 1003 1004 mLocationListeners.remove(key); 1005 mLastFixBroadcast.remove(key); 1006 mLastStatusBroadcast.remove(key); 1007 1008 // See if the providers associated with this listener have any 1009 // other listeners; if one does, inform it of the new smallest minTime 1010 // value; if one does not, disable location tracking for it 1011 for (String provider : providers) { 1012 // If provider is already disabled, don't need to do anything 1013 if (!isAllowedBySettings(provider)) { 1014 continue; 1015 } 1016 1017 boolean hasOtherListener = false; 1018 synchronized (mRecordsByProvider) { 1019 HashSet<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider); 1020 if (recordsForProvider != null && recordsForProvider.size() > 0) { 1021 hasOtherListener = true; 1022 } 1023 } 1024 1025 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1026 if (p != null) { 1027 if (hasOtherListener) { 1028 p.setMinTime(getMinTime(provider)); 1029 } else { 1030 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider); 1031 p.enableLocationTracking(false); 1032 } 1033 } 1034 } 1035 1036 updateWakelockStatus(mScreenOn); 1037 } 1038 } finally { 1039 Binder.restoreCallingIdentity(identity); 1040 mCallingUid = -1; 1041 } 1042 } 1043 1044 public boolean addGpsStatusListener(IGpsStatusListener listener) { 1045 if (mGpsLocationProvider == null) { 1046 return false; 1047 } 1048 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != 1049 PackageManager.PERMISSION_GRANTED) { 1050 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1051 } 1052 1053 try { 1054 mGpsLocationProvider.addGpsStatusListener(listener); 1055 } catch (RemoteException e) { 1056 Log.w(TAG, "RemoteException in addGpsStatusListener"); 1057 return false; 1058 } 1059 return true; 1060 } 1061 1062 public void removeGpsStatusListener(IGpsStatusListener listener) { 1063 mGpsLocationProvider.removeGpsStatusListener(listener); 1064 } 1065 1066 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1067 // first check for permission to the provider 1068 checkPermissions(provider); 1069 // and check for ACCESS_LOCATION_EXTRA_COMMANDS 1070 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS) 1071 != PackageManager.PERMISSION_GRANTED)) { 1072 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); 1073 } 1074 1075 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider); 1076 if (provider == null) { 1077 return false; 1078 } 1079 1080 return impl.sendExtraCommand(command, extras); 1081 } 1082 1083 class ProximityAlert { 1084 double mLatitude; 1085 double mLongitude; 1086 float mRadius; 1087 long mExpiration; 1088 PendingIntent mIntent; 1089 Location mLocation; 1090 1091 public ProximityAlert(double latitude, double longitude, 1092 float radius, long expiration, PendingIntent intent) { 1093 mLatitude = latitude; 1094 mLongitude = longitude; 1095 mRadius = radius; 1096 mExpiration = expiration; 1097 mIntent = intent; 1098 1099 mLocation = new Location(""); 1100 mLocation.setLatitude(latitude); 1101 mLocation.setLongitude(longitude); 1102 } 1103 1104 public long getExpiration() { 1105 return mExpiration; 1106 } 1107 1108 public PendingIntent getIntent() { 1109 return mIntent; 1110 } 1111 1112 public boolean isInProximity(double latitude, double longitude) { 1113 Location loc = new Location(""); 1114 loc.setLatitude(latitude); 1115 loc.setLongitude(longitude); 1116 1117 double radius = loc.distanceTo(mLocation); 1118 return radius <= mRadius; 1119 } 1120 } 1121 1122 // Listener for receiving locations to trigger proximity alerts 1123 class ProximityListener extends ILocationListener.Stub { 1124 1125 boolean isGpsAvailable = false; 1126 1127 public void onLocationChanged(Location loc) { 1128 1129 // If Gps is available, then ignore updates from NetworkLocationProvider 1130 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) { 1131 isGpsAvailable = true; 1132 } 1133 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) { 1134 return; 1135 } 1136 1137 // Process proximity alerts 1138 long now = System.currentTimeMillis(); 1139 double latitude = loc.getLatitude(); 1140 double longitude = loc.getLongitude(); 1141 ArrayList<PendingIntent> intentsToRemove = null; 1142 1143 for (ProximityAlert alert : mProximityAlerts.values()) { 1144 PendingIntent intent = alert.getIntent(); 1145 long expiration = alert.getExpiration(); 1146 1147 if ((expiration == -1) || (now <= expiration)) { 1148 boolean entered = mProximitiesEntered.contains(alert); 1149 boolean inProximity = 1150 alert.isInProximity(latitude, longitude); 1151 if (!entered && inProximity) { 1152 if (Config.LOGD) { 1153 Log.i(TAG, "Entered alert"); 1154 } 1155 mProximitiesEntered.add(alert); 1156 Intent enteredIntent = new Intent(); 1157 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 1158 try { 1159 intent.send(mContext, 0, enteredIntent, null, null); 1160 } catch (PendingIntent.CanceledException e) { 1161 if (Config.LOGD) { 1162 Log.i(TAG, "Canceled proximity alert: " + alert, e); 1163 } 1164 if (intentsToRemove == null) { 1165 intentsToRemove = new ArrayList<PendingIntent>(); 1166 } 1167 intentsToRemove.add(intent); 1168 } 1169 } else if (entered && !inProximity) { 1170 if (Config.LOGD) { 1171 Log.i(TAG, "Exited alert"); 1172 } 1173 mProximitiesEntered.remove(alert); 1174 Intent exitedIntent = new Intent(); 1175 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 1176 try { 1177 intent.send(mContext, 0, exitedIntent, null, null); 1178 } catch (PendingIntent.CanceledException e) { 1179 if (Config.LOGD) { 1180 Log.i(TAG, "Canceled proximity alert: " + alert, e); 1181 } 1182 if (intentsToRemove == null) { 1183 intentsToRemove = new ArrayList<PendingIntent>(); 1184 } 1185 intentsToRemove.add(intent); 1186 } 1187 } 1188 } else { 1189 // Mark alert for expiration 1190 if (Config.LOGD) { 1191 Log.i(TAG, "Expiring proximity alert: " + alert); 1192 } 1193 if (intentsToRemove == null) { 1194 intentsToRemove = new ArrayList<PendingIntent>(); 1195 } 1196 intentsToRemove.add(alert.getIntent()); 1197 } 1198 } 1199 1200 // Remove expired alerts 1201 if (intentsToRemove != null) { 1202 for (PendingIntent i : intentsToRemove) { 1203 mProximityAlerts.remove(i); 1204 ProximityAlert alert = mProximityAlerts.get(i); 1205 mProximitiesEntered.remove(alert); 1206 } 1207 } 1208 1209 } 1210 1211 public void onProviderDisabled(String provider) { 1212 if (provider.equals(LocationManager.GPS_PROVIDER)) { 1213 isGpsAvailable = false; 1214 } 1215 } 1216 1217 public void onProviderEnabled(String provider) { 1218 // ignore 1219 } 1220 1221 public void onStatusChanged(String provider, int status, Bundle extras) { 1222 if ((provider.equals(LocationManager.GPS_PROVIDER)) && 1223 (status != LocationProvider.AVAILABLE)) { 1224 isGpsAvailable = false; 1225 } 1226 } 1227 } 1228 1229 public void addProximityAlert(double latitude, double longitude, 1230 float radius, long expiration, PendingIntent intent) { 1231 try { 1232 _addProximityAlert(latitude, longitude, radius, expiration, intent); 1233 } catch (SecurityException se) { 1234 throw se; 1235 } catch (Exception e) { 1236 Log.e(TAG, "addProximityAlert got exception:", e); 1237 } 1238 } 1239 1240 private void _addProximityAlert(double latitude, double longitude, 1241 float radius, long expiration, PendingIntent intent) { 1242 if (Config.LOGD) { 1243 Log.d(TAG, "addProximityAlert: latitude = " + latitude + 1244 ", longitude = " + longitude + 1245 ", expiration = " + expiration + 1246 ", intent = " + intent); 1247 } 1248 1249 // Require ability to access all providers for now 1250 if (!isAllowedProvider(LocationManager.GPS_PROVIDER) || 1251 !isAllowedProvider(LocationManager.NETWORK_PROVIDER)) { 1252 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); 1253 } 1254 1255 if (expiration != -1) { 1256 expiration += System.currentTimeMillis(); 1257 } 1258 ProximityAlert alert = new ProximityAlert(latitude, longitude, radius, expiration, intent); 1259 mProximityAlerts.put(intent, alert); 1260 1261 if (mProximityListener == null) { 1262 mProximityListener = new Receiver(new ProximityListener()); 1263 1264 LocationProvider provider = LocationProviderImpl.getProvider( 1265 LocationManager.GPS_PROVIDER); 1266 if (provider != null) { 1267 _requestLocationUpdates(provider.getName(), 1000L, 1.0f, mProximityListener); 1268 } 1269 1270 provider = 1271 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER); 1272 if (provider != null) { 1273 _requestLocationUpdates(provider.getName(), 1000L, 1.0f, mProximityListener); 1274 } 1275 } 1276 } 1277 1278 public void removeProximityAlert(PendingIntent intent) { 1279 try { 1280 _removeProximityAlert(intent); 1281 } catch (SecurityException se) { 1282 throw se; 1283 } catch (Exception e) { 1284 Log.e(TAG, "removeProximityAlert got exception:", e); 1285 } 1286 } 1287 1288 private void _removeProximityAlert(PendingIntent intent) { 1289 if (Config.LOGD) { 1290 Log.d(TAG, "removeProximityAlert: intent = " + intent); 1291 } 1292 1293 mProximityAlerts.remove(intent); 1294 if (mProximityAlerts.size() == 0) { 1295 _removeUpdates(mProximityListener); 1296 mProximityListener = null; 1297 } 1298 } 1299 1300 /** 1301 * @return null if the provider does not exits 1302 * @throw SecurityException if the provider is not allowed to be 1303 * accessed by the caller 1304 */ 1305 public Bundle getProviderInfo(String provider) { 1306 try { 1307 return _getProviderInfo(provider); 1308 } catch (SecurityException se) { 1309 throw se; 1310 } catch (Exception e) { 1311 Log.e(TAG, "_getProviderInfo got exception:", e); 1312 return null; 1313 } 1314 } 1315 1316 private Bundle _getProviderInfo(String provider) { 1317 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1318 if (p == null) { 1319 return null; 1320 } 1321 1322 checkPermissions(provider); 1323 1324 Bundle b = new Bundle(); 1325 b.putBoolean("network", p.requiresNetwork()); 1326 b.putBoolean("satellite", p.requiresSatellite()); 1327 b.putBoolean("cell", p.requiresCell()); 1328 b.putBoolean("cost", p.hasMonetaryCost()); 1329 b.putBoolean("altitude", p.supportsAltitude()); 1330 b.putBoolean("speed", p.supportsSpeed()); 1331 b.putBoolean("bearing", p.supportsBearing()); 1332 b.putInt("power", p.getPowerRequirement()); 1333 b.putInt("accuracy", p.getAccuracy()); 1334 1335 return b; 1336 } 1337 1338 public boolean isProviderEnabled(String provider) { 1339 try { 1340 return _isProviderEnabled(provider); 1341 } catch (SecurityException se) { 1342 throw se; 1343 } catch (Exception e) { 1344 Log.e(TAG, "isProviderEnabled got exception:", e); 1345 return false; 1346 } 1347 } 1348 1349 private boolean _isProviderEnabled(String provider) { 1350 checkPermissions(provider); 1351 1352 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1353 if (p == null) { 1354 throw new IllegalArgumentException("provider=" + provider); 1355 } 1356 return isAllowedBySettings(provider); 1357 } 1358 1359 public Location getLastKnownLocation(String provider) { 1360 try { 1361 return _getLastKnownLocation(provider); 1362 } catch (SecurityException se) { 1363 throw se; 1364 } catch (Exception e) { 1365 Log.e(TAG, "getLastKnownLocation got exception:", e); 1366 return null; 1367 } 1368 } 1369 1370 private Location _getLastKnownLocation(String provider) { 1371 checkPermissions(provider); 1372 1373 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1374 if (p == null) { 1375 throw new IllegalArgumentException("provider=" + provider); 1376 } 1377 1378 if (!isAllowedBySettings(provider)) { 1379 return null; 1380 } 1381 1382 Location location = mLastKnownLocation.get(provider); 1383 if (location == null) { 1384 // Get the persistent last known location for the provider 1385 location = readLastKnownLocation(provider); 1386 if (location != null) { 1387 mLastKnownLocation.put(provider, location); 1388 } 1389 } 1390 1391 return location; 1392 } 1393 1394 private boolean shouldBroadcast(Location loc, Location lastLoc, UpdateRecord record) { 1395 // Always broadcast the first update 1396 if (lastLoc == null) { 1397 return true; 1398 } 1399 1400 // Don't broadcast same location again regardless of condition 1401 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0 1402 if (loc.getTime() == lastLoc.getTime()) { 1403 return false; 1404 } 1405 1406 // Check whether sufficient distance has been traveled 1407 double minDistance = record.mMinDistance; 1408 if (minDistance > 0.0) { 1409 if (loc.distanceTo(lastLoc) <= minDistance) { 1410 return false; 1411 } 1412 } 1413 1414 return true; 1415 } 1416 1417 private void handleLocationChanged(String provider) { 1418 HashSet<UpdateRecord> records = mRecordsByProvider.get(provider); 1419 if (records == null || records.size() == 0) { 1420 return; 1421 } 1422 1423 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 1424 if (p == null) { 1425 return; 1426 } 1427 1428 // Get location object 1429 Location loc = mLocationsByProvider.get(provider); 1430 if (loc == null) { 1431 loc = new Location(provider); 1432 mLocationsByProvider.put(provider, loc); 1433 } else { 1434 loc.reset(); 1435 } 1436 1437 // Use the mock location if available 1438 Location mockLoc = mMockProviderLocation.get(provider); 1439 boolean locationValid; 1440 if (mockLoc != null) { 1441 locationValid = true; 1442 loc.set(mockLoc); 1443 } else { 1444 locationValid = p.getLocation(loc); 1445 } 1446 1447 // Update last known location for provider 1448 if (locationValid) { 1449 Location location = mLastKnownLocation.get(provider); 1450 if (location == null) { 1451 mLastKnownLocation.put(provider, new Location(loc)); 1452 } else { 1453 location.set(loc); 1454 } 1455 writeLastKnownLocation(provider, loc); 1456 1457 if (p instanceof INetworkLocationProvider) { 1458 mWakeLockNetworkReceived = true; 1459 } else if (p instanceof GpsLocationProvider) { 1460 // Gps location received signal is in NetworkStateBroadcastReceiver 1461 } 1462 } 1463 1464 // Fetch latest status update time 1465 long newStatusUpdateTime = p.getStatusUpdateTime(); 1466 1467 // Override real time with mock time if present 1468 Long mockStatusUpdateTime = mMockProviderStatusUpdateTime.get(provider); 1469 if (mockStatusUpdateTime != null) { 1470 newStatusUpdateTime = mockStatusUpdateTime.longValue(); 1471 } 1472 1473 // Get latest status 1474 Bundle extras = new Bundle(); 1475 int status = p.getStatus(extras); 1476 1477 // Override status with mock status if present 1478 Integer mockStatus = mMockProviderStatus.get(provider); 1479 if (mockStatus != null) { 1480 status = mockStatus.intValue(); 1481 } 1482 1483 // Override extras with mock extras if present 1484 Bundle mockExtras = mMockProviderStatusExtras.get(provider); 1485 if (mockExtras != null) { 1486 extras.clear(); 1487 extras.putAll(mockExtras); 1488 } 1489 1490 // Broadcast location or status to all listeners 1491 for (UpdateRecord r : records) { 1492 Receiver receiver = r.mReceiver; 1493 Object key = receiver.getKey(); 1494 1495 // Broadcast location only if it is valid 1496 if (locationValid) { 1497 HashMap<String,Location> map = mLastFixBroadcast.get(key); 1498 if (map == null) { 1499 map = new HashMap<String,Location>(); 1500 mLastFixBroadcast.put(key, map); 1501 } 1502 Location lastLoc = map.get(provider); 1503 if ((lastLoc == null) || shouldBroadcast(loc, lastLoc, r)) { 1504 if (lastLoc == null) { 1505 lastLoc = new Location(loc); 1506 map.put(provider, lastLoc); 1507 } else { 1508 lastLoc.set(loc); 1509 } 1510 try { 1511 receiver.onLocationChanged(loc); 1512 } catch (RemoteException doe) { 1513 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver); 1514 _removeUpdates(receiver); 1515 } 1516 } 1517 } 1518 1519 // Broadcast status message 1520 HashMap<String,Long> statusMap = mLastStatusBroadcast.get(key); 1521 if (statusMap == null) { 1522 statusMap = new HashMap<String,Long>(); 1523 mLastStatusBroadcast.put(key, statusMap); 1524 } 1525 long prevStatusUpdateTime = 1526 (statusMap.get(provider) != null) ? statusMap.get(provider) : 0; 1527 1528 if ((newStatusUpdateTime > prevStatusUpdateTime) && 1529 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { 1530 1531 statusMap.put(provider, newStatusUpdateTime); 1532 try { 1533 receiver.onStatusChanged(provider, status, extras); 1534 } catch (RemoteException doe) { 1535 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver); 1536 _removeUpdates(receiver); 1537 } 1538 } 1539 } 1540 } 1541 1542 private class LocationWorkerHandler extends Handler { 1543 1544 @Override 1545 public void handleMessage(Message msg) { 1546 try { 1547 if (msg.what == MESSAGE_HEARTBEAT) { 1548 // log("LocationWorkerHandler: Heartbeat!"); 1549 1550 synchronized (mRecordsByProvider) { 1551 String provider = (String) msg.obj; 1552 if (!isAllowedBySettings(provider)) { 1553 return; 1554 } 1555 1556 // Process the location fix if the screen is on or we're holding a wakelock 1557 if (mScreenOn || (mWakeLockAcquireTime != 0)) { 1558 handleLocationChanged(provider); 1559 } 1560 1561 // If it continues to have listeners 1562 HashSet<UpdateRecord> records = mRecordsByProvider.get(provider); 1563 if (records != null && records.size() > 0) { 1564 Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider); 1565 sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000); 1566 } 1567 } 1568 1569 if ((mWakeLockAcquireTime != 0) && 1570 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime 1571 > MAX_TIME_FOR_WAKE_LOCK)) { 1572 1573 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1574 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1575 1576 log("LocationWorkerHandler: Exceeded max time for wake lock"); 1577 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1578 sendMessageAtFrontOfQueue(m); 1579 1580 } else if (mWakeLockAcquireTime != 0 && 1581 mWakeLockGpsReceived && mWakeLockNetworkReceived) { 1582 1583 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1584 removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1585 1586 log("LocationWorkerHandler: Locations received."); 1587 mWakeLockAcquireTime = 0; 1588 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK); 1589 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK); 1590 } 1591 1592 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) { 1593 log("LocationWorkerHandler: Acquire"); 1594 acquireWakeLock(); 1595 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) { 1596 log("LocationWorkerHandler: Release"); 1597 1598 // Update wakelock status so the next alarm is set before releasing wakelock 1599 updateWakelockStatus(mScreenOn); 1600 releaseWakeLock(); 1601 } else if (msg.what == MESSAGE_SET_NETWORK_LOCATION_PROVIDER) { 1602 synchronized (LocationManagerService.class) { 1603 Log.d(TAG, "adding network location provider"); 1604 mNetworkLocationInterface = 1605 (INetworkLocationProvider)msg.obj; 1606 mNetworkLocationInterface.addListener(getPackageNames()); 1607 mNetworkLocationProvider = 1608 (LocationProviderImpl)mNetworkLocationInterface; 1609 LocationProviderImpl.addProvider(mNetworkLocationProvider); 1610 updateProviders(); 1611 } 1612 } 1613 } catch (Exception e) { 1614 // Log, don't crash! 1615 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e); 1616 } 1617 } 1618 } 1619 1620 PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 1621 1622 private CellState mLastCellState = null; 1623 @Override 1624 public void onCellLocationChanged(CellLocation cellLocation) { 1625 try { 1626 int asu = mSignalStrength; 1627 1628 // Gets cell state 1629 mLastCellState = new CellState(mTelephonyManager, cellLocation, asu); 1630 1631 // Notify collector 1632 if (mCollector != null) { 1633 mCollector.updateCellState(mLastCellState); 1634 } 1635 1636 // Updates providers 1637 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 1638 for (LocationProviderImpl provider : providers) { 1639 if (provider.requiresCell()) { 1640 provider.updateCellState(mLastCellState); 1641 } 1642 } 1643 } catch (Exception e) { 1644 Log.e(TAG, "Exception in PhoneStateListener.onCellLocationCahnged:", e); 1645 } 1646 } 1647 1648 @Override 1649 public void onSignalStrengthChanged(int asu) { 1650 mSignalStrength = asu; 1651 1652 if (mLastCellState != null) { 1653 mLastCellState.updateSignalStrength(asu); 1654 } 1655 } 1656 1657 @Override 1658 public void onDataConnectionStateChanged(int state) { 1659 if (mLastCellState != null) { 1660 mLastCellState.updateRadioType(mTelephonyManager); 1661 } 1662 } 1663 }; 1664 1665 private class PowerStateBroadcastReceiver extends BroadcastReceiver { 1666 @Override public void onReceive(Context context, Intent intent) { 1667 String action = intent.getAction(); 1668 1669 if (action.equals(ALARM_INTENT)) { 1670 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1671 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1672 1673 log("PowerStateBroadcastReceiver: Alarm received"); 1674 Message m = mLocationHandler.obtainMessage(MESSAGE_ACQUIRE_WAKE_LOCK); 1675 mLocationHandler.sendMessageAtFrontOfQueue(m); 1676 1677 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1678 log("PowerStateBroadcastReceiver: Screen off"); 1679 updateWakelockStatus(false); 1680 1681 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 1682 log("PowerStateBroadcastReceiver: Screen on"); 1683 updateWakelockStatus(true); 1684 1685 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1686 log("PowerStateBroadcastReceiver: Battery changed"); 1687 int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100); 1688 int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0); 1689 boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0; 1690 1691 // Notify collector battery state 1692 if (mCollector != null) { 1693 mCollector.updateBatteryState(scale, level, plugged); 1694 } 1695 } 1696 } 1697 } 1698 1699 private class NetworkStateBroadcastReceiver extends BroadcastReceiver { 1700 @Override public void onReceive(Context context, Intent intent) { 1701 String action = intent.getAction(); 1702 1703 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 1704 1705 List<ScanResult> wifiScanResults = mWifiManager.getScanResults(); 1706 1707 if (wifiScanResults == null) { 1708 return; 1709 } 1710 1711 // Notify provider and collector of Wifi scan results 1712 if (mCollector != null) { 1713 mCollector.updateWifiScanResults(wifiScanResults); 1714 } 1715 if (mNetworkLocationInterface != null) { 1716 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults); 1717 } 1718 1719 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 1720 int networkState = LocationProvider.TEMPORARILY_UNAVAILABLE; 1721 1722 boolean noConnectivity = 1723 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 1724 if (!noConnectivity) { 1725 networkState = LocationProvider.AVAILABLE; 1726 } 1727 1728 // Notify location providers of current network state 1729 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders(); 1730 for (LocationProviderImpl provider : providers) { 1731 if (provider.requiresNetwork()) { 1732 provider.updateNetworkState(networkState); 1733 } 1734 } 1735 1736 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 1737 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 1738 WifiManager.WIFI_STATE_UNKNOWN); 1739 1740 boolean enabled; 1741 if (state == WifiManager.WIFI_STATE_ENABLED) { 1742 enabled = true; 1743 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 1744 enabled = false; 1745 } else { 1746 return; 1747 } 1748 1749 // Notify network provider of current wifi enabled state 1750 if (mNetworkLocationInterface != null) { 1751 mNetworkLocationInterface.updateWifiEnabledState(enabled); 1752 } 1753 1754 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) { 1755 1756 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, 1757 false); 1758 1759 if (!enabled) { 1760 // When GPS is disabled, we are OK to release wake-lock 1761 mWakeLockGpsReceived = true; 1762 } 1763 } 1764 1765 } 1766 } 1767 1768 // Wake locks 1769 1770 private void updateWakelockStatus(boolean screenOn) { 1771 log("updateWakelockStatus(): " + screenOn); 1772 1773 boolean needsLock = false; 1774 long minTime = Integer.MAX_VALUE; 1775 1776 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) { 1777 needsLock = true; 1778 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime); 1779 } 1780 1781 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) { 1782 needsLock = true; 1783 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime); 1784 if (screenOn) { 1785 startGps(); 1786 } else if (mScreenOn && !screenOn) { 1787 1788 // We just turned the screen off so stop navigating 1789 stopGps(); 1790 } 1791 } 1792 1793 mScreenOn = screenOn; 1794 1795 PendingIntent sender = 1796 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0); 1797 1798 // Cancel existing alarm 1799 log("Cancelling existing alarm"); 1800 mAlarmManager.cancel(sender); 1801 1802 if (needsLock && !mScreenOn) { 1803 long now = SystemClock.elapsedRealtime(); 1804 mAlarmManager.set( 1805 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender); 1806 mAlarmInterval = minTime; 1807 log("Creating a new wakelock alarm with minTime = " + minTime); 1808 } else { 1809 log("No need for alarm"); 1810 mAlarmInterval = -1; 1811 1812 // Clear out existing wakelocks 1813 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK); 1814 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK); 1815 releaseWakeLock(); 1816 } 1817 } 1818 1819 private void acquireWakeLock() { 1820 try { 1821 acquireWakeLockX(); 1822 } catch (Exception e) { 1823 // This is to catch a runtime exception thrown when we try to release an 1824 // already released lock. 1825 Log.e(TAG, "exception in acquireWakeLock()", e); 1826 } 1827 } 1828 1829 private void acquireWakeLockX() { 1830 if (mWakeLock.isHeld()) { 1831 log("Must release wakelock before acquiring"); 1832 mWakeLockAcquireTime = 0; 1833 mWakeLock.release(); 1834 } 1835 1836 boolean networkActive = (mNetworkLocationProvider != null) 1837 && mNetworkLocationProvider.isLocationTracking(); 1838 boolean gpsActive = (mGpsLocationProvider != null) 1839 && mGpsLocationProvider.isLocationTracking(); 1840 1841 boolean needsLock = networkActive || gpsActive; 1842 if (!needsLock) { 1843 log("No need for Lock!"); 1844 return; 1845 } 1846 1847 mWakeLockGpsReceived = !gpsActive; 1848 mWakeLockNetworkReceived = !networkActive; 1849 1850 // Acquire wake lock 1851 mWakeLock.acquire(); 1852 mWakeLockAcquireTime = SystemClock.elapsedRealtime(); 1853 log("Acquired wakelock"); 1854 1855 // Start the gps provider 1856 startGps(); 1857 1858 // Acquire cell lock 1859 if (mCellWakeLockAcquired) { 1860 // Lock is already acquired 1861 } else if (!mWakeLockNetworkReceived) { 1862 mTelephonyManager.enableLocationUpdates(); 1863 mCellWakeLockAcquired = true; 1864 } else { 1865 mCellWakeLockAcquired = false; 1866 } 1867 1868 // Notify NetworkLocationProvider 1869 if (mNetworkLocationInterface != null) { 1870 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); 1871 } 1872 1873 // Acquire wifi lock 1874 WifiManager.WifiLock wifiLock = getWifiWakelock(); 1875 if (wifiLock != null) { 1876 if (mWifiWakeLockAcquired) { 1877 // Lock is already acquired 1878 } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) { 1879 wifiLock.acquire(); 1880 mWifiWakeLockAcquired = true; 1881 } else { 1882 mWifiWakeLockAcquired = false; 1883 Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock"); 1884 } 1885 } 1886 } 1887 1888 private void startGps() { 1889 boolean gpsActive = (mGpsLocationProvider != null) 1890 && mGpsLocationProvider.isLocationTracking(); 1891 if (gpsActive) { 1892 mGpsLocationProvider.startNavigating(); 1893 long identity = Binder.clearCallingIdentity(); 1894 try { 1895 mBatteryStats.noteStartGps(mCallingUid == -1 ? getCallingUid() : mCallingUid); 1896 } catch (RemoteException e) { 1897 Log.w(TAG, "RemoteException calling noteStartGps on BatteryStatsService", e); 1898 } finally { 1899 Binder.restoreCallingIdentity(identity); 1900 } 1901 } 1902 } 1903 1904 private void stopGps() { 1905 boolean gpsActive = mGpsLocationProvider != null 1906 && mGpsLocationProvider.isLocationTracking(); 1907 if (gpsActive) { 1908 mGpsLocationProvider.stopNavigating(); 1909 long identity = Binder.clearCallingIdentity(); 1910 try { 1911 mBatteryStats.noteStopGps(mCallingUid == -1 ? getCallingUid() : mCallingUid); 1912 } catch (RemoteException e) { 1913 Log.w(TAG, "RemoteException calling noteStopGps on BatteryStatsService", e); 1914 } finally { 1915 Binder.restoreCallingIdentity(identity); 1916 } 1917 } 1918 } 1919 1920 private void releaseWakeLock() { 1921 try { 1922 releaseWakeLockX(); 1923 } catch (Exception e) { 1924 // This is to catch a runtime exception thrown when we try to release an 1925 // already released lock. 1926 Log.e(TAG, "exception in releaseWakeLock()", e); 1927 } 1928 } 1929 1930 private void releaseWakeLockX() { 1931 // Release wifi lock 1932 WifiManager.WifiLock wifiLock = getWifiWakelock(); 1933 if (wifiLock != null) { 1934 if (mWifiWakeLockAcquired) { 1935 wifiLock.release(); 1936 mWifiWakeLockAcquired = false; 1937 } 1938 } 1939 1940 if (!mScreenOn) { 1941 // Stop the gps 1942 stopGps(); 1943 } 1944 1945 // Release cell lock 1946 if (mCellWakeLockAcquired) { 1947 mTelephonyManager.disableLocationUpdates(); 1948 mCellWakeLockAcquired = false; 1949 } 1950 1951 // Notify NetworkLocationProvider 1952 if (mNetworkLocationInterface != null) { 1953 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired); 1954 } 1955 1956 // Release wake lock 1957 mWakeLockAcquireTime = 0; 1958 if (mWakeLock.isHeld()) { 1959 log("Released wakelock"); 1960 mWakeLock.release(); 1961 } else { 1962 log("Can't release wakelock again!"); 1963 } 1964 } 1965 1966 // Geocoder 1967 1968 public String getFromLocation(double latitude, double longitude, int maxResults, 1969 String language, String country, String variant, String appName, List<Address> addrs) { 1970 if (mNetworkLocationInterface != null) { 1971 return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults, 1972 language, country, variant, appName, addrs); 1973 } else { 1974 return null; 1975 } 1976 } 1977 1978 public String getFromLocationName(String locationName, 1979 double lowerLeftLatitude, double lowerLeftLongitude, 1980 double upperRightLatitude, double upperRightLongitude, int maxResults, 1981 String language, String country, String variant, String appName, List<Address> addrs) { 1982 if (mNetworkLocationInterface != null) { 1983 return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, 1984 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults, 1985 language, country, variant, appName, addrs); 1986 } else { 1987 return null; 1988 } 1989 } 1990 1991 // Mock Providers 1992 1993 class MockProvider extends LocationProviderImpl { 1994 boolean mRequiresNetwork; 1995 boolean mRequiresSatellite; 1996 boolean mRequiresCell; 1997 boolean mHasMonetaryCost; 1998 boolean mSupportsAltitude; 1999 boolean mSupportsSpeed; 2000 boolean mSupportsBearing; 2001 int mPowerRequirement; 2002 int mAccuracy; 2003 2004 public MockProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2005 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2006 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2007 super(name); 2008 2009 mRequiresNetwork = requiresNetwork; 2010 mRequiresSatellite = requiresSatellite; 2011 mRequiresCell = requiresCell; 2012 mHasMonetaryCost = hasMonetaryCost; 2013 mSupportsAltitude = supportsAltitude; 2014 mSupportsBearing = supportsBearing; 2015 mSupportsSpeed = supportsSpeed; 2016 mPowerRequirement = powerRequirement; 2017 mAccuracy = accuracy; 2018 } 2019 2020 @Override 2021 public void disable() { 2022 String name = getName(); 2023 mEnabledProviders.remove(name); 2024 mDisabledProviders.add(name); 2025 } 2026 2027 @Override 2028 public void enable() { 2029 String name = getName(); 2030 mEnabledProviders.add(name); 2031 mDisabledProviders.remove(name); 2032 } 2033 2034 @Override 2035 public boolean getLocation(Location l) { 2036 Location loc = mMockProviderLocation.get(getName()); 2037 if (loc == null) { 2038 return false; 2039 } 2040 l.set(loc); 2041 return true; 2042 } 2043 2044 @Override 2045 public int getStatus(Bundle extras) { 2046 String name = getName(); 2047 Integer s = mMockProviderStatus.get(name); 2048 int status = (s == null) ? AVAILABLE : s.intValue(); 2049 Bundle newExtras = mMockProviderStatusExtras.get(name); 2050 if (newExtras != null) { 2051 extras.clear(); 2052 extras.putAll(newExtras); 2053 } 2054 return status; 2055 } 2056 2057 @Override 2058 public boolean isEnabled() { 2059 return mEnabledProviders.contains(getName()); 2060 } 2061 2062 @Override 2063 public int getAccuracy() { 2064 return mAccuracy; 2065 } 2066 2067 @Override 2068 public int getPowerRequirement() { 2069 return mPowerRequirement; 2070 } 2071 2072 @Override 2073 public boolean hasMonetaryCost() { 2074 return mHasMonetaryCost; 2075 } 2076 2077 @Override 2078 public boolean requiresCell() { 2079 return mRequiresCell; 2080 } 2081 2082 @Override 2083 public boolean requiresNetwork() { 2084 return mRequiresNetwork; 2085 } 2086 2087 @Override 2088 public boolean requiresSatellite() { 2089 return mRequiresSatellite; 2090 } 2091 2092 @Override 2093 public boolean supportsAltitude() { 2094 return mSupportsAltitude; 2095 } 2096 2097 @Override 2098 public boolean supportsBearing() { 2099 return mSupportsBearing; 2100 } 2101 2102 @Override 2103 public boolean supportsSpeed() { 2104 return mSupportsSpeed; 2105 } 2106 } 2107 2108 private void checkMockPermissions() { 2109 boolean allowMocks = false; 2110 try { 2111 allowMocks = Settings.Secure.getInt(mContext.getContentResolver(), 2112 Settings.Secure.ALLOW_MOCK_LOCATION) == 1; 2113 } catch (SettingNotFoundException e) { 2114 // Do nothing 2115 } 2116 if (!allowMocks) { 2117 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting"); 2118 } 2119 2120 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) != 2121 PackageManager.PERMISSION_GRANTED) { 2122 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission"); 2123 } 2124 } 2125 2126 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 2127 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 2128 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 2129 checkMockPermissions(); 2130 2131 MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite, 2132 requiresCell, hasMonetaryCost, supportsAltitude, 2133 supportsSpeed, supportsBearing, powerRequirement, accuracy); 2134 if (LocationProviderImpl.getProvider(name) != null) { 2135 throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); 2136 } 2137 LocationProviderImpl.addProvider(provider); 2138 updateProviders(); 2139 } 2140 2141 public void removeTestProvider(String provider) { 2142 checkMockPermissions(); 2143 LocationProviderImpl p = LocationProviderImpl.getProvider(provider); 2144 if (p == null) { 2145 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2146 } 2147 LocationProviderImpl.removeProvider(p); 2148 updateProviders(); 2149 } 2150 2151 public void setTestProviderLocation(String provider, Location loc) { 2152 checkMockPermissions(); 2153 if (LocationProviderImpl.getProvider(provider) == null) { 2154 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2155 } 2156 mMockProviderLocation.put(provider, loc); 2157 } 2158 2159 public void clearTestProviderLocation(String provider) { 2160 checkMockPermissions(); 2161 if (LocationProviderImpl.getProvider(provider) == null) { 2162 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2163 } 2164 mMockProviderLocation.remove(provider); 2165 } 2166 2167 public void setTestProviderEnabled(String provider, boolean enabled) { 2168 checkMockPermissions(); 2169 if (LocationProviderImpl.getProvider(provider) == null) { 2170 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2171 } 2172 if (enabled) { 2173 mEnabledProviders.add(provider); 2174 mDisabledProviders.remove(provider); 2175 } else { 2176 mEnabledProviders.remove(provider); 2177 mDisabledProviders.add(provider); 2178 } 2179 updateProviders(); 2180 } 2181 2182 public void clearTestProviderEnabled(String provider) { 2183 checkMockPermissions(); 2184 if (LocationProviderImpl.getProvider(provider) == null) { 2185 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2186 } 2187 mEnabledProviders.remove(provider); 2188 mDisabledProviders.remove(provider); 2189 updateProviders(); 2190 } 2191 2192 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 2193 checkMockPermissions(); 2194 if (LocationProviderImpl.getProvider(provider) == null) { 2195 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2196 } 2197 mMockProviderStatus.put(provider, new Integer(status)); 2198 mMockProviderStatusExtras.put(provider, extras); 2199 mMockProviderStatusUpdateTime.put(provider, new Long(updateTime)); 2200 } 2201 2202 public void clearTestProviderStatus(String provider) { 2203 checkMockPermissions(); 2204 if (LocationProviderImpl.getProvider(provider) == null) { 2205 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); 2206 } 2207 mMockProviderStatus.remove(provider); 2208 mMockProviderStatusExtras.remove(provider); 2209 mMockProviderStatusUpdateTime.remove(provider); 2210 } 2211 2212 private void log(String log) { 2213 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2214 Log.d(TAG, log); 2215 } 2216 } 2217} 2218 2219