FileDocCategorySizeDatePackage
GpsLocationProvider.javaAPI DocAndroid 1.5 API36590Wed May 06 22:42:00 BST 2009com.android.internal.location

GpsLocationProvider

public class GpsLocationProvider extends android.location.LocationProviderImpl
A GPS implementation of LocationProvider used by LocationManager. {@hide}

Fields Summary
private static final String
TAG
public static final String
GPS_ENABLED_CHANGE_ACTION
Broadcast intent action indicating that the GPS has either been enabled or disabled. An intent extra provides this state as a boolean, where {@code true} means enabled.
public static final String
GPS_FIX_CHANGE_ACTION
Broadcast intent action indicating that the GPS has either started or stopped receiving GPS fixes. An intent extra provides this state as a boolean, where {@code true} means that the GPS is actively receiving fixes.
public static final String
EXTRA_ENABLED
The lookup key for a boolean that indicates whether GPS is enabled or disabled. {@code true} means GPS is enabled. Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. {@hide}
private static final int
GPS_POSITION_MODE_STANDALONE
private static final int
GPS_POSITION_MODE_MS_BASED
private static final int
GPS_POSITION_MODE_MS_ASSISTED
private static final int
GPS_STATUS_NONE
private static final int
GPS_STATUS_SESSION_BEGIN
private static final int
GPS_STATUS_SESSION_END
private static final int
GPS_STATUS_ENGINE_ON
private static final int
GPS_STATUS_ENGINE_OFF
private static final int
LOCATION_INVALID
private static final int
LOCATION_HAS_LAT_LONG
private static final int
LOCATION_HAS_ALTITUDE
private static final int
LOCATION_HAS_SPEED
private static final int
LOCATION_HAS_BEARING
private static final int
LOCATION_HAS_ACCURACY
private static final int
GPS_DELETE_EPHEMERIS
private static final int
GPS_DELETE_ALMANAC
private static final int
GPS_DELETE_POSITION
private static final int
GPS_DELETE_TIME
private static final int
GPS_DELETE_IONO
private static final int
GPS_DELETE_UTC
private static final int
GPS_DELETE_HEALTH
private static final int
GPS_DELETE_SVDIR
private static final int
GPS_DELETE_SVSTEER
private static final int
GPS_DELETE_SADATA
private static final int
GPS_DELETE_RTI
private static final int
GPS_DELETE_CELLDB_INFO
private static final int
GPS_DELETE_ALL
private static final String
PROPERTIES_FILE
private int
mLocationFlags
private int
mStatus
private long
mStatusUpdateTime
private static final long
RECENT_FIX_TIMEOUT
private boolean
mEnabled
private boolean
mLocationTracking
private boolean
mNetworkAvailable
private boolean
mNavigating
private int
mFixInterval
private int
mPositionMode
private boolean
mStarted
private long
mFixRequestTime
private int
mTTFF
private long
mLastFixTime
private Properties
mProperties
private String
mNtpServer
private android.content.Context
mContext
private android.location.Location
mLocation
private android.os.Bundle
mLocationExtras
private ArrayList
mListeners
private GpsEventThread
mEventThread
private GpsNetworkThread
mNetworkThread
private Object
mNetworkThreadLock
private String
mSuplHost
private int
mSuplPort
private boolean
mSetSuplServer
private static final long
NTP_INTERVAL
private static final long
RETRY_INTERVAL
private ILocationCollector
mCollector
private static final int
MAX_SVS
private static final int
EPHEMERIS_MASK
private static final int
ALMANAC_MASK
private static final int
USED_FOR_FIX_MASK
private int[]
mSvs
private float[]
mSnrs
private float[]
mSvElevations
private float[]
mSvAzimuths
private int[]
mSvMasks
private int
mSvCount
Constructors Summary
public GpsLocationProvider(android.content.Context context)

        super(LocationManager.GPS_PROVIDER);
        mContext = context;

        TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
        context.registerReceiver(receiver, intentFilter);

        mProperties = new Properties();
        try {
            File file = new File(PROPERTIES_FILE);
            FileInputStream stream = new FileInputStream(file);
            mProperties.load(stream);
            stream.close();
            mNtpServer = mProperties.getProperty("NTP_SERVER", null);
            mSuplHost = mProperties.getProperty("SUPL_HOST");
            String suplPortString = mProperties.getProperty("SUPL_PORT");
            if (mSuplHost != null && suplPortString != null) {
                try {
                    mSuplPort = Integer.parseInt(suplPortString);
                    mSetSuplServer = true;
                } catch (NumberFormatException e) {
                    Log.e(TAG, "unable to parse SUPL_PORT: " + suplPortString);
                }
            }
        } catch (IOException e) {
            Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
        }
    
