/* * This file is part of GPSLogger for Android. * * GPSLogger for Android is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * GPSLogger for Android is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GPSLogger for Android. If not, see <http://www.gnu.org/licenses/>. */ package com.mendhak.gpslogger.loggers; import android.location.Location; import com.mendhak.gpslogger.common.RejectionHandler; import com.mendhak.gpslogger.common.Utilities; import java.io.*; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; class Gpx10FileLogger implements ILogger { protected final static Object lock = new Object(); private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(128), new RejectionHandler()); private File gpxFile = null; private boolean useSatelliteTime = false; private final boolean addNewTrackSegment; private final int satelliteCount; protected final String name = "GPX"; private String user; Gpx10FileLogger(String user,File gpxFile, boolean useSatelliteTime, boolean addNewTrackSegment, int satelliteCount) { this.gpxFile = gpxFile; this.user = user; this.useSatelliteTime = useSatelliteTime; this.addNewTrackSegment = addNewTrackSegment; this.satelliteCount = satelliteCount; } public void write(Location loc) throws Exception { Date now; if (useSatelliteTime) { now = new Date(loc.getTime()); } else { now = new Date(); } String dateTimeString = Utilities.GetIsoDateTime(now); Gpx10WriteHandler writeHandler = new Gpx10WriteHandler(user,dateTimeString, gpxFile, loc, addNewTrackSegment, satelliteCount); Utilities.LogDebug(String.format("There are currently %s tasks waiting on the GPX10 EXECUTOR.", EXECUTOR.getQueue().size())); EXECUTOR.execute(writeHandler); } public void annotate(String description, Location loc) throws Exception { Date now; if (useSatelliteTime) { now = new Date(loc.getTime()); } else { now = new Date(); } String dateTimeString = Utilities.GetIsoDateTime(now); Gpx10AnnotateHandler annotateHandler = new Gpx10AnnotateHandler(description, gpxFile, loc, dateTimeString); Utilities.LogDebug(String.format("There are currently %s tasks waiting on the GPX10 EXECUTOR.", EXECUTOR.getQueue().size())); EXECUTOR.execute(annotateHandler); } // @Override public String getName() { return name; } public void annotate(String name, String description, Location loc) throws Exception { Date now; if (useSatelliteTime) { now = new Date(loc.getTime()); } else { now = new Date(); } String dateTimeString = Utilities.GetIsoDateTime(now); Gpx10AnnotateHandler annotateHandler = new Gpx10AnnotateHandler(name,description, gpxFile, loc, dateTimeString); Utilities.LogDebug(String.format("There are currently %s tasks waiting on the GPX10 EXECUTOR.", EXECUTOR.getQueue().size())); EXECUTOR.execute(annotateHandler); } } class Gpx10AnnotateHandler implements Runnable { String description; File gpxFile; Location loc; String dateTimeString; String name = null; public Gpx10AnnotateHandler(String description, File gpxFile, Location loc, String dateTimeString) { this.description = description; this.gpxFile = gpxFile; this.loc = loc; this.dateTimeString = dateTimeString; } public Gpx10AnnotateHandler(String name,String description, File gpxFile, Location loc, String dateTimeString) { this.name = name; this.description = description; this.gpxFile = gpxFile; this.loc = loc; this.dateTimeString = dateTimeString; } // @Override public void run() { synchronized (Gpx10FileLogger.lock) { if (!gpxFile.exists()) { return; } if (!gpxFile.exists()) { return; } int startPosition = 346; String wpt = ""; if(name==null || name==""){ wpt = GetWaypointXml(loc, dateTimeString, description); } else{ wpt = GetWaypointXml(loc, dateTimeString, name, description); } try { //Write to a temp file, delete original file, move temp to original File gpxTempFile = new File(gpxFile.getAbsolutePath() + ".tmp"); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(gpxFile)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(gpxTempFile)); int written = 0; int readSize; byte[] buffer = new byte[startPosition]; while ((readSize = bis.read(buffer)) > 0) { bos.write(buffer, 0, readSize); written += readSize; System.out.println(written); if (written == startPosition) { bos.write(wpt.getBytes()); buffer = new byte[20480]; } } bis.close(); bos.close(); gpxFile.delete(); gpxTempFile.renameTo(gpxFile); Utilities.LogDebug("Finished annotation to GPX10 File"); } catch (Exception e) { Utilities.LogError("Gpx10FileLogger.Annotate", e); } } } private String GetWaypointXml(Location loc, String dateTimeString, String description) { StringBuilder waypoint = new StringBuilder(); waypoint.append("\n<wpt lat=\"") .append(String.valueOf(loc.getLatitude())) .append("\" lon=\"") .append(String.valueOf(loc.getLongitude())) .append("\">"); if (loc.hasAltitude()) { waypoint.append("<ele>").append(String.valueOf(loc.getAltitude())).append("</ele>"); } if (loc.hasBearing()) { waypoint.append("<course>").append(String.valueOf(loc.getBearing())).append("</course>"); } if (loc.hasSpeed()) { waypoint.append("<speed>").append(String.valueOf(loc.getSpeed())).append("</speed>"); } waypoint.append("<name>").append(description).append("</name>"); waypoint.append("<src>").append(loc.getProvider()).append("</src>"); waypoint.append("<time>").append(dateTimeString).append("</time>"); waypoint.append("</wpt>\n"); return waypoint.toString(); } private String GetWaypointXml(Location loc, String dateTimeString,String descriptionName, String description) { StringBuilder waypoint = new StringBuilder(); waypoint.append("\n<wpt lat=\"") .append(String.valueOf(loc.getLatitude())) .append("\" lon=\"") .append(String.valueOf(loc.getLongitude())) .append("\">"); if (loc.hasAltitude()) { waypoint.append("<ele>").append(String.valueOf(loc.getAltitude())).append("</ele>"); } if (loc.hasBearing()) { waypoint.append("<course>").append(String.valueOf(loc.getBearing())).append("</course>"); } if (loc.hasSpeed()) { waypoint.append("<speed>").append(String.valueOf(loc.getSpeed())).append("</speed>"); } waypoint.append("<").append(descriptionName).append(">").append(description).append("</").append(descriptionName).append(">"); waypoint.append("<src>").append(loc.getProvider()).append("</src>"); waypoint.append("<time>").append(dateTimeString).append("</time>"); waypoint.append("</wpt>\n"); return waypoint.toString(); } } class Gpx10WriteHandler implements Runnable { String dateTimeString; Location loc; private File gpxFile = null; private boolean addNewTrackSegment; private int satelliteCount; private String user; public Gpx10WriteHandler(String user,String dateTimeString, File gpxFile, Location loc, boolean addNewTrackSegment, int satelliteCount) { this.dateTimeString = dateTimeString; this.user = user; this.addNewTrackSegment = addNewTrackSegment; this.gpxFile = gpxFile; this.loc = loc; this.satelliteCount = satelliteCount; } // @Override public void run() { synchronized (Gpx10FileLogger.lock) { try { if (!gpxFile.exists()) { gpxFile.createNewFile(); FileOutputStream initialWriter = new FileOutputStream(gpxFile, true); BufferedOutputStream initialOutput = new BufferedOutputStream(initialWriter); StringBuilder initialXml = new StringBuilder(); initialXml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); initialXml.append("<gpx version=\"1.0\" creator=\"GPSLogger - http://gpslogger.mendhak.com/\" "); initialXml.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "); initialXml.append("xmlns=\"http://www.topografix.com/GPX/1/0\" "); initialXml.append("xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 "); initialXml.append("http://www.topografix.com/GPX/1/0/gpx.xsd\">"); initialXml.append("<user>").append(user).append("</user>"); initialXml.append("<time>").append(dateTimeString).append("</time>").append("<bounds />").append("<trk></trk></gpx>"); initialOutput.write(initialXml.toString().getBytes()); initialOutput.flush(); initialOutput.close(); //New file, so new segment. addNewTrackSegment = true; } int offsetFromEnd = (addNewTrackSegment) ? 12 : 21; long startPosition = gpxFile.length() - offsetFromEnd; String trackPoint = GetTrackPointXml(loc, dateTimeString); RandomAccessFile raf = new RandomAccessFile(gpxFile, "rw"); raf.seek(startPosition); raf.write(trackPoint.getBytes()); raf.close(); Utilities.LogDebug("Finished writing to GPX10 file"); } catch (Exception e) { Utilities.LogError("Gpx10FileLogger.Write", e); } } } private String GetTrackPointXml(Location loc, String dateTimeString) { StringBuilder track = new StringBuilder(); if (addNewTrackSegment) { track.append("<trkseg>"); } track.append("<trkpt lat=\"") .append(String.valueOf(loc.getLatitude())) .append("\" lon=\"") .append(String.valueOf(loc.getLongitude())) .append("\">"); if (loc.hasAltitude()) { track.append("<ele>").append(String.valueOf(loc.getAltitude())).append("</ele>"); } if (loc.hasBearing()) { track.append("<course>").append(String.valueOf(loc.getBearing())).append("</course>"); } if (loc.hasSpeed()) { track.append("<speed>").append(String.valueOf(loc.getSpeed())).append("</speed>"); } if (loc.hasAccuracy() && loc.getAccuracy() > 0) { // Accuracy divided by 5 or 6 for approximate HDOP track.append("<hdop>").append(String.valueOf(loc.getAccuracy() / 5)).append("</hdop>"); } track.append("<src>").append(loc.getProvider()).append("</src>"); if (satelliteCount > 0) { track.append("<sat>").append(String.valueOf(satelliteCount)).append("</sat>"); } track.append("<time>").append(dateTimeString).append("</time>"); track.append("</trkpt>\n"); track.append("</trkseg></trk></gpx>"); return track.toString(); } }