FileDocCategorySizeDatePackage
LocationManagerService.javaAPI DocAndroid 1.5 API108110Wed May 06 22:42:00 BST 2009com.android.server

LocationManagerService

public class LocationManagerService extends ILocationManager.Stub implements com.android.internal.location.INetworkLocationManager
The service class that manages LocationProviders and issues location updates and alerts. {@hide}

Fields Summary
private static final String
TAG
private static final boolean
LOCAL_LOGV
private static final long
MIN_LAST_KNOWN_LOCATION_TIME
private static final long
MAX_TIME_FOR_WAKE_LOCK
private static final long
TIME_AFTER_WAKE_LOCK
private HashMap
mLastWriteTime
private static final Pattern
PATTERN_COMMA
private static final String
ACCESS_FINE_LOCATION
private static final String
ACCESS_COARSE_LOCATION
private static final String
ACCESS_MOCK_LOCATION
private static final String
ACCESS_LOCATION_EXTRA_COMMANDS
private final Set
mEnabledProviders
private final Set
mDisabledProviders
HashMap
mMockProviders
private final HashMap
mMockProviderLocation
private final HashMap
mMockProviderStatus
private final HashMap
mMockProviderStatusExtras
private final HashMap
mMockProviderStatusUpdateTime
private static boolean
sProvidersLoaded
private final android.content.Context
mContext
private com.android.internal.location.GpsLocationProvider
mGpsLocationProvider
private boolean
mGpsNavigating
private android.location.LocationProviderImpl
mNetworkLocationProvider
private com.android.internal.location.INetworkLocationProvider
mNetworkLocationInterface
private LocationWorkerHandler
mLocationHandler
private static final int
MESSAGE_HEARTBEAT
private static final int
MESSAGE_ACQUIRE_WAKE_LOCK
private static final int
MESSAGE_RELEASE_WAKE_LOCK
private static final int
MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER
private static final String
ALARM_INTENT
private static final String
WAKELOCK_KEY
private static final String
WIFILOCK_KEY
private android.app.AlarmManager
mAlarmManager
private long
mAlarmInterval
private boolean
mScreenOn
private PowerManager.WakeLock
mWakeLock
private WifiManager.WifiLock
mWifiLock
private long
mWakeLockAcquireTime
private boolean
mWakeLockGpsReceived
private boolean
mWakeLockNetworkReceived
private boolean
mWifiWakeLockAcquired
private boolean
mCellWakeLockAcquired
private final com.android.internal.app.IBatteryStats
mBatteryStats
private final ArrayList
mListeners
Mapping from listener IBinder/PendingIntent to local Listener wrappers.
private final android.util.SparseIntArray
mReportedGpsUids
Used for reporting which UIDs are causing the GPS to run.
private int
mReportedGpsSeq
private final HashMap
mLocationListeners
Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord. This also serves as the lock for our state.
private final HashMap
mLastFixBroadcast
Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast location.
private final HashMap
mLastStatusBroadcast
private final HashMap
mRecordsByProvider
Mapping from provider name to all its UpdateRecords
private final HashMap
mLocationsByProvider
Mappings from provider name to object to use for current location. Locations contained in this list may not always be valid.
private Receiver
mProximityListener
private HashMap
mProximityAlerts
private HashSet
mProximitiesEntered
private HashMap
mLastKnownLocation
private static final String
BATTERY_EXTRA_SCALE
private static final String
BATTERY_EXTRA_LEVEL
private static final String
BATTERY_EXTRA_PLUGGED
private android.telephony.TelephonyManager
mTelephonyManager
private com.android.internal.location.ILocationCollector
mCollector
private android.net.wifi.WifiManager
mWifiManager
private int
mNetworkState
private boolean
mWifiEnabled
CellLocationUpdater
mCellLocationUpdater
com.android.internal.location.CellState
mLastCellState
int
mLastSignalStrength
int
mLastRadioType
android.telephony.PhoneStateListener
mPhoneStateListener
Constructors Summary
public LocationManagerService(android.content.Context context)

param
context the context that the LocationManagerService runs in

        super();
        mContext = context;
        mLocationHandler = new LocationWorkerHandler();

        if (LOCAL_LOGV) {
            Log.v(TAG, "Constructed LocationManager Service");
        }

        // Alarm manager, needs to be done before calling loadProviders() below
        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        // Create a wake lock, needs to be done before calling loadProviders() below
        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
        
        // Battery statistics service to be notified when GPS turns on or off
        mBatteryStats = BatteryStatsService.getService();

        // Load providers
        loadProviders();

        // Listen for Radio changes
        mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        mTelephonyManager.listen(mPhoneStateListener,
                PhoneStateListener.LISTEN_CELL_LOCATION |
                PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);

        // Register for Network (Wifi or Mobile) updates
        NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
        IntentFilter networkIntentFilter = new IntentFilter();
        networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
        context.registerReceiver(networkReceiver, networkIntentFilter);

        // Register for power updates
        PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ALARM_INTENT);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
        context.registerReceiver(powerStateReceiver, intentFilter);

        // Get the wifi manager
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

        // Create a wifi lock for future use
        mWifiLock = getWifiWakelockLocked();
    
Methods Summary
private java.util.List_getAllProvidersLocked()

        if (LOCAL_LOGV) {
            Log.v(TAG, "getAllProviders");
        }
        List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
        ArrayList<String> out = new ArrayList<String>(providers.size());

        for (LocationProviderImpl p : providers) {
            out.add(p.getName());
        }
        return out;
    
private android.location.Location_getLastKnownLocationLocked(java.lang.String provider)

        checkPermissionsSafe(provider);

        LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
        if (p == null) {
            throw new IllegalArgumentException("provider=" + provider);
        }

        if (!isAllowedBySettingsLocked(provider)) {
            return null;
        }

        Location location = mLastKnownLocation.get(provider);
        if (location == null) {
            // Get the persistent last known location for the provider
            location = readLastKnownLocationLocked(provider);
            if (location != null) {
                mLastKnownLocation.put(provider, location);
            }
        }

        return location;
    