Methods Summary
public voidaddGpsStatusListener(android.location.IGpsStatusListener listener)

        
        if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener");

        synchronized(mListeners) {
            IBinder binder = listener.asBinder();
            int size = mListeners.size();
            for (int i = 0; i < size; i++) {
                Listener test = mListeners.get(i);
                if (binder.equals(test.mListener.asBinder())) {
                    // listener already added
                    return;
                }
            }

            Listener l = new Listener(listener);
            binder.linkToDeath(l, 0);
            mListeners.add(l);
        }
    
private static native voidclass_init_native()

private booleandeleteAidingData(android.os.Bundle extras)

        int flags;

        if (extras == null) {
            flags = GPS_DELETE_ALL;
        } else {
            flags = 0;
            if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
            if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
            if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
            if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
            if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
            if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
            if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
            if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
            if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
            if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
            if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
            if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
            if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
        }

        if (flags != 0) {
            native_delete_aiding_data(flags);
            return true;
        }

        return false;
    
public synchronized voiddisable()
Disables this provider. When disabled, calls to getStatus() and getLocation() need not be handled. Hardware may be shut down while the provider is disabled.

        if (Config.LOGD) Log.d(TAG, "disable");
        if (!mEnabled) return;

        mEnabled = false;
        stopNavigating();
        native_disable();

        // make sure our event thread exits
        if (mEventThread != null) {
            try {
                mEventThread.join();
            } catch (InterruptedException e) {
                Log.w(TAG, "InterruptedException when joining mEventThread");
            }
            mEventThread = null;
        }

        if (mNetworkThread != null) {
            mNetworkThread.setDone();
            mNetworkThread = null;
        }

        native_cleanup();
    
public synchronized voidenable()
Enables this provider. When enabled, calls to getStatus() and getLocation() must be handled. Hardware may be started up when the provider is enabled.

        if (Config.LOGD) Log.d(TAG, "enable");
        if (mEnabled) return;
        mEnabled = native_init();

        if (mEnabled) {
            // run event listener thread while we are enabled
            mEventThread = new GpsEventThread();
            mEventThread.start();

            if (requiresNetwork()) {
                // run network thread for NTP and XTRA support
                if (mNetworkThread == null) {
                    mNetworkThread = new GpsNetworkThread();
                    mNetworkThread.start();
                } else {
                    mNetworkThread.signal();
                }
            }
        } else {
            Log.w(TAG, "Failed to enable location provider");
        }
    
public voidenableLocationTracking(boolean enable)

        if (mLocationTracking == enable) {
            return;
        }

        if (enable) {
            mFixRequestTime = System.currentTimeMillis();
            mTTFF = 0;
            mLastFixTime = 0;
            startNavigating();
        } else {
            stopNavigating();
        }
        mLocationTracking = enable;
    
public intgetAccuracy()
Returns the horizontal accuracy of this provider

return
the accuracy of location from this provider, as one of the constants Criteria.ACCURACY_*.

        return Criteria.ACCURACY_FINE;
    
public booleangetLocation(android.location.Location l)

        synchronized (mLocation) {
            // don't report locations without latitude and longitude
            if ((mLocationFlags & LOCATION_HAS_LAT_LONG) == 0) {
                return false;
            }
            l.set(mLocation);
            l.setExtras(mLocationExtras);
            return true;
        }
    
public intgetPowerRequirement()
Returns the power requirement for this provider.

return
the power requirement for this provider, as one of the constants Criteria.POWER_REQUIREMENT_*.

        return Criteria.POWER_HIGH;
    
public intgetStatus(android.os.Bundle extras)

        if (extras != null) {
            extras.putInt("satellites", mSvCount);
        }
        return mStatus;
    
public longgetStatusUpdateTime()

        return mStatusUpdateTime;
    
public booleanhasMonetaryCost()
Returns true if the use of this provider may result in a monetary charge to the user, false if use is free. It is up to each provider to give accurate information.

        return false;
    
public booleanisEnabled()

        return mEnabled;
    
public booleanisLocationTracking()

        return mLocationTracking;
    
public static booleanisSupported()

        return native_is_supported();
    
private native voidnative_cleanup()

private native voidnative_delete_aiding_data(int flags)

private native voidnative_disable()

