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