private android.os.Bundle_getProviderInfoLocked(java.lang.String provider)

        LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
        if (p == null) {
            return null;
        }

        checkPermissionsSafe(provider);

        Bundle b = new Bundle();
        b.putBoolean("network", p.requiresNetwork());
        b.putBoolean("satellite", p.requiresSatellite());
        b.putBoolean("cell", p.requiresCell());
        b.putBoolean("cost", p.hasMonetaryCost());
        b.putBoolean("altitude", p.supportsAltitude());
        b.putBoolean("speed", p.supportsSpeed());
        b.putBoolean("bearing", p.supportsBearing());
        b.putInt("power", p.getPowerRequirement());
        b.putInt("accuracy", p.getAccuracy());

        return b;
    
private java.util.List_getProvidersLocked(boolean enabledOnly)

        if (LOCAL_LOGV) {
            Log.v(TAG, "getProviders");
        }
        List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
        ArrayList<String> out = new ArrayList<String>();

        for (LocationProviderImpl p : providers) {
            String name = p.getName();
            if (isAllowedProviderSafe(name)) {
                if (enabledOnly && !isAllowedBySettingsLocked(name)) {
                    continue;
                }
                out.add(name);
            }
        }
        return out;
    
private boolean_isProviderEnabledLocked(java.lang.String provider)

        checkPermissionsSafe(provider);

        LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
        if (p == null) {
            throw new IllegalArgumentException("provider=" + provider);
        }
        return isAllowedBySettingsLocked(provider);
    
private void_loadProvidersLocked()

        // Attempt to load "real" providers first
        if (GpsLocationProvider.isSupported()) {
            // Create a gps location provider
            mGpsLocationProvider = new GpsLocationProvider(mContext);
            LocationProviderImpl.addProvider(mGpsLocationProvider);
        }

        // Load fake providers if real providers are not available
        File f = new File(LocationManager.PROVIDER_DIR);
        if (f.isDirectory()) {
            File[] subdirs = f.listFiles();
            for (int i = 0; i < subdirs.length; i++) {
                if (!subdirs[i].isDirectory()) {
                    continue;
                }

                String name = subdirs[i].getName();

                if (LOCAL_LOGV) {
                    Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath());
                    Log.v(TAG, "name = " + name);
                }

                // Don't create a fake provider if a real provider exists
                if (LocationProviderImpl.getProvider(name) == null) {
                    LocationProviderImpl provider = null;
                    try {
                        File classFile = new File(subdirs[i], "class");
                        // Look for a 'class' file
                        provider = LocationProviderImpl.loadFromClass(classFile);

                        // Look for an 'kml', 'nmea', or 'track' file
                        if (provider == null) {
                            // Load properties from 'properties' file, if present
                            File propertiesFile = new File(subdirs[i], "properties");

                            if (propertiesFile.exists()) {
                                provider = new TrackProvider(name);
                                ((TrackProvider)provider).readProperties(propertiesFile);

                                File kmlFile = new File(subdirs[i], "kml");
                                if (kmlFile.exists()) {
                                    ((TrackProvider) provider).readKml(kmlFile);
                                } else {
                                    File nmeaFile = new File(subdirs[i], "nmea");
                                    if (nmeaFile.exists()) {
                                        ((TrackProvider) provider).readNmea(name, nmeaFile);
                                    } else {
                                        File trackFile = new File(subdirs[i], "track");
                                        if (trackFile.exists()) {
                                            ((TrackProvider) provider).readTrack(trackFile);
                                        }
                                    }
                                }
                            }
                        }
                        if (provider != null) {
                            LocationProviderImpl.addProvider(provider);
                        }
                        // Grab the initial location of a TrackProvider and
                        // store it as the last known location for that provider
                        if (provider instanceof TrackProvider) {
                            TrackProvider tp = (TrackProvider) provider;
                            mLastKnownLocation.put(tp.getName(), tp.getInitialLocation());
                        }
                    } catch (Exception e) {
                        Log.e(TAG, "Exception loading provder " + name, e);
                    }
                }
            }
        }

        updateProvidersLocked();
    
private voidacquireWakeLockLocked()

        try {
            acquireWakeLockXLocked();
        } catch (Exception e) {
            // This is to catch a runtime exception thrown when we try to release an
            // already released lock.
            Log.e(TAG, "exception in acquireWakeLock()", e);
        }
    
private voidacquireWakeLockXLocked()

        if (mWakeLock.isHeld()) {
            log("Must release wakelock before acquiring");
            mWakeLockAcquireTime = 0;
            mWakeLock.release();
        }

        boolean networkActive = (mNetworkLocationProvider != null)
                && mNetworkLocationProvider.isLocationTracking();
        boolean gpsActive = (mGpsLocationProvider != null)
                && mGpsLocationProvider.isLocationTracking();

        boolean needsLock = networkActive || gpsActive;
        if (!needsLock) {
            log("No need for Lock!");
            return;
        }

        mWakeLockGpsReceived = !gpsActive;
        mWakeLockNetworkReceived = !networkActive;

        // Acquire wake lock
        mWakeLock.acquire();
        mWakeLockAcquireTime = SystemClock.elapsedRealtime();
        log("Acquired wakelock");

        // Start the gps provider
        startGpsLocked();

        // Acquire cell lock
        if (mCellWakeLockAcquired) {
            // Lock is already acquired
        } else if (!mWakeLockNetworkReceived) {
            mTelephonyManager.enableLocationUpdates();
            mCellWakeLockAcquired = true;
        } else {
            mCellWakeLockAcquired = false;
        }

        // Notify NetworkLocationProvider
        if (mNetworkLocationInterface != null) {
            mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
        }

        // Acquire wifi lock
        WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
        if (wifiLock != null) {
            if (mWifiWakeLockAcquired) {
                // Lock is already acquired
            } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) {
                wifiLock.acquire();
                mWifiWakeLockAcquired = true;
            } else {
                mWifiWakeLockAcquired = false;
                Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock");
            }
        }
    
public booleanaddGpsStatusListener(android.location.IGpsStatusListener listener)

        if (mGpsLocationProvider == null) {
            return false;
        }
        if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
                PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
        }

        try {
            mGpsLocationProvider.addGpsStatusListener(listener);
        } catch (RemoteException e) {
            Log.w(TAG, "RemoteException in addGpsStatusListener");
            return false;
        }
        return true;
    
