diff --git a/contrib/RideLogger/.classpath b/contrib/RideLogger/.classpath new file mode 100644 index 000000000..51769745b --- /dev/null +++ b/contrib/RideLogger/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/contrib/RideLogger/.gitignore b/contrib/RideLogger/.gitignore new file mode 100644 index 000000000..f6da3b79e --- /dev/null +++ b/contrib/RideLogger/.gitignore @@ -0,0 +1,12 @@ +# Ignores for Eclipse +/.settings/ + +# Ignores for Android Projects +/bin/ +/gen/ +/publish/ +/local.properties +/secure.properties + +# Ignores for Mac machines +.DS_Store diff --git a/contrib/RideLogger/AndroidManifest.xml b/contrib/RideLogger/AndroidManifest.xml new file mode 100644 index 000000000..0ee61ea2d --- /dev/null +++ b/contrib/RideLogger/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/RideLogger/assets/WorkoutRepeatSteps.fit b/contrib/RideLogger/assets/WorkoutRepeatSteps.fit new file mode 100644 index 000000000..0dbe51a0e Binary files /dev/null and b/contrib/RideLogger/assets/WorkoutRepeatSteps.fit differ diff --git a/contrib/RideLogger/ic_launcher-web.png b/contrib/RideLogger/ic_launcher-web.png new file mode 100644 index 000000000..2988fc3a5 Binary files /dev/null and b/contrib/RideLogger/ic_launcher-web.png differ diff --git a/contrib/RideLogger/libs/android-support-v4.jar b/contrib/RideLogger/libs/android-support-v4.jar new file mode 100644 index 000000000..6080877d4 Binary files /dev/null and b/contrib/RideLogger/libs/android-support-v4.jar differ diff --git a/contrib/RideLogger/libs/antpluginlib_3-1-0.jar b/contrib/RideLogger/libs/antpluginlib_3-1-0.jar new file mode 100644 index 000000000..ce1d421f0 Binary files /dev/null and b/contrib/RideLogger/libs/antpluginlib_3-1-0.jar differ diff --git a/contrib/RideLogger/libs/fit_12.00.jar b/contrib/RideLogger/libs/fit_12.00.jar new file mode 100644 index 000000000..7aa581756 Binary files /dev/null and b/contrib/RideLogger/libs/fit_12.00.jar differ diff --git a/contrib/RideLogger/lint.xml b/contrib/RideLogger/lint.xml new file mode 100644 index 000000000..ee0eead5b --- /dev/null +++ b/contrib/RideLogger/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/contrib/RideLogger/project.properties b/contrib/RideLogger/project.properties new file mode 100644 index 000000000..2e18f6073 --- /dev/null +++ b/contrib/RideLogger/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-19 +android.library.reference.1=../AntPluginLib diff --git a/contrib/RideLogger/res/drawable-hdpi/ic_launcher.png b/contrib/RideLogger/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..feb241fa8 Binary files /dev/null and b/contrib/RideLogger/res/drawable-hdpi/ic_launcher.png differ diff --git a/contrib/RideLogger/res/drawable-ldpi/ic_launcher.png b/contrib/RideLogger/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 000000000..1857ef3b2 Binary files /dev/null and b/contrib/RideLogger/res/drawable-ldpi/ic_launcher.png differ diff --git a/contrib/RideLogger/res/drawable-mdpi/ic_launcher.png b/contrib/RideLogger/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..747f16cb4 Binary files /dev/null and b/contrib/RideLogger/res/drawable-mdpi/ic_launcher.png differ diff --git a/contrib/RideLogger/res/drawable-xhdpi/ic_launcher.png b/contrib/RideLogger/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..f21ee6fa8 Binary files /dev/null and b/contrib/RideLogger/res/drawable-xhdpi/ic_launcher.png differ diff --git a/contrib/RideLogger/res/layout/activity_dashboard.xml b/contrib/RideLogger/res/layout/activity_dashboard.xml new file mode 100644 index 000000000..ddc243ebd --- /dev/null +++ b/contrib/RideLogger/res/layout/activity_dashboard.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/contrib/RideLogger/res/values/strings.xml b/contrib/RideLogger/res/values/strings.xml new file mode 100644 index 000000000..c56f9d469 --- /dev/null +++ b/contrib/RideLogger/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + Ride Logger + Logging Ride + \ No newline at end of file diff --git a/contrib/RideLogger/src/com/ridelogger/RideService.java b/contrib/RideLogger/src/com/ridelogger/RideService.java new file mode 100644 index 000000000..9aa5b2a30 --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/RideService.java @@ -0,0 +1,366 @@ +package com.ridelogger; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; + +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.R; +import com.ridelogger.listners.Gps; +import com.ridelogger.listners.HeartRate; +import com.ridelogger.listners.Power; +import com.ridelogger.listners.Sensors; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.app.TaskStackBuilder; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Environment; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; + +public class RideService extends Service +{ + public static BufferedWriter buf; + public static long start_time; + public static Map current_values; + public boolean rideStarted = false; + + public static HeartRate hr; + public static Power w; + public static Gps gps; + public static Sensors sensors; + + MultiDeviceSearch mSearch; + MultiDeviceSearch.SearchCallbacks mCallback; + MultiDeviceSearch.RssiCallback mRssiCallback; + + public int notifyID = 1; + NotificationManager mNotificationManager; + + public String file_name = ""; + SharedPreferences settings; + + /** + * + * @return BufferedWriter + */ + public static BufferedWriter getBuf() { + return buf; + } + + /** + * + * @return start_time + */ + public static long getStartTime() { + return start_time; + } + + + /** + * + * @return start_time + */ + public static Map getCurrentValues() { + return current_values; + } + + + /** + * + * @return w + */ + public static Power getPower() { + return w; + } + + /** + * + * @return w + */ + public static void setPower(Power pw) { + w = pw; + if(w == null) { + w = pw; + } + } + + /** + * + * @return hr + */ + public static HeartRate getHeartRate() { + return hr; + } + + + public static void setHeartRate(HeartRate phr) { + if(hr == null) { + hr = phr; + } + } + + + public static void setGps(Gps pgps) { + if(gps == null) { + gps = pgps; + } + } + + public static Gps getGps() { + return gps; + } + + + public static void setSensors(Sensors psens) { + if(sensors == null) { + sensors = psens; + } + } + + public static Sensors getSensors() { + return sensors; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + startRide(); + return Service.START_NOT_STICKY; + } + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + public boolean onUnbind (Intent intent) { + return true; + } + + @Override + public void onDestroy() { + stopRide(); + super.onDestroy(); + } + + protected void startRide() { + if(rideStarted) return; + + start_time = System.currentTimeMillis(); + file_name = "ride-" + start_time + ".json"; + + current_values = new HashMap(); + + SimpleDateFormat f = new SimpleDateFormat("yyyy/MMM/dd HH:mm:ss"); + f.setTimeZone(TimeZone.getTimeZone("UTC")); + String utc = f.format(new Date(start_time)); + + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(start_time); + + String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US); + String week_day = cal.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.US); + String year = Integer.toString(cal.get(Calendar.YEAR)); + settings = getSharedPreferences(StartActivity.PREFS_NAME, 0); + String rider_name = settings.getString(StartActivity.RIDER_NAME, ""); + final Set pairedAnts = settings.getStringSet(StartActivity.PAIRED_ANTS, null); + + + current_values.put("SECS", "0.0"); + + String rideHeadder = "{" + + "\"RIDE\":{" + + "\"STARTTIME\":\"" + utc + " UTC\"," + + "\"RECINTSECS\":1," + + "\"DEVICETYPE\":\"Android\"," + + "\"IDENTIFIER\":\"\"," + + "\"TAGS\":{" + + "\"Athlete\":\"" + rider_name + "\"," + + "\"Calendar Text\":\"Auto Recored Android Ride\"," + + "\"Change History\":\"\"," + + "\"Data\":\"\"," + + "\"Device\":\"\"," + + "\"Device Info\":\"\"," + + "\"File Format\":\"\"," + + "\"Filename\":\"\"," + + "\"Month\":\"" + month +"\"," + + "\"Notes\":\"\"," + + "\"Objective\":\"\"," + + "\"Sport\":\"Bike\"," + + "\"Weekday\":\"" + week_day + "\"," + + "\"Workout Code\":\"\"," + + "\"Year\":\"" + year + "\"" + + "}," + + "\"SAMPLES\":[{\"SECS\":0}"; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + File dir = new File( + Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOCUMENTS + ), + "Rides" + ); + + File file = new File( + Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOCUMENTS + ) + "/Rides", + "ride-" + start_time + ".json" + ); + + try { + dir.mkdirs(); + file.createNewFile(); + buf = new BufferedWriter(new FileWriter(file, true)); + buf.write(rideHeadder); + + if(gps == null) { + gps = new Gps(this); + } + + if(sensors == null) { + sensors = new Sensors(this); + } + + mCallback = new MultiDeviceSearch.SearchCallbacks(){ + public void onDeviceFound(final MultiDeviceSearchResult deviceFound) + { + if (!deviceFound.isAlreadyConnected() && (pairedAnts == null || pairedAnts.contains(Integer.toString(deviceFound.getAntDeviceNumber())))) { + launchConnection(deviceFound); + } + } + + @Override + public void onSearchStopped(RequestAccessResult arg0) {} + }; + + 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; + + + NotificationCompat.Builder mBuilder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_launcher) + .setContentTitle("Ride On") + .setContentText("Building ride: " + file_name + " Click to stop ride."); + mBuilder.setProgress(0, 0, true); + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(this, StartActivity.class); + + // The stack builder object will contain an artificial back stack for the + // started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(StartActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + mBuilder.setContentIntent(resultPendingIntent); + if(mNotificationManager == null) { + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + + startForeground(notifyID, mBuilder.build()); + } + + + protected void stopRide() { + if(!rideStarted) return; + + if(w != null) { + w.onDestroy(); + } + + if(hr != null) { + hr.onDestroy(); + } + + if(gps != null) { + gps.onDestroy(); + } + + if(sensors != null) { + sensors.onDestroy(); + } + + mSearch.close(); + + try { + buf.write("]}}"); + buf.close(); + } catch (IOException e) {} + + rideStarted = false; + mNotificationManager.cancel(notifyID); + } + + + public void launchConnection(MultiDeviceSearchResult result) + { + switch (result.getAntDeviceType()) + { + case BIKE_CADENCE: + break; + case BIKE_POWER: + if(w == null) { + w = new Power(result, this); + } + break; + case BIKE_SPD: + break; + case BIKE_SPDCAD: + break; + case BLOOD_PRESSURE: + break; + case ENVIRONMENT: + break; + case WEIGHT_SCALE: + break; + case HEARTRATE: + if(hr == null) { + hr = new HeartRate(result, this); + } + break; + case STRIDE_SDM: + break; + case FITNESS_EQUIPMENT: + break; + case GEOCACHE: + case CONTROLLABLE_DEVICE: + break; + case UNKNOWN: + break; + default: + break; + } + } +} + + diff --git a/contrib/RideLogger/src/com/ridelogger/StartActivity.java b/contrib/RideLogger/src/com/ridelogger/StartActivity.java new file mode 100644 index 000000000..97172b317 --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/StartActivity.java @@ -0,0 +1,196 @@ +package com.ridelogger; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; + +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 android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.text.InputType; +import android.widget.EditText; +import android.widget.Toast; + +public class StartActivity extends FragmentActivity +{ + Intent rsi; + public static final String PREFS_NAME = "RideLogger"; + public static final String RIDER_NAME = "RiderName"; + public static final String PAIRED_ANTS = "PairedAnts"; + SharedPreferences settings; + AlertDialog dialog; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + rsi = new Intent(this, RideService.class); + + settings = getSharedPreferences(PREFS_NAME, 0); + String rider_name = settings.getString(RIDER_NAME, ""); + + if(rider_name == "") { + // 1. Instantiate an AlertDialog.Builder with its constructor + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + // 2. Chain together various setter methods to set the dialog characteristics + builder.setMessage("What is your Golder Cheata Rider Name") + .setTitle("Chose Rider Name"); + + // Set up the input + final EditText input = new EditText(this); + // Specify the type of input expected; this, for example, sets the input as a password, and will mask the text + input.setInputType(InputType.TYPE_CLASS_TEXT); + builder.setView(input); + + + builder.setPositiveButton("Set", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String name = input.getText().toString(); + if(name != "" && name != null) { + SharedPreferences.Editor editor = settings.edit(); + editor.putString(RIDER_NAME, name); + editor.commit(); + setupAnt(); + } + } + }); + + // 3. Get the AlertDialog from create() + dialog = builder.create(); + dialog.show(); + } else { + toggleRide(); + finish(); + } + } + + protected void setupAnt() { + + MultiDeviceSearch mSearch; + MultiDeviceSearch.SearchCallbacks mCallback; + MultiDeviceSearch.RssiCallback mRssiCallback; + final ArrayList foundDevices = new ArrayList(); + mCallback = new MultiDeviceSearch.SearchCallbacks(){ + public void onDeviceFound(final MultiDeviceSearchResult deviceFound) + { + if(!foundDevices.contains(deviceFound)) { + foundDevices.add(deviceFound); + selectDevicesDialog(foundDevices); + } + } + + @Override + public void onSearchStopped(RequestAccessResult arg0) {} + }; + + 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); + } + + protected void selectDevicesDialog(final ArrayList foundDevices) { + final ArrayList mSelectedItems = new ArrayList(); // Where we track the selected items + final ArrayList foundDevicesString = new ArrayList(); + + for(MultiDeviceSearchResult device : foundDevices) { + foundDevicesString.add(device.getAntDeviceType() + " - " + device.getDeviceDisplayName()); + } + CharSequence[] foundDevicesCharSeq = foundDevicesString.toArray(new CharSequence[foundDevicesString.size()]); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + // Set the dialog title + builder.setTitle("Select Paired Ant Devices") + // Specify the list array, the items to be selected by default (null for none), + // and the listener through which to receive callbacks when items are selected + .setMultiChoiceItems(foundDevicesCharSeq, null, new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + if (isChecked) { + // If the user checked the item, add it to the selected items + mSelectedItems.add(which); + } else if (mSelectedItems.contains(which)) { + // Else, if the item is already in the array, remove it + mSelectedItems.remove(Integer.valueOf(which)); + } + } + }) + // Set the action buttons + .setPositiveButton("Pair", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + ArrayList ids = new ArrayList(); + for(Integer index : mSelectedItems) { + ids.add(Integer.toString(foundDevices.get(index).getAntDeviceNumber())); + } + + SharedPreferences.Editor editor = settings.edit(); + editor.putStringSet(PAIRED_ANTS, new HashSet(ids)); + editor.commit(); + toggleRide(); + finish(); + } + }); + + dialog = builder.create(); + dialog.show(); + } + + @Override + protected void onDestroy() { + // TODO Auto-generated method stub + super.onDestroy(); + } + + + private void stopRide() { + Toast toast = Toast.makeText(getApplicationContext(), "Stoping Ride!", Toast.LENGTH_LONG); + toast.show(); + this.stopService(rsi); + } + + + protected void toggleRide() { + if(!isServiceRunning(RideService.class)) { + startRide(); + } else { + stopRide(); + } + } + + + private void startRide() { + if(!isServiceRunning(RideService.class)) { + this.startService(rsi); + } + Toast toast = Toast.makeText(getApplicationContext(), "Starting Ride!", Toast.LENGTH_LONG); + toast.show(); + } + + + private boolean isServiceRunning(Class serviceClass) { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (serviceClass.getName().equals(service.service.getClassName())) { + return true; + } + } + return false; + } +} diff --git a/contrib/RideLogger/src/com/ridelogger/listners/Base.java b/contrib/RideLogger/src/com/ridelogger/listners/Base.java new file mode 100644 index 000000000..0f9476f98 --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/listners/Base.java @@ -0,0 +1,114 @@ +package com.ridelogger.listners; + +import android.content.Context; + +import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState; +import com.dsi.ant.plugins.antplus.pccbase.PccReleaseHandle; +import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IDeviceStateChangeReceiver; +import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver; +import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch.MultiDeviceSearchResult; +import com.ridelogger.RideService; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.Map; + +/** + * Base class to connects to Heart Rate Plugin and display all the event data. + */ +public class Base +{ + public static BufferedWriter buf; + public static long start_time; + public static Map current_values; + public PccReleaseHandle releaseHandle; + public Context context; + + public Base(MultiDeviceSearchResult result, Context mContext) { + init(mContext); + } + + public Base(Context mContext) { + init(mContext); + } + + public void init(Context mContext) { + buf = RideService.getBuf(); + start_time = RideService.getStartTime(); + current_values = RideService.getCurrentValues(); + context = mContext; + } + + IDeviceStateChangeReceiver mDeviceStateChangeReceiver = new IDeviceStateChangeReceiver() { + @Override + public void onDeviceStateChange(final DeviceState newDeviceState){} + }; + + public IPluginAccessResultReceiver mResultReceiver; + + public void writeData(String key, String value) + { + if(!current_values.containsKey(key) || current_values.get(key) != value) { + String ts = String.valueOf((double) (System.currentTimeMillis() - start_time) / 1000.0); + current_values.put("SECS", ts); + current_values.put(key, value); + + try { + buf.write(",{"); + + buf.write("\""); + buf.write("SECS"); + buf.write("\":"); + buf.write(ts); + + buf.write(",\""); + buf.write(key); + buf.write("\":"); + buf.write(value); + + buf.write("}"); + } catch (IOException e) {} + } + } + + + public void writeData(Map map) + { + String ts = String.valueOf((double) (System.currentTimeMillis() - start_time) / 1000.0); + current_values.put("SECS", ts); + + try { + buf.write(",{"); + + buf.write("\""); + buf.write("SECS"); + buf.write("\":"); + buf.write(ts); + + for (Map.Entry entry : map.entrySet()) + { + String key = entry.getKey(); + String value = entry.getValue(); + + buf.write(",\""); + buf.write(key); + buf.write("\":"); + buf.write(value); + + current_values.put(key, value); + } + + buf.write("}"); + } catch (IOException e) {} + } + + + public void onDestroy() + { + if(releaseHandle != null) { + releaseHandle.close(); + } + } +} + + diff --git a/contrib/RideLogger/src/com/ridelogger/listners/Gps.java b/contrib/RideLogger/src/com/ridelogger/listners/Gps.java new file mode 100644 index 000000000..c86ddc27d --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/listners/Gps.java @@ -0,0 +1,45 @@ +package com.ridelogger.listners; + +import java.util.HashMap; +import java.util.Map; + +import android.content.Context; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; + +public class Gps extends Base +{ + public Gps(Context mContext) + { + super(mContext); + + LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + + + LocationListener locationListener = new LocationListener() { + public void onLocationChanged(Location location) { + Map map = new HashMap(); + map.put("ALTITUDE", Double.toString(location.getAltitude()) ); + map.put("KPH", Float.toString( location.getSpeed()) ); + map.put("bearing", Float.toString( location.getBearing()) ); + map.put("gpsa", Float.toString( location.getAccuracy()) ); + map.put("LAT", Double.toString(location.getLatitude()) ); + map.put("LON", Double.toString(location.getLongitude())); + writeData(map); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) {} + + @Override + public void onProviderEnabled(String provider) {} + + @Override + public void onProviderDisabled(String provider) {} + }; + + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); + } +} \ No newline at end of file diff --git a/contrib/RideLogger/src/com/ridelogger/listners/HeartRate.java b/contrib/RideLogger/src/com/ridelogger/listners/HeartRate.java new file mode 100644 index 000000000..b91152d0e --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/listners/HeartRate.java @@ -0,0 +1,44 @@ +package com.ridelogger.listners; + +import android.content.Context; + +import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc; +import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc.DataState; +import com.dsi.ant.plugins.antplus.pcc.AntPlusHeartRatePcc.IHeartRateDataReceiver; +import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState; +import com.dsi.ant.plugins.antplus.pcc.defines.EventFlag; +import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult; +import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver; +import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch.MultiDeviceSearchResult; + +import java.math.BigDecimal; +import java.util.EnumSet; + +/** + * Base class to connects to Heart Rate Plugin and display all the event data. + */ +public class HeartRate extends Base +{ + public HeartRate(MultiDeviceSearchResult result, Context mContext) { + super(result, mContext); + releaseHandle = AntPlusHeartRatePcc.requestAccess(context, result.getAntDeviceNumber(), 0, mResultReceiver, mDeviceStateChangeReceiver); + } + + public IPluginAccessResultReceiver mResultReceiver = new IPluginAccessResultReceiver() { + //Handle the result, connecting to events on success or reporting failure to user. + @Override + public void onResultReceived(AntPlusHeartRatePcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) + { + if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SUCCESS) { + result.subscribeHeartRateDataEvent( + new IHeartRateDataReceiver() { + @Override + public void onNewHeartRateData(final long estTimestamp, EnumSet eventFlags, final int computedHeartRate, final long heartBeatCount, final BigDecimal heartBeatEventTime, final DataState dataState) { + writeData("HR", String.valueOf(computedHeartRate)); + } + } + ); + } + } + }; +} \ No newline at end of file diff --git a/contrib/RideLogger/src/com/ridelogger/listners/Power.java b/contrib/RideLogger/src/com/ridelogger/listners/Power.java new file mode 100644 index 000000000..5a2971a72 --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/listners/Power.java @@ -0,0 +1,183 @@ +package com.ridelogger.listners; + +import android.content.Context; + +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.CalculatedWheelDistanceReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.CalculatedWheelSpeedReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.DataSource; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedCrankCadenceReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedPowerReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ICalculatedTorqueReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IInstantaneousCadenceReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IPedalPowerBalanceReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IPedalSmoothnessReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IRawCrankTorqueDataReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IRawPowerOnlyDataReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.IRawWheelTorqueDataReceiver; +import com.dsi.ant.plugins.antplus.pcc.AntPlusBikePowerPcc.ITorqueEffectivenessReceiver; +import com.dsi.ant.plugins.antplus.pcc.defines.DeviceState; +import com.dsi.ant.plugins.antplus.pcc.defines.EventFlag; +import com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult; +import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IDeviceStateChangeReceiver; +import com.dsi.ant.plugins.antplus.pccbase.AntPluginPcc.IPluginAccessResultReceiver; +import com.dsi.ant.plugins.antplus.pccbase.MultiDeviceSearch.MultiDeviceSearchResult; + +import java.math.BigDecimal; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +/** + * Base class to connects to Heart Rate Plugin and display all the event data. + */ +public class Power extends Base +{ + + public Power(MultiDeviceSearchResult result, Context mContext) { + super(result, mContext); + releaseHandle = AntPlusBikePowerPcc.requestAccess(context, result.getAntDeviceNumber(), 0, mResultReceiver, mDeviceStateChangeReceiver); + } + + BigDecimal wheelCircumferenceInMeters = new BigDecimal("2.07"); + + IDeviceStateChangeReceiver mDeviceStateChangeReceiver = new IDeviceStateChangeReceiver() + { + @Override + public void onDeviceStateChange(final DeviceState newDeviceState){} + }; + + + protected IPluginAccessResultReceiver mResultReceiver = new IPluginAccessResultReceiver() { + //Handle the result, connecting to events on success or reporting failure to user. + @Override + public void onResultReceived(AntPlusBikePowerPcc result, RequestAccessResult resultCode, DeviceState initialDeviceState) + { + if(resultCode == com.dsi.ant.plugins.antplus.pcc.defines.RequestAccessResult.SUCCESS) { + result.subscribeCalculatedPowerEvent(new ICalculatedPowerReceiver() { + @Override + public void onNewCalculatedPower(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final BigDecimal calculatedPower) { + writeData("WATTS", String.format("%.1f", calculatedPower)); + } + } + ); + + result.subscribeCalculatedTorqueEvent( + new ICalculatedTorqueReceiver() { + @Override + public void onNewCalculatedTorque(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final BigDecimal calculatedTorque) { + writeData("NM", String.format("%.1f", calculatedTorque)); + } + } + ); + + result.subscribeCalculatedCrankCadenceEvent( + new ICalculatedCrankCadenceReceiver() { + @Override + public void onNewCalculatedCrankCadence(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final BigDecimal calculatedCrankCadence) { + writeData("RPM", String.format("%.1f", calculatedCrankCadence)); + } + } + ); + + result.subscribeCalculatedWheelSpeedEvent( + new CalculatedWheelSpeedReceiver(wheelCircumferenceInMeters) { + @Override + public void onNewCalculatedWheelSpeed(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final BigDecimal calculatedWheelSpeed) + { + writeData("KMH", String.format("%.1f", calculatedWheelSpeed)); + } + } + ); + + result.subscribeCalculatedWheelDistanceEvent( + new CalculatedWheelDistanceReceiver(wheelCircumferenceInMeters) { + @Override + public void onNewCalculatedWheelDistance(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final BigDecimal calculatedWheelDistance) + { + writeData("KM", String.format("%.1f", calculatedWheelDistance)); + } + } + ); + + result.subscribeInstantaneousCadenceEvent( + new IInstantaneousCadenceReceiver() { + @Override + public void onNewInstantaneousCadence(final long estTimestamp, final EnumSet eventFlags, final DataSource dataSource, final int instantaneousCadence) + { + writeData("RPM", String.format("%d", instantaneousCadence)); + } + } + ); + + result.subscribeRawPowerOnlyDataEvent( + new IRawPowerOnlyDataReceiver() { + @Override + public void onNewRawPowerOnlyData(final long estTimestamp, final EnumSet eventFlags, final long powerOnlyUpdateEventCount, final int instantaneousPower, final long accumulatedPower) + { + writeData("WATTS", String.format("%d", instantaneousPower)); + } + } + ); + + result.subscribePedalPowerBalanceEvent( + new IPedalPowerBalanceReceiver() { + @Override + public void onNewPedalPowerBalance(final long estTimestamp, final EnumSet eventFlags, final boolean rightPedalIndicator, final int pedalPowerPercentage) + { + writeData("LTE", String.format("%d", pedalPowerPercentage)); + } + } + ); + + result.subscribeRawWheelTorqueDataEvent( + new IRawWheelTorqueDataReceiver() { + @Override + public void onNewRawWheelTorqueData(final long estTimestamp, final EnumSet eventFlags, final long wheelTorqueUpdateEventCount, final long accumulatedWheelTicks, final BigDecimal accumulatedWheelPeriod, final BigDecimal accumulatedWheelTorque) + { + writeData("NM", String.format("%.1f", accumulatedWheelTorque)); + } + } + ); + + result.subscribeRawCrankTorqueDataEvent( + new IRawCrankTorqueDataReceiver() { + @Override + public void onNewRawCrankTorqueData(final long estTimestamp, final EnumSet eventFlags, final long crankTorqueUpdateEventCount, final long accumulatedCrankTicks, final BigDecimal accumulatedCrankPeriod, final BigDecimal accumulatedCrankTorque) + { + writeData("NM", String.format("%.1f", accumulatedCrankTorque)); + } + } + ); + + result.subscribeTorqueEffectivenessEvent( + new ITorqueEffectivenessReceiver() { + @Override + public void onNewTorqueEffectiveness(final long estTimestamp, final EnumSet eventFlags, final long powerOnlyUpdateEventCount, final BigDecimal leftTorqueEffectiveness, final BigDecimal rightTorqueEffectiveness) + { + Map map = new HashMap(); + map.put("LTE", String.format("%.1f", leftTorqueEffectiveness)); + map.put("RTE", String.format("%.1f", rightTorqueEffectiveness)); + writeData(map); + } + + } + ); + + result.subscribePedalSmoothnessEvent(new IPedalSmoothnessReceiver() { + @Override + public void onNewPedalSmoothness(final long estTimestamp, final EnumSet eventFlags, final long powerOnlyUpdateEventCount, final boolean separatePedalSmoothnessSupport, final BigDecimal leftOrCombinedPedalSmoothness, final BigDecimal rightPedalSmoothness) + { + Map map = new HashMap(); + map.put("SNPLC", String.format("%.1f", leftOrCombinedPedalSmoothness)); + map.put("SNPR", String.format("%.1f", rightPedalSmoothness)); + writeData(map); + } + } + ); + } + } + }; +} + + diff --git a/contrib/RideLogger/src/com/ridelogger/listners/Sensors.java b/contrib/RideLogger/src/com/ridelogger/listners/Sensors.java new file mode 100644 index 000000000..c8ecefdf9 --- /dev/null +++ b/contrib/RideLogger/src/com/ridelogger/listners/Sensors.java @@ -0,0 +1,141 @@ +package com.ridelogger.listners; + +import java.util.HashMap; +import java.util.Map; + +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; + +public class Sensors extends Base +{ + private SensorManager mSensorManager; + + private Sensor mLight; + private Sensor mAccel; + private Sensor mPress; + private Sensor mTemp; + private Sensor mField; + + private SensorEventListener luxListner; + private SensorEventListener accelListner; + private SensorEventListener pressListner; + private SensorEventListener tempListner; + private SensorEventListener fieldListner; + + public Sensors(Context mContext) + { + super(mContext); + + mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + + mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + mPress = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); + mTemp = mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE); + mField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + + if(mLight != null) { + luxListner = new SensorEventListener() { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public final void onSensorChanged(SensorEvent event) { + // The light sensor returns a single value. + // Many sensors return 3 values, one for each axis. + writeData("lux", Float.toString(event.values[0])); + } + }; + + mSensorManager.registerListener(luxListner, mLight, 3000000); + } + if(mAccel != null) { + accelListner = new SensorEventListener() { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public final void onSensorChanged(SensorEvent event) { + Map map = new HashMap(); + map.put("ms2x", Float.toString(event.values[0])); + map.put("ms2y", Float.toString(event.values[1])); + map.put("ms2z", Float.toString(event.values[2])); + writeData(map); + } + }; + + mSensorManager.registerListener(accelListner, mAccel, SensorManager.SENSOR_DELAY_NORMAL); + } + if(mPress != null) { + pressListner = new SensorEventListener() { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public final void onSensorChanged(SensorEvent event) { + // The light sensor returns a single value. + // Many sensors return 3 values, one for each axis. + writeData("press", Float.toString(event.values[0])); + } + }; + + mSensorManager.registerListener(pressListner, mPress, 3000000); + } + if(mTemp != null) { + tempListner = new SensorEventListener() { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public final void onSensorChanged(SensorEvent event) { + // The light sensor returns a single value. + // Many sensors return 3 values, one for each axis. + writeData("temp", Float.toString(event.values[0])); + } + }; + + mSensorManager.registerListener(tempListner, mTemp, 3000000); + } + if(mField != null) { + fieldListner = new SensorEventListener() { + @Override + public final void onAccuracyChanged(Sensor sensor, int accuracy) {} + + @Override + public final void onSensorChanged(SensorEvent event) { + Map map = new HashMap(); + map.put("uTx", Float.toString(event.values[0])); + map.put("uTy", Float.toString(event.values[1])); + map.put("uTz", Float.toString(event.values[2])); + writeData(map); + } + }; + + mSensorManager.registerListener(fieldListner, mField, SensorManager.SENSOR_DELAY_NORMAL); + } + } + + + @Override + public void onDestroy() + { + if(luxListner != null) { + mSensorManager.unregisterListener(luxListner); + } + if(accelListner != null) { + mSensorManager.unregisterListener(accelListner); + } + if(pressListner != null) { + mSensorManager.unregisterListener(pressListner); + } + if(tempListner != null) { + mSensorManager.unregisterListener(tempListner); + } + if(fieldListner != null) { + mSensorManager.unregisterListener(fieldListner); + } + } +} \ No newline at end of file