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

TrackProvider

public class TrackProvider extends android.location.LocationProviderImpl
A dummy provider that returns positions interpolated from a sequence of caller-supplied waypoints. The waypoints are supplied as a String containing one or more numeric quadruples of the form:

The waypoints must be supplied in increasing timestamp order.

The time at which the provider is constructed is considered to be time 0, and further requests for positions will return a position that is linearly interpolated between the waypoints whose timestamps are closest to the amount of wall clock time that has elapsed since time 0.

Following the time of the last waypoint, the position of that waypoint will continue to be returned indefinitely. {@hide}

Fields Summary
static final String
LOG_TAG
private static final long
INTERVAL
private boolean
mEnabled
private double
mLatitude
private double
mLongitude
private boolean
mHasAltitude
private boolean
mHasBearing
private boolean
mHasSpeed
private double
mAltitude
private float
mBearing
private float
mSpeed
private android.os.Bundle
mExtras
private long
mBaseTime
private long
mLastTime
private long
mTime
private long
mMinTime
private long
mMaxTime
private List
mWaypoints
private int
mWaypointIndex
private boolean
mRequiresNetwork
private boolean
mRequiresSatellite
private boolean
mRequiresCell
private boolean
mHasMonetaryCost
private boolean
mSupportsAltitude
private boolean
mSupportsSpeed
private boolean
mSupportsBearing
private boolean
mRepeat
private int
mPowerRequirement
private int
mAccuracy
private float
mTrackSpeed
private android.location.Location
mInitialLocation
Constructors Summary
public TrackProvider(String name, File file)

        this(name);

        String filename = file.getName();
        if (filename.endsWith("kml")) {
            readKml(file);
        } else if (filename.endsWith("nmea")) {
            readNmea(getName(), file);
        } else if (filename.endsWith("track")) {
            readTrack(file);
        } else {
            Log.e(LOG_TAG, "Can't initialize TrackProvider from file " +
                filename + " (not *kml, *nmea, or *track)");
        }
        setTimes();
    
public TrackProvider(String name)

        super(name);
        setTimes();
    
Methods Summary
private static booleanbooleanVal(java.lang.String tf)

        return (tf == null) || (tf.equalsIgnoreCase("true"));
    
private voidclose(java.io.Reader rdr)


        
        try {
            if (rdr != null) {
                rdr.close();
            }
        } catch (IOException e) {
            Log.w(LOG_TAG, "Exception closing reader", e);
        }
    
public voiddisable()

        mEnabled = false;
    
public voidenable()

        mEnabled = true;
    
private static floatfloatVal(java.lang.String val)

        try {
            return (val == null) ? 0 : Float.parseFloat(val);
        } catch (NumberFormatException nfe) {
            return 0.0f;
        }
    
public intgetAccuracy()

        return mAccuracy;
    
public android.location.LocationgetInitialLocation()

        return mInitialLocation;
    
public booleangetLocation(android.location.Location l)

        if (mEnabled) {
            update();
            l.setProvider(getName());
            l.setTime(mTime + mBaseTime);
            l.setLatitude(mLatitude);
            l.setLongitude(mLongitude);
            if (mSupportsAltitude && mHasAltitude) {
                l.setAltitude(mAltitude);
            }
            if (mSupportsBearing && mHasBearing) {
                l.setBearing(mBearing);
            }
            if (mSupportsSpeed && mHasSpeed) {
                l.setSpeed(mSpeed);
            }
            if (mExtras != null) {
                l.setExtras(mExtras);
            }
            return true;
        } else {
            return false;
        }
    
public intgetPowerRequirement()

        return mPowerRequirement;
    
public intgetStatus(android.os.Bundle extras)

        return AVAILABLE;
    
public booleanhasMonetaryCost()

        return mHasMonetaryCost;
    
private static intintVal(java.lang.String val)

        try {
            return (val == null) ? 0 : Integer.parseInt(val);
        } catch (NumberFormatException nfe) {
            return 0;
        }
    
private doubleinterp(double d0, double d1, float frac)

        return d0 + frac * (d1 - d0);
    
public booleanisEnabled()

        return mEnabled;
    