public voidaddProximityAlert(double latitude, double longitude, float radius, long expiration, android.app.PendingIntent intent)

        try {
            synchronized (mLocationListeners) {
                addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "addProximityAlert got exception:", e);
        }
    
private voidaddProximityAlertLocked(double latitude, double longitude, float radius, long expiration, android.app.PendingIntent intent)

        if (LOCAL_LOGV) {
            Log.v(TAG, "addProximityAlert: latitude = " + latitude +
                    ", longitude = " + longitude +
                    ", expiration = " + expiration +
                    ", intent = " + intent);
        }

        // Require ability to access all providers for now
        if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
            !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
        }

        if (expiration != -1) {
            expiration += System.currentTimeMillis();
        }
        ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
                latitude, longitude, radius, expiration, intent);
        mProximityAlerts.put(intent, alert);

        if (mProximityListener == null) {
            mProximityListener = new Receiver(new ProximityListener(), -1);

            LocationProvider provider = LocationProviderImpl.getProvider(
                LocationManager.GPS_PROVIDER);
            if (provider != null) {
                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
            }

            provider =
                LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
            if (provider != null) {
                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
            }
        } else if (mGpsNavigating) {
            updateReportedGpsLocked();
        }
    
public voidaddTestProvider(java.lang.String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy)

        checkMockPermissionsSafe();

        synchronized (mLocationListeners) {
            MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
                requiresCell, hasMonetaryCost, supportsAltitude,
                supportsSpeed, supportsBearing, powerRequirement, accuracy);
            if (LocationProviderImpl.getProvider(name) != null) {
                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
            }
            LocationProviderImpl.addProvider(provider);
            updateProvidersLocked();
        }
    
private voidcheckMockPermissionsSafe()

        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
        if (!allowMocks) {
            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
        }

        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
            PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
        }            
    
private voidcheckPermissionsSafe(java.lang.String provider)

        if (LocationManager.GPS_PROVIDER.equals(provider)
            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)) {
            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
        }
        if (LocationManager.NETWORK_PROVIDER.equals(provider)
            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)
            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)) {
            throw new SecurityException(
                "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
        }
    
public voidclearTestProviderEnabled(java.lang.String provider)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            mEnabledProviders.remove(provider);
            mDisabledProviders.remove(provider);
            updateProvidersLocked();
        }
    
public voidclearTestProviderLocation(java.lang.String provider)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            mMockProviderLocation.remove(provider);
        }
    
public voidclearTestProviderStatus(java.lang.String provider)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            mMockProviderStatus.remove(provider);
            mMockProviderStatusExtras.remove(provider);
            mMockProviderStatusUpdateTime.remove(provider);
        }
    
protected voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                != PackageManager.PERMISSION_GRANTED) {
            pw.println("Permission Denial: can't dump AlarmManager from from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
            return;
        }
        
        synchronized (mLocationListeners) {
            pw.println("Current Location Manager state:");
            pw.println("  sProvidersLoaded=" + sProvidersLoaded);
            pw.println("  mGpsLocationProvider=" + mGpsLocationProvider);
            pw.println("  mGpsNavigating=" + mGpsNavigating);
            pw.println("  mNetworkLocationProvider=" + mNetworkLocationProvider);
            pw.println("  mNetworkLocationInterface=" + mNetworkLocationInterface);
            pw.println("  mLastSignalStrength=" + mLastSignalStrength
                    + "  mLastRadioType=" + mLastRadioType);
            pw.println("  mCellLocationUpdater=" + mCellLocationUpdater);
            pw.println("  mLastCellState=" + mLastCellState);
            pw.println("  mCollector=" + mCollector);
            pw.println("  mAlarmInterval=" + mAlarmInterval
                    + " mScreenOn=" + mScreenOn
                    + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
            pw.println("  mWakeLockGpsReceived=" + mWakeLockGpsReceived
                    + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
            pw.println("  mWifiWakeLockAcquired=" + mWifiWakeLockAcquired
                    + " mCellWakeLockAcquired=" + mCellWakeLockAcquired);
            pw.println("  Listeners:");
            int N = mListeners.size();
            for (int i=0; i<N; i++) {
                pw.println("    " + mListeners.get(i));
            }
            pw.println("  Location Listeners:");
            for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i
                    : mLocationListeners.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) {
                    pw.println("      " + j.getKey() + ":");
                    j.getValue().dump(pw, "        ");
                }
            }
            pw.println("  Last Fix Broadcasts:");
            for (Map.Entry<Receiver, HashMap<String,Location>> i
                    : mLastFixBroadcast.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                for (Map.Entry<String,Location> j : i.getValue().entrySet()) {
                    pw.println("      " + j.getKey() + ":");
                    j.getValue().dump(new PrintWriterPrinter(pw), "        ");
                }
            }
            pw.println("  Last Status Broadcasts:");
            for (Map.Entry<Receiver, HashMap<String,Long>> i
                    : mLastStatusBroadcast.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                for (Map.Entry<String,Long> j : i.getValue().entrySet()) {
                    pw.println("      " + j.getKey() + " -> 0x"
                            + Long.toHexString(j.getValue()));
                }
            }
            pw.println("  Records by Provider:");
            for (Map.Entry<String, ArrayList<UpdateRecord>> i
                    : mRecordsByProvider.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                for (UpdateRecord j : i.getValue()) {
                    pw.println("      " + j + ":");
                    j.dump(pw, "        ");
                }
            }
            pw.println("  Locations by Provider:");
            for (Map.Entry<String, Location> i
                    : mLocationsByProvider.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                i.getValue().dump(new PrintWriterPrinter(pw), "      ");
            }
            pw.println("  Last Known Locations:");
            for (Map.Entry<String, Location> i
                    : mLastKnownLocation.entrySet()) {
                pw.println("    " + i.getKey() + ":");
                i.getValue().dump(new PrintWriterPrinter(pw), "      ");
            }
            if (mProximityAlerts.size() > 0) {
                pw.println("  Proximity Alerts:");
                for (Map.Entry<PendingIntent, ProximityAlert> i
                        : mProximityAlerts.entrySet()) {
                    pw.println("    " + i.getKey() + ":");
                    i.getValue().dump(pw, "      ");
                }
            }
            if (mProximitiesEntered.size() > 0) {
                pw.println("  Proximities Entered:");
                for (ProximityAlert i : mProximitiesEntered) {
                    pw.println("    " + i + ":");
                    i.dump(pw, "      ");
                }
            }
            pw.println("  mProximityListener=" + mProximityListener);
            if (mEnabledProviders.size() > 0) {
                pw.println("  Enabled Providers:");
                for (String i : mEnabledProviders) {
                    pw.println("    " + i);
                }
                
            }
            if (mDisabledProviders.size() > 0) {
                pw.println("  Disabled Providers:");
                for (String i : mDisabledProviders) {
                    pw.println("    " + i);
                }
                
            }
            if (mMockProviders.size() > 0) {
                pw.println("  Mock Providers:");
                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
                    pw.println("    " + i.getKey() + " -> " + i.getValue());
                }
            }
            if (mMockProviderLocation.size() > 0) {
                pw.println("  Mock Provider Location:");
                for (Map.Entry<String, Location> i : mMockProviderLocation.entrySet()) {
                    pw.println("    " + i.getKey() + ":");
                    i.getValue().dump(new PrintWriterPrinter(pw), "      ");
                }
            }
            if (mMockProviderStatus.size() > 0) {
                pw.println("  Mock Provider Status:");
                for (Map.Entry<String, Integer> i : mMockProviderStatus.entrySet()) {
                    pw.println("    " + i.getKey() + " -> 0x"
                            + Integer.toHexString(i.getValue()));
                }
            }
            if (mMockProviderStatusExtras.size() > 0) {
                pw.println("  Mock Provider Status Extras:");
                for (Map.Entry<String, Bundle> i : mMockProviderStatusExtras.entrySet()) {
                    pw.println("    " + i.getKey() + " -> " + i.getValue());
                }
            }
            if (mMockProviderStatusUpdateTime.size() > 0) {
                pw.println("  Mock Provider Status Update Time:");
                for (Map.Entry<String, Long> i : mMockProviderStatusUpdateTime.entrySet()) {
                    pw.println("    " + i.getKey() + " -> " + i.getValue());
                }
            }
            pw.println("  Reported GPS UIDs @ seq " + mReportedGpsSeq + ":");
            N = mReportedGpsUids.size();
            for (int i=0; i<N; i++)  {
                pw.println("    UID " + mReportedGpsUids.keyAt(i)
                        + " seq=" + mReportedGpsUids.valueAt(i));
            }
        }
    
