Extendable File Format

All file formats to be extended

Also fixed a bug in the display of values
This commit is contained in:
Chet Henry
2014-12-06 00:16:00 -07:00
parent 54c4cd6daa
commit 1efecf1705
11 changed files with 315 additions and 280 deletions

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -7,17 +7,17 @@
android:versionCode="040000"
android:versionName="4.0.0"
android:icon="@drawable/ic_launcher" >
<uses-sdk android:minSdkVersion="14"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-sdk android:minSdkVersion="14"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light">
android:theme="@android:style/Theme.DeviceDefault.Light" >
<service
android:name="com.ridelogger.RideService"
android:icon="@drawable/ic_launcher"

View File

@@ -11,5 +11,5 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library.reference.1=../AntPluginLib
target=android-21
min=android-14

View File

@@ -80,6 +80,7 @@ public class CurrentValuesAdapter extends BaseAdapter {
}
layout.setAdapter(CurrentValuesAdapter.this);
notifyDataSetChanged();
} else if (pkey == context.getString(R.string.PREF_TRACKING_IMPERIAL_UNITS)) {
imperial = sharedPreferences.getBoolean(pkey, false);

View File

@@ -10,6 +10,19 @@ public class GzipWriter extends GZIPOutputStream {
}
public void write(String data) throws IOException {
write(data.getBytes());
super.write(data.getBytes());
}
public void write(float data) throws IOException {
super.write(Float.floatToIntBits(data));
}
public void write(CharSequence data) throws IOException {
byte[] barr = new byte[data.length()];
for (int i = 0; i < barr.length; i++) {
barr[i] = (byte) data.charAt(i);
}
super.write(barr);
}
}

View File