public voidreadKml(java.io.File kmlFile)

        FileReader kmlReader = null;
        try {
            kmlReader = new FileReader(kmlFile);
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xpp = factory.newPullParser();
            xpp.setInput(kmlReader);

            // Concatenate the text of each <coordinates> tag
            boolean inCoordinates = false;
            StringBuilder sb = new StringBuilder();
            int eventType = xpp.getEventType();
            do {
                if (eventType == XmlPullParser.START_DOCUMENT) {
                    // do nothing
                } else if (eventType == XmlPullParser.END_DOCUMENT) {
                    // do nothing
                } else if (eventType == XmlPullParser.START_TAG) {
                    String startTagName = xpp.getName();
                    if (startTagName.equals("coordinates")) {
                        inCoordinates = true;
                    }
                } else if (eventType == XmlPullParser.END_TAG) {
                    String endTagName = xpp.getName();
                    if (endTagName.equals("coordinates")) {
                        inCoordinates = false;
                    }
                } else if (eventType == XmlPullParser.TEXT) {
                    if (inCoordinates) {
                        sb.append(xpp.getText());
                        sb.append(' ");
                    }
                }
                eventType = xpp.next();
            } while (eventType != XmlPullParser.END_DOCUMENT);

            String coordinates = sb.toString();

            // Parse the "lon,lat,alt" triples and supply times
            // for each waypoint based on a constant speed
            Location loc = null;
            double KM_PER_HOUR = mTrackSpeed;
            double KM_PER_METER = 1.0 / 1000.0;
            double MILLIS_PER_HOUR = 60.0 * 60.0 * 1000.0;
            double MILLIS_PER_METER =
                (1.0 / KM_PER_HOUR) * (KM_PER_METER) * (MILLIS_PER_HOUR);
            long time = 0L;

            StringTokenizer st = new StringTokenizer(coordinates, ", ");
            while (st.hasMoreTokens()) {
                try {
                    String lon = st.nextToken();
                    String lat = st.nextToken();
                    String alt = st.nextToken();
                    if (Config.LOGD) {
                        Log.d(LOG_TAG,
                            "lon=" + lon + ", lat=" + lat + ", alt=" + alt);
                    }

                    double nLongitude = Double.parseDouble(lon);
                    double nLatitude = Double.parseDouble(lat);
                    double nAltitude = Double.parseDouble(alt);

                    Location nLoc = new Location(getName());
                    nLoc.setLatitude(nLatitude);
                    nLoc.setLongitude(nLongitude);
                    if (loc != null) {
                        double distance = loc.distanceTo(nLoc);
                        if (Config.LOGD) {
                            Log.d(LOG_TAG, "distance = " + distance);
                        }
                        time += (long) (distance * MILLIS_PER_METER);
                    }

                    Waypoint w = new Waypoint(getName(), time,
                        nLatitude, nLongitude, nAltitude);
                    if (supportsSpeed()) {
                        w.setSpeed(mTrackSpeed);
                    }
                    if (supportsBearing()) {
                        w.setBearing(0.0f);
                    }
                    mWaypoints.add(w);

                    if (mInitialLocation == null) {
                        mInitialLocation = w.getLocation();
                    }

                    loc = nLoc;
                } catch (NumberFormatException nfe) {
                    Log.e(LOG_TAG, "Got NumberFormatException reading KML data: " +
                        nfe, nfe);
                }
            }

            setTimes();
            return;
        } catch (IOException ioe) {
            mWaypoints.clear();
            Log.e(LOG_TAG, "Exception reading KML data: " + ioe, ioe);
            // fall through
        } catch (XmlPullParserException xppe) {
            mWaypoints.clear();
            Log.e(LOG_TAG, "Exception reading KML data: " + xppe, xppe);
            // fall through
        } finally {
            close(kmlReader);
        }
    
public voidreadNmea(java.lang.String name, java.io.File file)

        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(file), 8192);
            String s;

            String provider = getName();
            NmeaParser parser = new NmeaParser(name);
            while ((s = br.readLine()) != null) {
                boolean newWaypoint = parser.parseSentence(s);
                if (newWaypoint) {
                    Location loc = parser.getLocation();
                    Waypoint w = new Waypoint(loc);
                    mWaypoints.add(w);
                    // Log.i(TAG, "Got waypoint " + w);
                }
            }

            setTimes();
            return;
        } catch (IOException ioe) {
            Log.e(LOG_TAG, "Exception reading NMEA data: " + ioe);
            mWaypoints.clear();
        } finally {
            close(br);
        }
    