public java.util.ListgetAllProviders()

        try {
            synchronized (mLocationListeners) {
                return _getAllProvidersLocked();
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "getAllProviders got exception:", e);
            return null;
        }
    
public java.lang.StringgetFromLocation(double latitude, double longitude, int maxResults, java.lang.String language, java.lang.String country, java.lang.String variant, java.lang.String appName, java.util.List addrs)

        synchronized (mLocationListeners) {
            if (mNetworkLocationInterface != null) {
                return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults,
                        language, country, variant, appName, addrs);
            } else {
                return null;
            }
        }
    
public java.lang.StringgetFromLocationName(java.lang.String locationName, double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude, double upperRightLongitude, int maxResults, java.lang.String language, java.lang.String country, java.lang.String variant, java.lang.String appName, java.util.List addrs)

        synchronized (mLocationListeners) {
            if (mNetworkLocationInterface != null) {
                return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude, 
                        lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults,
                        language, country, variant, appName, addrs);
            } else {
                return null;
            }
        }
    
public android.location.LocationgetLastKnownLocation(java.lang.String provider)

        try {
            synchronized (mLocationListeners) {
                return _getLastKnownLocationLocked(provider);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "getLastKnownLocation got exception:", e);
            return null;
        }
    
private longgetMinTimeLocked(java.lang.String provider)

        long minTime = Long.MAX_VALUE;
        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
        if (records != null) {
            for (int i=records.size()-1; i>=0; i--) {
                minTime = Math.min(minTime, records.get(i).mMinTime);
            }
        }
        return minTime;
    
private java.lang.String[]getPackageNames()

        // Since a single UID may correspond to multiple packages, this can only be used as an
        // approximation for tracking
        return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
    
public android.os.BundlegetProviderInfo(java.lang.String provider)

return
null if the provider does not exits
throw
SecurityException if the provider is not allowed to be accessed by the caller

        try {
            synchronized (mLocationListeners) {
                return _getProviderInfoLocked(provider);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "_getProviderInfo got exception:", e);
            return null;
        }
    
public java.util.ListgetProviders(boolean enabledOnly)

        try {
            synchronized (mLocationListeners) {
                return _getProvidersLocked(enabledOnly);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "getProviders got exception:", e);
            return null;
        }
    
private WifiManager.WifiLockgetWifiWakelockLocked()

        if (mWifiLock == null && mWifiManager != null) {
            mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
            mWifiLock.setReferenceCounted(false);
        }
        return mWifiLock;
    