private native booleannative_init()

private native voidnative_inject_time(long time, long timeReference, int uncertainty)

private native voidnative_inject_xtra_data(byte[] data, int length)

private static native booleannative_is_supported()

private native intnative_read_sv_status(int[] svs, float[] snrs, float[] elevations, float[] azimuths, int[] masks)

private native voidnative_set_fix_frequency(int fixFrequency)

private native voidnative_set_supl_apn(java.lang.String apn)

private native voidnative_set_supl_server(int addr, int port)

private native booleannative_start(int positionMode, boolean singleFix, int fixInterval)

private native booleannative_stop()

private native booleannative_supports_xtra()

private native voidnative_wait_for_event()

public voidremoveGpsStatusListener(android.location.IGpsStatusListener listener)

        if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener");

        synchronized(mListeners) {        
            IBinder binder = listener.asBinder();
            Listener l = null;
            int size = mListeners.size();
            for (int i = 0; i < size && l == null; i++) {
                Listener test = mListeners.get(i);
                if (binder.equals(test.mListener.asBinder())) {
                    l = test;
                }
            }

            if (l != null) {
                mListeners.remove(l);
                binder.unlinkToDeath(l, 0);
            }
        }
    
private voidreportLocation(int flags, double latitude, double longitude, double altitude, float speed, float bearing, float accuracy, long timestamp)
called from native code to update our position.

        if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
                " timestamp: " + timestamp);

        mLastFixTime = System.currentTimeMillis();
        // report time to first fix
        if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
            mTTFF = (int)(mLastFixTime - mFixRequestTime);
            if (Config.LOGD) Log.d(TAG, "TTFF: " + mTTFF);

            // notify status listeners
            synchronized(mListeners) {
                int size = mListeners.size();
                for (int i = 0; i < size; i++) {
                    Listener listener = mListeners.get(i);
                    try {
                        listener.mListener.onFirstFix(mTTFF); 
                    } catch (RemoteException e) {
                        Log.w(TAG, "RemoteException in stopNavigating");
                        mListeners.remove(listener);
                        // adjust for size of list changing
                        size--;
                    }
                }
            }
        }

        synchronized (mLocation) {
            mLocationFlags = flags;
            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
                mLocation.setLatitude(latitude);
                mLocation.setLongitude(longitude);
                mLocation.setTime(timestamp);
            }
            if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
                mLocation.setAltitude(altitude);
            } else {
                mLocation.removeAltitude();
            }
            if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
                mLocation.setSpeed(speed);
            } else {
                mLocation.removeSpeed();
            }
            if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
                mLocation.setBearing(bearing);
            } else {
                mLocation.removeBearing();
            }
            if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
                mLocation.setAccuracy(accuracy);
            } else {
                mLocation.removeAccuracy();
            }

            // Send to collector
            if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG
                    && mCollector != null) {
                mCollector.updateLocation(mLocation);
            }
        }

        if (mStarted && mStatus != AVAILABLE) {
            // send an intent to notify that the GPS is receiving fixes.
            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
            intent.putExtra(EXTRA_ENABLED, true);
            mContext.sendBroadcast(intent);
            updateStatus(AVAILABLE, mSvCount);
        }
   
private voidreportStatus(int status)
called from native code to update our status

        if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status);

        boolean wasNavigating = mNavigating;
        mNavigating = (status == GPS_STATUS_SESSION_BEGIN);

        if (wasNavigating != mNavigating) {
            synchronized(mListeners) {
                int size = mListeners.size();
                for (int i = 0; i < size; i++) {
                    Listener listener = mListeners.get(i);
                    try {
                        if (mNavigating) {
                            listener.mListener.onGpsStarted(); 
                        } else {
                            listener.mListener.onGpsStopped(); 
                        }
                    } catch (RemoteException e) {
                        Log.w(TAG, "RemoteException in reportStatus");
                        mListeners.remove(listener);
                        // adjust for size of list changing
                        size--;
                    }
                }
            }

            // send an intent to notify that the GPS has been enabled or disabled.
            Intent intent = new Intent(GPS_ENABLED_CHANGE_ACTION);
            intent.putExtra(EXTRA_ENABLED, mNavigating);
            mContext.sendBroadcast(intent);
        }
    