public voidreadProperties(java.io.File propertiesFile)

        BufferedReader br = null;
        if (!propertiesFile.exists()) {
            return;
        }
        try {
            if (Config.LOGD) {
                Log.d(LOG_TAG, "Loading properties file " +
                    propertiesFile.getPath());
            }
            br = new BufferedReader(new FileReader(propertiesFile), 8192);

            String s;
            while ((s = br.readLine()) != null) {
                StringTokenizer st = new StringTokenizer(s);
                String command = null;
                String value = null;
                if (!st.hasMoreTokens()) {
                    continue;
                }
                command = st.nextToken();
                if (st.hasMoreTokens()) {
                    value = st.nextToken();
                }

                if (command.equalsIgnoreCase("requiresNetwork")) {
                    setRequiresNetwork(booleanVal(value));
                } else if (command.equalsIgnoreCase("requiresSatellite")) {
                    setRequiresSatellite(booleanVal(value));
                } else if (command.equalsIgnoreCase("requiresCell")) {
                    setRequiresCell(booleanVal(value));
                } else if (command.equalsIgnoreCase("hasMonetaryCost")) {
                    setHasMonetaryCost(booleanVal(value));
                } else if (command.equalsIgnoreCase("supportsAltitude")) {
                    setSupportsAltitude(booleanVal(value));
                } else if (command.equalsIgnoreCase("supportsBearing")) {
                    setSupportsBearing(booleanVal(value));
                } else if (command.equalsIgnoreCase("repeat")) {
                    setRepeat(booleanVal(value));
                } else if (command.equalsIgnoreCase("supportsSpeed")) {
                    setSupportsSpeed(booleanVal(value));
                } else if (command.equalsIgnoreCase("powerRequirement")) {
                    setPowerRequirement(intVal(value));
                } else if (command.equalsIgnoreCase("accuracy")) {
                    setAccuracy(intVal(value));
                } else if (command.equalsIgnoreCase("trackspeed")) {
                    setTrackSpeed(floatVal(value));
                } else {
                    Log.e(LOG_TAG, "Unknown command \"" + command + "\"");
                }
            }
        } catch (IOException ioe) {
            Log.e(LOG_TAG, "IOException reading properties file " +
                propertiesFile.getPath(), ioe);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                Log.w(LOG_TAG, "IOException closing properties file " +
                    propertiesFile.getPath(), e);
            }
        }
    
public voidreadTrack(java.io.File trackFile)

        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(trackFile), 8192);
            String s;

            long lastTime = -Long.MAX_VALUE;
            while ((s = br.readLine()) != null) {
                String[] tokens = s.split("\\s+");
                if (tokens.length != 4 && tokens.length != 6) {
                    Log.e(LOG_TAG, "Got track \"" + s +
                        "\", wanted <time> <long> <lat> <alt> [<bearing> <speed>]");
                    continue;
                }
                long time;
                double longitude, latitude, altitude;
                try {
                    time = Long.parseLong(tokens[0]);
                    longitude = Double.parseDouble(tokens[1]);
                    latitude = Double.parseDouble(tokens[2]);
                    altitude = Double.parseDouble(tokens[3]);
                } catch (NumberFormatException e) {
                    Log.e(LOG_TAG, "Got track \"" + s +
                        "\", wanted <time> <long> <lat> <alt> " +
                        "[<bearing> <speed>]", e);
                    continue;
                }

                Waypoint w = new Waypoint(getName(), time, latitude, longitude, altitude);
                if (tokens.length >= 6) {
                    float bearing, speed;
                    try {
                        bearing = Float.parseFloat(tokens[4]);
                        speed = Float.parseFloat(tokens[5]);
                        w.setBearing(bearing);
                        w.setSpeed(speed);
                    } catch (NumberFormatException e) {
                        Log.e(LOG_TAG, "Ignoring bearing and speed \"" +
                            tokens[4] + "\", \"" + tokens[5] + "\"", e);
                    }
                }

                if (mInitialLocation == null) {
                    mInitialLocation = w.getLocation();
                }

                // Ignore waypoints whose time is less than or equal to 0 or
                // the time of the previous waypoint
                if (time < 0) {
                    Log.e(LOG_TAG, "Ignoring waypoint at negative time=" + time);
                    continue;
                }
                if (time <= lastTime) {
                    Log.e(LOG_TAG, "Ignoring waypoint at time=" + time +
                        " (< " + lastTime + ")");
                    continue;
                }

                mWaypoints.add(w);
                lastTime = time;
            }

            setTimes();
            return;
        } catch (IOException e) {
            Log.e(LOG_TAG, "Exception reading track file", e);
            mWaypoints.clear();
        } finally {
            close(br);
        }
    
public booleanrequiresCell()

        return mRequiresCell;
    
public booleanrequiresNetwork()

        return mRequiresNetwork;
    
public booleanrequiresSatellite()

        return mRequiresSatellite;
    
public voidsetAccuracy(int accuracy)

        mAccuracy = accuracy;
    