private voidhandleLocationChangedLocked(java.lang.String provider)

        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
        if (records == null || records.size() == 0) {
            return;
        }

        LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
        if (p == null) {
            return;
        }

        // Get location object
        Location loc = mLocationsByProvider.get(provider);
        if (loc == null) {
            loc = new Location(provider);
            mLocationsByProvider.put(provider, loc);
        } else {
            loc.reset();
        }

        // Use the mock location if available
        Location mockLoc = mMockProviderLocation.get(provider);
        boolean locationValid;
        if (mockLoc != null) {
            locationValid = true;
            loc.set(mockLoc);
        } else {
            locationValid = p.getLocation(loc);
        }

        // Update last known location for provider
        if (locationValid) {
            Location location = mLastKnownLocation.get(provider);
            if (location == null) {
                mLastKnownLocation.put(provider, new Location(loc));
            } else {
                location.set(loc);
            }
            writeLastKnownLocationLocked(provider, loc);

            if (p instanceof INetworkLocationProvider) {
                mWakeLockNetworkReceived = true;
            } else if (p instanceof GpsLocationProvider) {
                // Gps location received signal is in NetworkStateBroadcastReceiver
            }
        }

        // Fetch latest status update time
        long newStatusUpdateTime = p.getStatusUpdateTime();

        // Override real time with mock time if present
        Long mockStatusUpdateTime = mMockProviderStatusUpdateTime.get(provider);
        if (mockStatusUpdateTime != null) {
            newStatusUpdateTime = mockStatusUpdateTime.longValue();
        }

        // Get latest status
        Bundle extras = new Bundle();
        int status = p.getStatus(extras);

        // Override status with mock status if present
        Integer mockStatus = mMockProviderStatus.get(provider);
        if (mockStatus != null) {
            status = mockStatus.intValue();
        }

        // Override extras with mock extras if present
        Bundle mockExtras = mMockProviderStatusExtras.get(provider);
        if (mockExtras != null) {
            extras.clear();
            extras.putAll(mockExtras);
        }

        ArrayList<Receiver> deadReceivers = null;
        
        // Broadcast location or status to all listeners
        final int N = records.size();
        for (int i=0; i<N; i++) {
            UpdateRecord r = records.get(i);
            Receiver receiver = r.mReceiver;

            // Broadcast location only if it is valid
            if (locationValid) {
                HashMap<String,Location> map = mLastFixBroadcast.get(receiver);
                if (map == null) {
                    map = new HashMap<String,Location>();
                    mLastFixBroadcast.put(receiver, map);
                }
                Location lastLoc = map.get(provider);
                if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) {
                    if (lastLoc == null) {
                        lastLoc = new Location(loc);
                        map.put(provider, lastLoc);
                    } else {
                        lastLoc.set(loc);
                    }
                    if (!receiver.callLocationChangedLocked(loc)) {
                        Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
                        if (deadReceivers == null) {
                            deadReceivers = new ArrayList<Receiver>();
                        }
                        deadReceivers.add(receiver);
                    }
                }
            }

            // Broadcast status message
            HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver);
            if (statusMap == null) {
                statusMap = new HashMap<String,Long>();
                mLastStatusBroadcast.put(receiver, statusMap);
            }
            long prevStatusUpdateTime =
                (statusMap.get(provider) != null) ? statusMap.get(provider) : 0;

            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {

                statusMap.put(provider, newStatusUpdateTime);
                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
                    Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
                    if (deadReceivers == null) {
                        deadReceivers = new ArrayList<Receiver>();
                    }
                    if (!deadReceivers.contains(receiver)) {
                        deadReceivers.add(receiver);
                    }
                }
            }
        }
        
        if (deadReceivers != null) {
            for (int i=deadReceivers.size()-1; i>=0; i--) {
                removeUpdatesLocked(deadReceivers.get(i));
            }
        }
    
private booleanisAllowedBySettingsLocked(java.lang.String provider)

        if (mEnabledProviders.contains(provider)) {
            return true;
        }
        if (mDisabledProviders.contains(provider)) {
            return false;
        }
        // Use system settings
        ContentResolver resolver = mContext.getContentResolver();
        String allowedProviders = Settings.Secure.getString(resolver,
           Settings.Secure.LOCATION_PROVIDERS_ALLOWED);

        return ((allowedProviders != null) && (allowedProviders.contains(provider)));
    
private booleanisAllowedProviderSafe(java.lang.String provider)

        if (LocationManager.GPS_PROVIDER.equals(provider)
            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)) {
            return false;
        }
        if (LocationManager.NETWORK_PROVIDER.equals(provider)
            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)
            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED)) {
            return false;
        }

        return true;
    
public booleanisProviderEnabled(java.lang.String provider)

        try {
            synchronized (mLocationListeners) {
                return _isProviderEnabledLocked(provider);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "isProviderEnabled got exception:", e);
            return false;
        }
    
private voidloadProviders()
Load providers from /data/location// class kml nmea track location properties

        synchronized (mLocationListeners) {
            if (sProvidersLoaded) {
                return;
            }

            // Load providers
            loadProvidersLocked();
            sProvidersLoaded = true;
        }
    
private voidloadProvidersLocked()

        try {
            _loadProvidersLocked();
        } catch (Exception e) {
            Log.e(TAG, "Exception loading providers:", e);
        }
    
private voidlog(java.lang.String log)

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.d(TAG, log);
        }
    
private android.location.LocationreadLastKnownLocationLocked(java.lang.String provider)

        Location location = null;
        String s = null;
        try {
            File f = new File(LocationManager.SYSTEM_DIR + "/location."
                    + provider);
            if (!f.exists()) {
                return null;
            }
            BufferedReader reader = new BufferedReader(new FileReader(f), 256);
            s = reader.readLine();
        } catch (IOException e) {
            Log.w(TAG, "Unable to read last known location", e);
        }

        if (s == null) {
            return null;
        }
        try {
            String[] tokens = PATTERN_COMMA.split(s);
            int idx = 0;
            long time = Long.parseLong(tokens[idx++]);
            double latitude = Double.parseDouble(tokens[idx++]);
            double longitude = Double.parseDouble(tokens[idx++]);
            double altitude = Double.parseDouble(tokens[idx++]);
            float bearing = Float.parseFloat(tokens[idx++]);
            float speed = Float.parseFloat(tokens[idx++]);

            location = new Location(provider);
            location.setTime(time);
            location.setLatitude(latitude);
            location.setLongitude(longitude);
            location.setAltitude(altitude);
            location.setBearing(bearing);
            location.setSpeed(speed);
        } catch (NumberFormatException nfe) {
            Log.e(TAG, "NumberFormatException reading last known location", nfe);
            return null;
        }

        return location;
    
private voidreleaseWakeLockLocked()

        try {
            releaseWakeLockXLocked();
        } catch (Exception e) {
            // This is to catch a runtime exception thrown when we try to release an
            // already released lock.
            Log.e(TAG, "exception in releaseWakeLock()", e);
        }
    