private voidreportSvStatus()
called from native code to update SV info


        int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
        
        synchronized(mListeners) {
            int size = mListeners.size();
            for (int i = 0; i < size; i++) {
                Listener listener = mListeners.get(i);
                try {
                    listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs, 
                            mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK], 
                            mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]); 
                } catch (RemoteException e) {
                    Log.w(TAG, "RemoteException in reportSvInfo");
                    mListeners.remove(listener);
                    // adjust for size of list changing
                    size--;
                }
            }
        }

        if (Config.LOGD) {
            if (Config.LOGV) Log.v(TAG, "SV count: " + svCount +
                    " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
                    " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
            for (int i = 0; i < svCount; i++) {
                if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] +
                        " snr: " + (float)mSnrs[i]/10 +
                        " elev: " + mSvElevations[i] +
                        " azimuth: " + mSvAzimuths[i] +
                        ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " E") +
                        ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "  " : " A") +
                        ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
            }
        }

        updateStatus(mStatus, svCount);

        if (mNavigating && mStatus == AVAILABLE && mLastFixTime > 0 &&
            System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
            // send an intent to notify that the GPS is no longer receiving fixes.
            Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
            intent.putExtra(EXTRA_ENABLED, false);
            mContext.sendBroadcast(intent);
            updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount);
        }
    
public booleanrequiresCell()
Returns true if the provider requires access to an appropriate cellular network (e.g., to make use of cell tower IDs), false otherwise.

        return false;
    
public booleanrequiresNetwork()
Returns true if the provider requires access to a data network (e.g., the Internet), false otherwise.

        // We want updateNetworkState() to get called when the network state changes
        // for XTRA and NTP time injection support.
        return (mNtpServer != null || native_supports_xtra() || mSuplHost != null);
    
public booleanrequiresSatellite()
Returns true if the provider requires access to a satellite-based positioning system (e.g., GPS), false otherwise.

        return true;
    
public booleansendExtraCommand(java.lang.String command, android.os.Bundle extras)

        
        if ("delete_aiding_data".equals(command)) {
            return deleteAidingData(extras);
        }
        
        Log.w(TAG, "sendExtraCommand: unknown command " + command);
        return false;
    
public voidsetLocationCollector(ILocationCollector collector)

        mCollector = collector;
    
public voidsetMinTime(long minTime)

        super.setMinTime(minTime);
        if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime);
        
        if (minTime >= 0) {
            int interval = (int)(minTime/1000);
            if (interval < 1) {
                interval = 1;
            }
            mFixInterval = interval;
            native_set_fix_frequency(mFixInterval);
        }
    
public voidstartNavigating()

        if (!mStarted) {
            if (Config.LOGV) Log.v(TAG, "startNavigating");
            mStarted = true;
            if (!native_start(mPositionMode, false, mFixInterval)) {
                mStarted = false;
                Log.e(TAG, "native_start failed in startNavigating()");
            }

            // reset SV count to zero
            updateStatus(TEMPORARILY_UNAVAILABLE, 0);
        }
    
public voidstopNavigating()

        if (Config.LOGV) Log.v(TAG, "stopNavigating");
        if (mStarted) {
            mStarted = false;
            native_stop();
            mTTFF = 0;
            mLastFixTime = 0;
            mLocationFlags = LOCATION_INVALID;

            // reset SV count to zero
            updateStatus(TEMPORARILY_UNAVAILABLE, 0);
        }
    
public booleansupportsAltitude()
Returns true if the provider is able to provide altitude information, false otherwise. A provider that reports altitude under most circumstances but may occassionally not report it should return true.

        return true;
    
public booleansupportsBearing()
Returns true if the provider is able to provide bearing information, false otherwise. A provider that reports bearing under most circumstances but may occassionally not report it should return true.

        return true;
    
public booleansupportsSpeed()
Returns true if the provider is able to provide speed information, false otherwise. A provider that reports speed under most circumstances but may occassionally not report it should return true.

        return true;
    
public voidupdateNetworkState(int state)

        mNetworkAvailable = (state == LocationProvider.AVAILABLE);

        if (Config.LOGD) {
            Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable"));
        }
        
        if (mNetworkAvailable && mNetworkThread != null && mEnabled) {
            // signal the network thread when the network becomes available
            mNetworkThread.signal();
        } 
    
private voidupdateStatus(int status, int svCount)

        if (status != mStatus || svCount != mSvCount) {
            mStatus = status;
            mSvCount = svCount;
            mLocationExtras.putInt("satellites", svCount);
            mStatusUpdateTime = SystemClock.elapsedRealtime();
        }
    
private voidxtraDownloadRequest()

        if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
        if (mNetworkThread != null) {
            mNetworkThread.xtraDownloadRequest();
        }