@@ -1,15 +1,8 @@
package com.ridelogger;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import java.util.Timer;
@@ -19,6 +12,8 @@ import com.dsi.ant.plugins.antplus.pcc.defines.DeviceType;
import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult;
import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch;
import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch.MultiDeviceSearchResult;
import com.ridelogger.formats.BaseFormat;
import com.ridelogger.formats.JsonFormat;
import com.ridelogger.listners.Base;
import com.ridelogger.listners.Gps;
import com.ridelogger.listners.HeartRate;
@@ -107,56 +102,20 @@ public class RideService extends Service
"press",
"lux"
};
public float[] currentValues = new float[RideService.KEYS.length]; //float array of current values
public GzipWriter buf; //writes to log file buffered
public long startTime; //start time of the ride
private boolean rideStarted = false; //have we started logging the ride
private Set<String> pairedAnts; //list of ant devices to pair with
private Timer timer; //timer class to control the periodic messages
private Timer timerUI; //timer class to control the periodic messages
private String emergencyNumbuer; //the number to send the messages to
private Base<?>[] sensors;
private int sensor_index = 0;
MultiDeviceSearch mSearch; //Ant+ device search class to init connections
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
Messenger replyTo;
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
@Override
public void handleMessage(Message msg) {
if(timerUI != null) {
timerUI.cancel();
timerUI = null;
}
timerUI = new Timer();
if(msg.replyTo != null) {
replyTo = msg.replyTo;
timerUI.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
Message msg = Message.obtain(null, 2, 0, 0);
Bundle bundle = new Bundle();
bundle.putSerializable("currentValues", currentValues);
msg.setData(bundle);
try {
replyTo.send(msg);
} catch (RemoteException e) { }
}
},
1000,
1000
); //every second update the screen
}
}
}
public GzipWriter buf; //writes to log file buffered
public long startTime; //start time of the ride
public float[] currentValues = new float[RideService.KEYS.length]; //float array of current values
private Messenger mMessenger = null; //class to send back current values if needed
private boolean rideStarted = false; //have we started logging the ride
private int sensor_index = 0; //current index of sensors
private String emergencyNumbuer; //the number to send the messages to
private MultiDeviceSearch mSearch; //Ant+ device search class to init connections
private Timer timer; //timer class to control the periodic messages
private Timer timerUI; //timer class to control the periodic messages
private Base<?>[] sensors; //list of sensors tracking
public BaseFormat<?> fileFormat;
/**
* starts the ride on service start
@@ -173,6 +132,39 @@ public class RideService extends Service
*/
@Override
public IBinder onBind(Intent arg0) {
mMessenger = new Messenger(new Handler() { // Handler of incoming messages from clients.
Messenger replyTo;
@Override
public void handleMessage(Message msg) {
if(timerUI != null) {
timerUI.cancel();
timerUI = null;
}
timerUI = new Timer();
if(msg.replyTo != null) {
replyTo = msg.replyTo;
timerUI.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
Message msg = Message.obtain(null, 2, 0, 0);
Bundle bundle = new Bundle();
bundle.putSerializable("currentValues", currentValues);
msg.setData(bundle);
try {
replyTo.send(msg);
} catch (RemoteException e) {}
}
},
1000,
1000
); //every second update the screen
}
}
}); // Target we publish for clients to send messages to IncomingHandler.
return mMessenger.getBinder();
}
@@ -187,6 +179,8 @@ public class RideService extends Service
timerUI = null;
}
mMessenger = null;
return true;
}
@@ -206,116 +200,76 @@ public class RideService extends Service
protected void startRide() {
if(rideStarted) return;
startTime = System.currentTimeMillis();
final String fileName = "ride-" + startTime + ".json.gz";
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
emergencyNumbuer = settings.getString(getString(R.string.PREF_EMERGENCY_NUMBER), "");
currentValues[SECS] = (float) 0.0;
SimpleDateFormat f = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
startTime = System.currentTimeMillis();
String utc = f.format(new Date(startTime));
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(startTime);
Date startDate = new Date(startTime);
String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US);
String weekDay = cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US);
String year = Integer.toString(cal.get(Calendar.YEAR));
SimpleDateFormat startTimef = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
SimpleDateFormat month = new SimpleDateFormat("MMMMM");
SimpleDateFormat year = new SimpleDateFormat("yyyy");
SimpleDateFormat day = new SimpleDateFormat("EEEEE");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
emergencyNumbuer = settings.getString(getString(R.string.PREF_EMERGENCY_NUMBER), "");
pairedAnts = settings.getStringSet(getString(R.string.PREF_PAIRED_ANTS), null);
currentValues[SECS] = (float) 0.0;
startTimef.setTimeZone(TimeZone.getTimeZone("UTC"));
filef.setTimeZone(TimeZone.getTimeZone("UTC"));
month.setTimeZone(TimeZone.getTimeZone("UTC"));
year.setTimeZone(TimeZone.getTimeZone("UTC"));
day.setTimeZone(TimeZone.getTimeZone("UTC"));
String rideHeadder = "{" +
"\"RIDE\":{" +
"\"STARTTIME\":\"" + utc + " UTC\"," +
"\"RECINTSECS\":1," +
"\"DEVICETYPE\":\"Android\"," +
"\"IDENTIFIER\":\"\"," +
"\"TAGS\":{" +
"\"Athlete\":\"" + settings.getString(getString(R.string.PREF_RIDER_NAME), "") + "\"," +
"\"Calendar Text\":\"Auto Recored Android Ride\"," +
"\"Change History\":\"\"," +
"\"Data\":\"\"," +
"\"Device\":\"\"," +
"\"Device Info\":\"\"," +
"\"File Format\":\"\"," +
"\"Filename\":\"\"," +
"\"Month\":\"" + month +"\"," +
"\"Notes\":\"\"," +
"\"Objective\":\"\"," +
"\"Sport\":\"Bike\"," +
"\"Weekday\":\"" + weekDay + "\"," +
"\"Workout Code\":\"\"," +
"\"Year\":\"" + year + "\"" +
"}," +
"\"SAMPLES\":[{\"SECS\":0}";
final String fileName = filef.format(startDate) + ".json.gz";
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File dir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS
),
"Rides"
);
fileFormat = new JsonFormat(this);
fileFormat.createFile();
fileFormat.writeHeader();
File file = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOCUMENTS
) + "/Rides",
fileName
);
final Set<String> pairedAnts = settings.getStringSet(getString(R.string.PREF_PAIRED_ANTS), null);
if(pairedAnts != null) {
sensors = new Base<?>[pairedAnts.size() + 2];
} else {
sensors = new Base<?>[2];
}
sensors[sensor_index++] = new Gps(this);
sensors[sensor_index++] = new Sensors(this);
try {
dir.mkdirs();
file.createNewFile();
file.setReadable(true);
file.setWritable(true);
OutputStream bufWriter = new BufferedOutputStream(new FileOutputStream(file));
buf = new GzipWriter(bufWriter);
buf.write(rideHeadder);
if(pairedAnts != null) {
sensors = new Base<?>[pairedAnts.size() + 2];
} else {
sensors = new Base<?>[2];
}
sensors[sensor_index++] = new Gps(this);
sensors[sensor_index++] = new Sensors(this);
if(pairedAnts != null && !pairedAnts.isEmpty()){
MultiDeviceSearch.SearchCallbacks mCallback = new MultiDeviceSearch.SearchCallbacks(){
public void onDeviceFound(final MultiDeviceSearchResult deviceFound)
{
if (!deviceFound.isAlreadyConnected()) {
if(pairedAnts == null || pairedAnts.contains(Integer.toString(deviceFound.getAntDeviceNumber()))) {
launchConnection(deviceFound);
if(pairedAnts != null && !pairedAnts.isEmpty()){
// start the multi-device search
mSearch = new MultiDeviceSearch(
this,
EnumSet.allOf(DeviceType.class),
new MultiDeviceSearch.SearchCallbacks() {
public void onDeviceFound(final MultiDeviceSearchResult deviceFound)
{
if (!deviceFound.isAlreadyConnected()) {
if(pairedAnts == null || pairedAnts.contains(Integer.toString(deviceFound.getAntDeviceNumber()))) {
launchConnection(deviceFound);
pairedAnts.remove(Integer.toString(deviceFound.getAntDeviceNumber()));
}
}
if(pairedAnts.isEmpty()) {
mSearch.close();
mSearch = null;
}
}
@Override
public void onSearchStopped(RequestAccessResult arg0) {
mSearch = null;
}
},
new MultiDeviceSearch.RssiCallback() {
@Override
public void onRssiUpdate(final int resultId, final int rssi){}
}
@Override
public void onSearchStopped(RequestAccessResult arg0) {
mSearch = null;
}
};
MultiDeviceSearch.RssiCallback mRssiCallback = new MultiDeviceSearch.RssiCallback() {
@Override
public void onRssiUpdate(final int resultId, final int rssi){}
};
// start the multi-device search
mSearch = new MultiDeviceSearch(this, EnumSet.allOf(DeviceType.class), mCallback, mRssiCallback);
}
} catch (IOException e) {}
);
}
}
rideStarted = true;
@@ -428,7 +382,10 @@ public class RideService extends Service
protected void stopRide() {
if(!rideStarted) return;
phoneStop();
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
if(settings.getBoolean(getString(R.string.PREF_PHONE_HOME), false)) {
phoneStop();
}
for(Base<?> sensor: sensors) {
if(sensor != null) {
@@ -452,10 +409,7 @@ public class RideService extends Service
timerUI = null;
}
try {
buf.write("]}}");
buf.close();
} catch (IOException e) {}
fileFormat.writeFooter();
rideStarted = false;
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

View File

@@ -24,7 +24,7 @@ public class StartActivity extends FragmentActivity
private MenuItem stopMenu;
private ServiceConnection mConnection;
CurrentValuesAdapter currentValuesAdapter;
static CurrentValuesAdapter currentValuesAdapter;
@Override
@@ -106,6 +106,13 @@ public class StartActivity extends FragmentActivity
finish();
}
static final Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg_internal) {
updateValues(msg_internal.getData());
}
};
/**
* tell the service to start sending us messages with current values
@@ -119,12 +126,7 @@ public class StartActivity extends FragmentActivity
Messenger mService = new Messenger(service);
try {
Message msg = Message.obtain();
msg.replyTo = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg_internal) {
updateValues(msg_internal.getData());
}
});
msg.replyTo = new Messenger(mHandler);
mService.send(msg);
} catch (RemoteException e) {
@@ -156,7 +158,7 @@ public class StartActivity extends FragmentActivity
* update the text fields with current values
* @param bundle
*/
private void updateValues(Bundle bundle) {
private static void updateValues(Bundle bundle) {
currentValuesAdapter.update((float[]) bundle.getSerializable("currentValues"));
}

View File

@@ -0,0 +1,71 @@
package com.ridelogger.formats;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.os.Environment;
import com.ridelogger.GzipWriter;
import com.ridelogger.RideService;
public class BaseFormat<T> {
protected GzipWriter buf;
protected RideService context;
protected String subExt = "";
public BaseFormat(RideService rideService) {
context = rideService;
}
public void createFile() {
File dir = new File(
Environment.getExternalStorageDirectory(),
"Rides"
);
dir.mkdirs();
Date startDate = new Date(context.startTime);
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String fileName = filef.format(startDate) + subExt + ".gz";
try {
buf = new GzipWriter(new BufferedOutputStream(new FileOutputStream(new File(dir, fileName))));
} catch (Exception e) {}
}
public void writeHeader(){
try {
synchronized (buf) {
for(CharSequence key : RideService.KEYS) {
buf.write(key);
buf.write(",");
}
}
} catch (Exception e) {}
}
public void writeValues() {
try {
synchronized (buf) {
for(float value : context.currentValues) {
buf.write(value);
}
}
} catch (Exception e) {}
}
public void writeFooter() {
try {
buf.close();
} catch (Exception e) {}
}
}

View File

@@ -0,0 +1,93 @@
package com.ridelogger.formats;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import com.ridelogger.R;
import com.ridelogger.RideService;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
public class JsonFormat extends BaseFormat<Object> {
public JsonFormat(RideService rideService) {
super(rideService);
subExt = ".json";
}
public void writeHeader() {
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
Date startDate = new Date(context.startTime);
SimpleDateFormat startTimef = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat filef = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
SimpleDateFormat month = new SimpleDateFormat("MMMMM");
SimpleDateFormat year = new SimpleDateFormat("yyyy");
SimpleDateFormat day = new SimpleDateFormat("EEEEE");
startTimef.setTimeZone(TimeZone.getTimeZone("UTC"));
filef.setTimeZone(TimeZone.getTimeZone("UTC"));
month.setTimeZone(TimeZone.getTimeZone("UTC"));
year.setTimeZone(TimeZone.getTimeZone("UTC"));
day.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
buf.write("{" +
"\"RIDE\":{" +
"\"STARTTIME\":\"" + startTimef.format(startDate) + " UTC\"," +
"\"RECINTSECS\":1," +
"\"DEVICETYPE\":\"Android\"," +
"\"IDENTIFIER\":\"\"," +
"\"TAGS\":{" +
"\"Athlete\":\"" + settings.getString(context.getString(R.string.PREF_RIDER_NAME), "") + "\"," +
"\"Calendar Text\":\"Auto Recored Android Ride\"," +
"\"Change History\":\"\"," +
"\"Data\":\"\"," +
"\"Device\":\"\"," +
"\"Device Info\":\"\"," +
"\"File Format\":\"\"," +
"\"Filename\":\"\"," +
"\"Month\":\"" + month.format(startDate) +"\"," +
"\"Notes\":\"\"," +
"\"Objective\":\"\"," +
"\"Sport\":\"Bike\"," +
"\"Weekday\":\"" + day.format(startDate) + "\"," +
"\"Workout Code\":\"\"," +
"\"Year\":\"" + year.format(startDate) + "\"" +
"}," +
"\"SAMPLES\":[{\"SECS\":0}");
} catch (Exception e) {}
}
public void writeValues() {
try {
synchronized (buf) {
buf.write(",{");
buf.write("\"");
buf.write(RideService.KEYS[0]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[0]));
for (int i = 1; i < context.currentValues.length; i++) {
buf.write(",\"");
buf.write(RideService.KEYS[i]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[i]));
}
buf.write("}");
}
} catch (Exception e) {}
}
public void writeFooter() {
try {
buf.write("]}}");
} catch (Exception e) {}
super.writeFooter();
}
}