private voidreleaseWakeLockXLocked()

        // Release wifi lock
        WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
        if (wifiLock != null) {
            if (mWifiWakeLockAcquired) {
                wifiLock.release();
                mWifiWakeLockAcquired = false;
            }
        }

        if (!mScreenOn) {
            // Stop the gps
            stopGpsLocked();
        }

        // Release cell lock
        if (mCellWakeLockAcquired) {
            mTelephonyManager.disableLocationUpdates();
            mCellWakeLockAcquired = false;
        }

        // Notify NetworkLocationProvider
        if (mNetworkLocationInterface != null) {
            mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
        }

        // Release wake lock
        mWakeLockAcquireTime = 0;
        if (mWakeLock.isHeld()) {
            log("Released wakelock");
            mWakeLock.release();
        } else {
            log("Can't release wakelock again!");
        }
    
public voidremoveGpsStatusListener(android.location.IGpsStatusListener listener)

        synchronized (mLocationListeners) {
            mGpsLocationProvider.removeGpsStatusListener(listener);
        }
    
public voidremoveProximityAlert(android.app.PendingIntent intent)

        try {
            synchronized (mLocationListeners) {
               removeProximityAlertLocked(intent);
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "removeProximityAlert got exception:", e);
        }
    
private voidremoveProximityAlertLocked(android.app.PendingIntent intent)

        if (LOCAL_LOGV) {
            Log.v(TAG, "removeProximityAlert: intent = " + intent);
        }

        mProximityAlerts.remove(intent);
        if (mProximityAlerts.size() == 0) {
            removeUpdatesLocked(mProximityListener);
            mProximityListener = null;
        } else if (mGpsNavigating) {
            updateReportedGpsLocked();
        }
     
public voidremoveTestProvider(java.lang.String provider)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
            if (p == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            LocationProviderImpl.removeProvider(p);
            updateProvidersLocked();
        }
    
public voidremoveUpdates(android.location.ILocationListener listener)

        try {
            synchronized (mLocationListeners) {
                removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid()));
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "removeUpdates got exception:", e);
        }
    
private voidremoveUpdatesLocked(com.android.server.LocationManagerService$Receiver receiver)

        if (LOCAL_LOGV) {
            Log.v(TAG, "_removeUpdates: listener = " + receiver);
        }

        // so wakelock calls will succeed
        final int callingUid = Binder.getCallingUid();
        long identity = Binder.clearCallingIdentity();
        try {
            int idx = mListeners.indexOf(receiver);
            if (idx >= 0) {
                Receiver myReceiver = mListeners.remove(idx);
                if (myReceiver.isListener()) {
                    myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0);
                }
            }

            // Record which providers were associated with this listener
            HashSet<String> providers = new HashSet<String>();
            HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver);
            if (oldRecords != null) {
                // Call dispose() on the obsolete update records.
                for (UpdateRecord record : oldRecords.values()) {
                    if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) {
                        if (mNetworkLocationInterface != null) {
                            mNetworkLocationInterface.removeListener(record.mPackages);
                        }
                    }
                    record.disposeLocked();
                }
                // Accumulate providers
                providers.addAll(oldRecords.keySet());
            }
            
            mLocationListeners.remove(receiver);
            mLastFixBroadcast.remove(receiver);
            mLastStatusBroadcast.remove(receiver);

            // See if the providers associated with this listener have any
            // other listeners; if one does, inform it of the new smallest minTime
            // value; if one does not, disable location tracking for it
            for (String provider : providers) {
                // If provider is already disabled, don't need to do anything
                if (!isAllowedBySettingsLocked(provider)) {
                    continue;
                }

                boolean hasOtherListener = false;
                ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
                if (recordsForProvider != null && recordsForProvider.size() > 0) {
                    hasOtherListener = true;
                }

                LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
                if (p != null) {
                    if (hasOtherListener) {
                        p.setMinTime(getMinTimeLocked(provider));
                    } else {
                        mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
                        p.enableLocationTracking(false);
                    }
                    
                    if (p == mGpsLocationProvider && mGpsNavigating) {
                        updateReportedGpsLocked();
                    }
                }
            }

            updateWakelockStatusLocked(mScreenOn);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    
public voidremoveUpdatesPI(android.app.PendingIntent intent)

        try {
            synchronized (mLocationListeners) {
                removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid()));
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "removeUpdates got exception:", e);
        }
    
private booleanreportGpsUidLocked(int curSeq, int nextSeq, int uid)

        int seq = mReportedGpsUids.get(uid, -1);
        if (seq == curSeq) {
            // Already reported; propagate to next sequence.
            mReportedGpsUids.put(uid, nextSeq);
            return true;
        } else if (seq != nextSeq) {
            try {
                // New UID; report it.
                mBatteryStats.noteStartGps(uid);
                mReportedGpsUids.put(uid, nextSeq);
                return true;
            } catch (RemoteException e) {
            }
        }
        return false;
    
private voidreportStopGpsLocked()

        int curSeq = mReportedGpsSeq;
        for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
            if (mReportedGpsUids.valueAt(i) == curSeq) {
                try {
                    mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
                } catch (RemoteException e) {
                }
            }
        }
        curSeq++;
        if (curSeq < 0) curSeq = 0;
        mReportedGpsSeq = curSeq;
        mReportedGpsUids.clear();
    
public voidrequestLocationUpdates(java.lang.String provider, long minTime, float minDistance, android.location.ILocationListener listener)


        try {
            synchronized (mLocationListeners) {
                requestLocationUpdatesLocked(provider, minTime, minDistance,
                    new Receiver(listener, Binder.getCallingUid()));
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "requestUpdates got exception:", e);
        }
    
