ftrimble.kingme.device.file.KingMeGPX.java Source code

Java tutorial

Introduction

Here is the source code for ftrimble.kingme.device.file.KingMeGPX.java

Source

/**
 * Copyright 2013 Forest Trimble
 *
 * Licensed under the Apache Licesnse, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
    
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ftrimble.kingme.device.file;

import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;

import android.text.format.Time;
import android.location.Location;
import android.util.Log;

import org.apache.commons.lang3.StringUtils;

public class KingMeGPX {

    private static final String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
    private static final String ROOT_NODE = "<gpx creator=\"KingMeGPX\" version=\"0.1\" "
            + "xmlns=\"http://www.topografix.com/GPX/1/1\" "
            + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
            + "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 "
            + "http://www.topografix.com/GPX/1/1/gpx.xsd " + "http://www.garmin.com/xmlschemas/GpxExtensions/v3 "
            + "http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd "
            + "http://www.garmin.com/xmlschemas/TrackPointExtension/v1 "
            + "http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd "
            + "http://www.garmin.com/xmlschemas/GpxExtensions/v3 "
            + "http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd "
            + "http://www.garmin.com/xmlschemas/TrackPointExtension/v1 "
            + "http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd\" "
            + "xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\" "
            + "xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\">";

    private final File mFile;
    private final FileWriter mFileWriter;
    private final BufferedWriter mOut;
    private int mIndentLevel;

    public KingMeGPX(File dir, String rideName, Time time) throws IOException {
        mFile = new File(dir, rideName);
        mFileWriter = new FileWriter(mFile);
        mOut = new BufferedWriter(mFileWriter);
        mIndentLevel = 0;

        beginDocument(time, rideName);
    }

    /**
     * Initializes the document data for writing.
     */
    private void beginDocument(Time time, String firstTrackName) {
        try {
            addRootNode();
            addMetaData(time);
            addTrack(firstTrackName);
            addSegment();
        } catch (IOException ioe) {
            Log.d("KingMeGPX", "Could not write to GPX file.");
        }
    }

    /**
     * Closes the document when a course is finished.
     */
    public void endDocument() {
        try {
            endFile();
        } catch (IOException ioe) {
            Log.d("KingMeGPX", "Could not close GPX file.");
        }
    }

    /**
     * Adds the root node and the data accompanying it.
     */
    private void addRootNode() throws IOException {
        StringBuilder sb = new StringBuilder();

        sb.append(XML_VERSION);
        sb.append(addNewLine());
        sb.append(ROOT_NODE);
        ++mIndentLevel;

        mOut.write(sb.toString(), 0, sb.toString().length());
    }

    /**
     * Adds whatever metadata we're given.
     */
    private void addMetaData(Time time) throws IOException {
        StringBuilder sb = new StringBuilder();

        sb.append(addNewLine());

        sb.append("<metadata>");
        ++mIndentLevel;

        sb.append(addNewLine());

        sb.append("<time>");
        sb.append(time.format("%FT%TZ"));
        sb.append("</time>");
        --mIndentLevel;

        sb.append(addNewLine());

        sb.append("</metadata>");

        mOut.write(sb.toString(), 0, sb.toString().length());
    }

    /**
     * This adds a new track; Context.getApplicationContext() is a full course. 
     * In general, we'll only use one for each route on the device.
     */
    private void addTrack(String trackName) throws IOException {
        StringBuilder sb = new StringBuilder();

        sb.append(addNewLine());

        sb.append("<trk>");
        ++mIndentLevel;

        sb.append(addNewLine());

        sb.append("<name>");
        sb.append(trackName);
        sb.append("</name>");

        mOut.write(sb.toString(), 0, sb.toString().length());
    }

    /**
     * This adds a new segment. These might indicate laps. Even better, once our
     * segment handling is sufficiently powerful, we can use them to track the
     * users progress on certain segments.
     */
    public void addSegment() {
        StringBuilder sb = new StringBuilder();

        sb.append(addNewLine());

        sb.append("<trkseg>");
        ++mIndentLevel;

        try {
            mOut.write(sb.toString(), 0, sb.toString().length());
        } catch (IOException ioe) {
            Log.d("KingMeGPX", "Could not write to GPX file.");
        }
    }

    /**
     * Quick helper function to ensure that there is the correct
     * amount of whitespace for the indentation level.
     */
    private String addNewLine() {
        StringBuilder sb = new StringBuilder();
        sb.append("\n");
        sb.append(StringUtils.repeat("  ", mIndentLevel));
        return sb.toString();
    }

    /**
     * Adds data about a specific point in a course.
     */
    public void addPoint(Location location, Time time) {
        if (location == null)
            System.out.println("Received a null location");
        StringBuilder sb = new StringBuilder();

        sb.append(addNewLine());
        sb.append("<trkpt lat=\"");
        sb.append(location.getLatitude());
        sb.append("\" lon=\"");
        sb.append(location.getLongitude());
        sb.append("\">");
        ++mIndentLevel;

        sb.append(addNewLine());

        sb.append("<ele>");
        // TODO calculate location more accurately;
        // perhaps using a web service
        sb.append(location.getAltitude());
        sb.append("</ele>");

        sb.append(addNewLine());

        sb.append("<time>");
        sb.append(time.format("%FT%TZ"));
        sb.append("</time>");
        --mIndentLevel;

        sb.append(addNewLine());

        sb.append("</trkpt>");

        try {
            mOut.write(sb.toString(), 0, sb.toString().length());
        } catch (IOException ioe) {
            Log.d("KingMeGPX", "Could not write to GPX file.");
        }
    }

    /**
     * Terminates a segment; the lap / segment is over.
     */
    public void endSegment() {
        StringBuilder sb = new StringBuilder();
        --mIndentLevel;

        sb.append(addNewLine());
        sb.append("</trkseg>");

        try {
            mOut.write(sb.toString(), 0, sb.toString().length());
        } catch (IOException ioe) {
            Log.d("KingMeGPX", "Could not write to GPX file.");
        }
    }

    /**
     * Finishes the course; ends the segment and the root node
     * and closes the file.
     */
    private void endFile() throws IOException {
        StringBuilder sb = new StringBuilder();
        endSegment();
        --mIndentLevel;

        sb.append(addNewLine());
        sb.append("</trk>");
        --mIndentLevel;

        sb.append(addNewLine());
        sb.append("</gpx>");

        mOut.write(sb.toString(), 0, sb.toString().length());
        mOut.close();
    }

}