View File

@@ -44,19 +44,6 @@ public class Ant extends Base<Object>
releaseHandle.close();
}
}
@Override
public void writeData(int key, float value)
{
super.writeData(key, value);
}
@Override
public void writeData(int[] keys, float[] values)
{
super.writeData(keys, values);
}
@Override

View File

@@ -1,81 +1,18 @@
package com.ridelogger.listners;
import com.ridelogger.GzipWriter;
import com.ridelogger.RideService;
import java.io.IOException;
/**
* Base
* @author Chet Henry
* Base sensor class that has methods to time stamp are write to buffer
*/
public class Base<T>
{
public GzipWriter buf;
public long startTime;
{
public RideService context;
public Base(RideService mContext) {
context = mContext;
buf = context.buf; //shared file buffer object
}
public void writeData(int key, float value)
{
if(context.currentValues[key] != value) {
context.currentValues[RideService.SECS] = getTs();
context.currentValues[key] = value;
try {
synchronized (buf) {
buf.write(",{");
buf.write("\"");
buf.write((String) RideService.KEYS[RideService.SECS]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[RideService.SECS]));
buf.write(",\"");
buf.write((String) RideService.KEYS[key]);
buf.write("\":");
buf.write(String.format("%f", value));
buf.write("}");
}
} catch (IOException e) {}
}
}
public void writeData(int[] keys, float[] values)
{
context.currentValues[RideService.SECS] = getTs();
try {
synchronized (buf) {
buf.write(",{");
buf.write("\"");
buf.write((String) RideService.KEYS[RideService.SECS]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[RideService.SECS]));
int i = 0;
for (int key : keys) {
context.currentValues[key] = values[i];
buf.write(",\"");
buf.write((String) RideService.KEYS[key]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[i]));
i++;
}
buf.write("}");
}
} catch (IOException e) {}
}
@@ -84,7 +21,7 @@ public class Base<T>
synchronized (context.currentValues) {
context.currentValues[RideService.SECS] = getTs();
context.currentValues[key] = value;
writeCurrentData();
context.fileFormat.writeValues();
}
}
@@ -100,34 +37,11 @@ public class Base<T>
i++;
}
writeCurrentData();
context.fileFormat.writeValues();
}
}
public void writeCurrentData()
{
try {
synchronized (buf) {
buf.write(",{");
buf.write("\"");
buf.write((String) RideService.KEYS[0]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[0]));
for (int i = 1; i < context.currentValues.length; i++) {
buf.write(",\"");
buf.write((String) RideService.KEYS[i]);
buf.write("\":");
buf.write(String.format("%f", context.currentValues[i]));
}
buf.write("}");
}
} catch (IOException e) {}
}
//get current time stamp
public float getTs() {
return (float) ((System.currentTimeMillis() - context.startTime) / 1000.0);