private voidrequestLocationUpdatesLocked(java.lang.String provider, long minTime, float minDistance, com.android.server.LocationManagerService$Receiver receiver)

        if (LOCAL_LOGV) {
            Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
        }

        LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
        if (impl == null) {
            throw new IllegalArgumentException("provider=" + provider);
        }

        checkPermissionsSafe(provider);

        String[] packages = getPackageNames();

        // so wakelock calls will succeed
        final int callingUid = Binder.getCallingUid();
        long identity = Binder.clearCallingIdentity();
        try {
            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance,
                    receiver, callingUid, packages);
            if (!mListeners.contains(receiver)) {
                try {
                    if (receiver.isListener()) {
                        receiver.getListener().asBinder().linkToDeath(receiver, 0);
                    }
                    mListeners.add(receiver);
                } catch (RemoteException e) {
                    return;
                }
            }

            HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver);
            if (records == null) {
                records = new HashMap<String,UpdateRecord>();
                mLocationListeners.put(receiver, records);
            }
            UpdateRecord oldRecord = records.put(provider, r);
            if (oldRecord != null) {
                oldRecord.disposeLocked();
            }

            boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
            if (isProviderEnabled) {
                long minTimeForProvider = getMinTimeLocked(provider);
                impl.setMinTime(minTimeForProvider);
                impl.enableLocationTracking(true);
                updateWakelockStatusLocked(mScreenOn);

                if (provider.equals(LocationManager.GPS_PROVIDER)) {
                    if (mGpsNavigating) {
                        updateReportedGpsLocked();
                    }
                }
                
                // Clear heartbeats if any before starting a new one
                mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
                Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
                mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
            } else {
                try {
                    // Notify the listener that updates are currently disabled
                    if (receiver.isListener()) {
                        receiver.getListener().onProviderDisabled(provider);
                    }
                } catch(RemoteException e) {
                    Log.w(TAG, "RemoteException calling onProviderDisabled on " +
                            receiver.getListener());
                }
            }
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    
public voidrequestLocationUpdatesPI(java.lang.String provider, long minTime, float minDistance, android.app.PendingIntent intent)

        try {
            synchronized (mLocationListeners) {
                requestLocationUpdatesLocked(provider, minTime, minDistance,
                        new Receiver(intent, Binder.getCallingUid()));
            }
        } catch (SecurityException se) {
            throw se;
        } catch (Exception e) {
            Log.e(TAG, "requestUpdates got exception:", e);
        }
    
public booleansendExtraCommand(java.lang.String provider, java.lang.String command, android.os.Bundle extras)

        // first check for permission to the provider
        checkPermissionsSafe(provider);
        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
        if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
                != PackageManager.PERMISSION_GRANTED)) {
            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
        }

        synchronized (mLocationListeners) {
            LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
            if (provider == null) {
                return false;
            }
    
            return impl.sendExtraCommand(command, extras);
        }
    
public voidsetInstallCallback(InstallCallback callback)

        synchronized (mLocationListeners) {
            mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
            Message m = Message.obtain(mLocationHandler, 
                    MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
            mLocationHandler.sendMessageAtFrontOfQueue(m);
        }
    
public voidsetLocationCollector(com.android.internal.location.ILocationCollector collector)

        synchronized (mLocationListeners) {
            mCollector = collector;
            if (mGpsLocationProvider != null) {
                mGpsLocationProvider.setLocationCollector(mCollector);
            }
        }
    
public voidsetNetworkLocationProvider(com.android.internal.location.INetworkLocationProvider provider)

        synchronized (mLocationListeners) {
            mNetworkLocationInterface = provider;
            provider.addListener(getPackageNames());
            mNetworkLocationProvider = (LocationProviderImpl)provider;
            LocationProviderImpl.addProvider(mNetworkLocationProvider);
            updateProvidersLocked();
            
            // notify NetworkLocationProvider of any events it might have missed
            synchronized (mLocationListeners) {
                mNetworkLocationProvider.updateNetworkState(mNetworkState);
                mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled);
                mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);

                if (mLastCellState != null) {
                    if (mCollector != null) {
                        mCollector.updateCellState(mLastCellState);
                    }
                    mNetworkLocationProvider.updateCellState(mLastCellState);
                }

                // There might be an existing wifi scan available
                if (mWifiManager != null) {
                    List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
                    if (wifiScanResults != null && wifiScanResults.size() != 0) {
                        mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
                        if (mCollector != null) {
                            mCollector.updateWifiScanResults(wifiScanResults);
                        }
                    }
                }
            }
        }
    
public voidsetTestProviderEnabled(java.lang.String provider, boolean enabled)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            if (enabled) {
                mEnabledProviders.add(provider);
                mDisabledProviders.remove(provider);
            } else {
                mEnabledProviders.remove(provider);
                mDisabledProviders.add(provider);
            }
            updateProvidersLocked();
        }
    
public voidsetTestProviderLocation(java.lang.String provider, android.location.Location loc)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            mMockProviderLocation.put(provider, loc);
        }
    
public voidsetTestProviderStatus(java.lang.String provider, int status, android.os.Bundle extras, long updateTime)

        checkMockPermissionsSafe();
        synchronized (mLocationListeners) {
            if (LocationProviderImpl.getProvider(provider) == null) {
                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
            }
            mMockProviderStatus.put(provider, new Integer(status));
            mMockProviderStatusExtras.put(provider, extras);
            mMockProviderStatusUpdateTime.put(provider, new Long(updateTime));
        }
    
private static booleanshouldBroadcastSafe(android.location.Location loc, android.location.Location lastLoc, com.android.server.LocationManagerService$UpdateRecord record)

        // Always broadcast the first update
        if (lastLoc == null) {
            return true;
        }

        // Don't broadcast same location again regardless of condition
        // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
        if (loc.getTime() == lastLoc.getTime()) {
            return false;
        }

        // Check whether sufficient distance has been traveled
        double minDistance = record.mMinDistance;
        if (minDistance > 0.0) {
            if (loc.distanceTo(lastLoc) <= minDistance) {
                return false;
            }
        }

        return true;
    
private voidstartGpsLocked()

        boolean gpsActive = (mGpsLocationProvider != null)
                    && mGpsLocationProvider.isLocationTracking();
        if (gpsActive) {
            mGpsLocationProvider.startNavigating();
        }
    
private voidstopGpsLocked()

        boolean gpsActive = mGpsLocationProvider != null
                    && mGpsLocationProvider.isLocationTracking();
        if (gpsActive) {
            mGpsLocationProvider.stopNavigating();
        }
    