public voidsetHasMonetaryCost(boolean hasMonetaryCost)

        mHasMonetaryCost = hasMonetaryCost;
    
public voidsetPowerRequirement(int powerRequirement)

        if (powerRequirement < Criteria.POWER_LOW ||
            powerRequirement > Criteria.POWER_HIGH) {
            throw new IllegalArgumentException("powerRequirement = " +
                powerRequirement);
        }
        mPowerRequirement = powerRequirement;
    
public voidsetRepeat(boolean repeat)

        mRepeat = repeat;
    
public voidsetRequiresCell(boolean requiresCell)

        mRequiresCell = requiresCell;
    
public voidsetRequiresNetwork(boolean requiresNetwork)

        mRequiresNetwork = requiresNetwork;
    
public voidsetRequiresSatellite(boolean requiresSatellite)

        mRequiresSatellite = requiresSatellite;
    
public voidsetSupportsAltitude(boolean supportsAltitude)

        mSupportsAltitude = supportsAltitude;
    
public voidsetSupportsBearing(boolean supportsBearing)

        mSupportsBearing = supportsBearing;
    
public voidsetSupportsSpeed(boolean supportsSpeed)

        mSupportsSpeed = supportsSpeed;
    
private voidsetTimes()

        mBaseTime = System.currentTimeMillis();
        if (mWaypoints.size() >= 2) {
            mMinTime = mWaypoints.get(0).getTime();
            mMaxTime = mWaypoints.get(mWaypoints.size() - 1).getTime();
        } else {
            mMinTime = mMaxTime = 0;
        }
    
public voidsetTrackSpeed(float trackSpeed)

        mTrackSpeed = trackSpeed;
    
public booleansupportsAltitude()

        return mSupportsAltitude;
    
public booleansupportsBearing()

        return mSupportsBearing;
    
public booleansupportsSpeed()

        return mSupportsSpeed;
    
private voidupdate()

        // Don't update the position at all unless INTERVAL milliseconds
        // have passed since the last request
        long time = System.currentTimeMillis() - mBaseTime;
        if (time - mLastTime < INTERVAL) {
            return;
        }

        List<Waypoint> waypoints = mWaypoints;
        if (waypoints == null) {
            return;
        }
        int size = waypoints.size();
        if (size < 2) {
            return;
        }

        long t = time;
        if (t < mMinTime) {
            t = mMinTime;
        }
        if (mRepeat) {
            t -= mMinTime;
            long deltaT = mMaxTime - mMinTime;
            t %= 2 * deltaT;
            if (t > deltaT) {
                t = 2 * deltaT - t;
            }
            t += mMinTime;
        } else if (t > mMaxTime) {
            t = mMaxTime;
        }

        // Locate the time interval for the current time
        // We slide the window since we don't expect to move
        // much between calls

        Waypoint w0 = waypoints.get(mWaypointIndex);
        Waypoint w1 = waypoints.get(mWaypointIndex + 1);

        // If the right end of the current interval is too early,
        // move forward to the next waypoint
        while (t > w1.getTime()) {
            w0 = w1;
            w1 = waypoints.get(++mWaypointIndex + 1);
        }
        // If the left end of the current interval is too late,
        // move back to the previous waypoint
        while (t < w0.getTime()) {
            w1 = w0;
            w0 = waypoints.get(--mWaypointIndex);
        }

        // Now we know that w0.mTime <= t <= w1.mTime
        long w0Time = w0.getTime();
        long w1Time = w1.getTime();
        long dt = w1Time - w0Time;

        float frac = (dt == 0) ? 0 : ((float) (t - w0Time) / dt);
        mLatitude  = interp(w0.getLatitude(), w1.getLatitude(), frac);
        mLongitude = interp(w0.getLongitude(), w1.getLongitude(), frac);
        mHasAltitude = w0.hasAltitude() && w1.hasAltitude();
        if (mSupportsAltitude && mHasAltitude) {
            mAltitude  = interp(w0.getAltitude(), w1.getAltitude(), frac);
        }
        if (mSupportsBearing) {
            mHasBearing = frac <= 0.5f ? w0.hasBearing() : w1.hasBearing();
            if (mHasBearing) {
                mBearing  = frac <= 0.5f ? w0.getBearing() : w1.getBearing();
            }
        }
        if (mSupportsSpeed) {
            mHasSpeed = frac <= 0.5f ? w0.hasSpeed() : w1.hasSpeed();
            if (mHasSpeed) {
                mSpeed  = frac <= 0.5f ? w0.getSpeed() : w1.getSpeed();
            }
        }
        mLastTime = time;
        mTime = time;