package com.openxc.sinks; import java.io.BufferedWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; import android.util.Log; import com.openxc.messages.VehicleMessage; import com.openxc.messages.formatters.JsonFormatter; import com.openxc.util.FileOpener; /** * Record raw vehicle messages to a file as JSON. * * This data sink is a simple passthrough that records every raw vehicle * message as it arrives to a file on the device. It uses a heuristic to * detect different "trips" in the vehicle, and splits the recorded trace by * trip. * * The heuristic is very simple: if we haven't received any new data in a while, * consider the previous trip to have ended. When activity resumes, start a new * trip. */ public class FileRecorderSink implements VehicleDataSink { private final static String TAG = "FileRecorderSink"; private final static int INTER_TRIP_THRESHOLD_MINUTES = 5; private static SimpleDateFormat sDateFormatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US); private FileOpener mFileOpener; private BufferedWriter mWriter; private Calendar mLastMessageReceived; public FileRecorderSink(FileOpener fileOpener) { mFileOpener = fileOpener; } @Override public synchronized void receive(VehicleMessage message) throws DataSinkException { if(mLastMessageReceived == null || Calendar.getInstance().getTimeInMillis() - mLastMessageReceived.getTimeInMillis() > INTER_TRIP_THRESHOLD_MINUTES * 60 * 1000) { Log.i(TAG, "Detected a new trip, splitting recorded trace file"); try { openTimestampedFile(); } catch(IOException e) { throw new DataSinkException( "Unable to open file for recording", e); } } if(mWriter == null) { throw new DataSinkException( "No valid writer - not recording trace line"); } mLastMessageReceived = Calendar.getInstance(); try { mWriter.write(JsonFormatter.serialize(message)); mWriter.newLine(); } catch(IOException e) { throw new DataSinkException("Unable to write message to file"); } } @Override public synchronized void stop() { close(); Log.i(TAG, "Shutting down"); } public synchronized void flush() { if(mWriter != null) { try { mWriter.flush(); } catch(IOException e) { Log.w(TAG, "Unable to flush writer", e); } } } private synchronized void close() { if(mWriter != null) { try { mWriter.close(); } catch(IOException e) { Log.w(TAG, "Unable to close output file", e); } mWriter = null; } } private synchronized void openTimestampedFile() throws IOException { Calendar calendar = Calendar.getInstance(); String filename = sDateFormatter.format( calendar.getTime()) + ".json"; if(mWriter != null) { close(); } mWriter = mFileOpener.openForWriting(filename); Log.i(TAG, "Opened trace file " + filename + " for writing"); } }