private voidupdateProviderListenersLocked(java.lang.String provider, boolean enabled)

        int listeners = 0;

        LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
        if (p == null) {
            return;
        }

        ArrayList<Receiver> deadReceivers = null;
        
        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
        if (records != null) {
            final int N = records.size();
            for (int i=0; i<N; i++) {
                UpdateRecord record = records.get(i);
                // Sends a notification message to the receiver
                try {
                    Receiver receiver = record.mReceiver;
                    if (receiver.isListener()) {
                        if (enabled) {
                            receiver.getListener().onProviderEnabled(provider);
                        } else {
                            receiver.getListener().onProviderDisabled(provider);
                        }
                    } else {
                        Intent providerIntent = new Intent();
                        providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
                        try {
                            receiver.getPendingIntent().send(mContext, 0,
                                 providerIntent, null, null);
                        } catch (PendingIntent.CanceledException e) {
                            if (deadReceivers == null) {
                                deadReceivers = new ArrayList<Receiver>();
                                deadReceivers.add(receiver);
                            }
                        }
                    }
                } catch (RemoteException e) {
                    // The death link will clean this up.
                }
                listeners++;
            }
        }

        if (deadReceivers != null) {
            for (int i=deadReceivers.size()-1; i>=0; i--) {
                removeUpdatesLocked(deadReceivers.get(i));
            }
        }
        
        if (enabled) {
            p.enable();
            if (listeners > 0) {
                p.setMinTime(getMinTimeLocked(provider));
                p.enableLocationTracking(true);
                updateWakelockStatusLocked(mScreenOn);
            }
        } else {
            p.enableLocationTracking(false);
            if (p == mGpsLocationProvider) {
                mGpsNavigating = false;
                reportStopGpsLocked();
            }
            p.disable();
            updateWakelockStatusLocked(mScreenOn);
        }

        if (enabled && listeners > 0) {
            mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
            Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
            mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
        } else {
            mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
        }
    
public voidupdateProviders()

        synchronized (mLocationListeners) {
            updateProvidersLocked();
        }
    
private voidupdateProvidersLocked()

        for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
            boolean isEnabled = p.isEnabled();
            String name = p.getName();
            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);

            // Collection is only allowed when network provider is being used
            if (mCollector != null &&
                    p.getName().equals(LocationManager.NETWORK_PROVIDER)) {
                mCollector.updateNetworkProviderStatus(shouldBeEnabled);
            }

            if (isEnabled && !shouldBeEnabled) {
                updateProviderListenersLocked(name, false);
            } else if (!isEnabled && shouldBeEnabled) {
                updateProviderListenersLocked(name, true);
            }

        }
    
private voidupdateReportedGpsLocked()

        if (mGpsLocationProvider == null) {
            return;
        }
        
        final String name = mGpsLocationProvider.getName();
        final int curSeq = mReportedGpsSeq;
        final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0;
        mReportedGpsSeq = nextSeq;
        
        ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name);
        int num = 0;
        final int N = urs.size();
        for (int i=0; i<N; i++) {
            UpdateRecord ur = urs.get(i);
            if (ur.mReceiver == mProximityListener) {
                // We don't want the system to take the blame for this one.
                continue;
            }
            if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) {
                num++;
            }
        }
        
        for (ProximityAlert pe : mProximityAlerts.values()) {
            if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) {
                num++;
            }
        }
        
        if (num != mReportedGpsUids.size()) {
            // The number of uids is processed is different than the
            // array; report any that are no longer active.
            for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
                if (mReportedGpsUids.valueAt(i) != nextSeq) {
                    try {
                        mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
                    } catch (RemoteException e) {
                    }
                    mReportedGpsUids.removeAt(i);
                }
            }
        }
    
private voidupdateWakelockStatusLocked(boolean screenOn)

        log("updateWakelockStatus(): " + screenOn);

        long callerId = Binder.clearCallingIdentity();
        
        boolean needsLock = false;
        long minTime = Integer.MAX_VALUE;

        if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
            needsLock = true;
            minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
        }

        if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
            needsLock = true;
            minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
            if (screenOn) {
                startGpsLocked();
            } else if (mScreenOn && !screenOn) {
                // We just turned the screen off so stop navigating
                stopGpsLocked();
            }
        }

        mScreenOn = screenOn;

        PendingIntent sender =
            PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);

        // Cancel existing alarm
        log("Cancelling existing alarm");
        mAlarmManager.cancel(sender);

        if (needsLock && !mScreenOn) {
            long now = SystemClock.elapsedRealtime();
            mAlarmManager.set(
                AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
            mAlarmInterval = minTime;
            log("Creating a new wakelock alarm with minTime = " + minTime);
        } else {
            log("No need for alarm");
            mAlarmInterval = -1;

            // Clear out existing wakelocks
            mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
            mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
            releaseWakeLockLocked();
        }
        Binder.restoreCallingIdentity(callerId);
    
private voidwriteLastKnownLocationLocked(java.lang.String provider, android.location.Location location)

        long now = SystemClock.elapsedRealtime();
        Long last = mLastWriteTime.get(provider);
        if ((last != null)
            && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
            return;
        }
        mLastWriteTime.put(provider, now);

        StringBuilder sb = new StringBuilder(100);
        sb.append(location.getTime());
        sb.append(',");
        sb.append(location.getLatitude());
        sb.append(',");
        sb.append(location.getLongitude());
        sb.append(',");
        sb.append(location.getAltitude());
        sb.append(',");
        sb.append(location.getBearing());
        sb.append(',");
        sb.append(location.getSpeed());

        FileWriter writer = null;
        try {
            File d = new File(LocationManager.SYSTEM_DIR);
            if (!d.exists()) {
                if (!d.mkdirs()) {
                    Log.w(TAG, "Unable to create directory to write location");
                    return;
                }
            }
            File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
            writer = new FileWriter(f);
            writer.write(sb.toString());
        } catch (IOException e) {
            Log.w(TAG, "Unable to write location", e);
        } finally {
            if (writer != null) {
                try {
                writer.close();
                } catch (IOException e) {
                    Log.w(TAG, "Exception closing file", e);
                }
            }
        }