package com.solderbyte.openfit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.content.SharedPreferences;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessActivities;
import com.google.android.gms.fitness.data.DataPoint;
import com.google.android.gms.fitness.data.DataSet;
import com.google.android.gms.fitness.data.DataSource;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;
import com.google.android.gms.fitness.data.Session;
import com.google.android.gms.fitness.request.DataDeleteRequest;
import com.google.android.gms.fitness.request.SessionInsertRequest;
import com.google.android.gms.fitness.request.SessionReadRequest;
import com.google.android.gms.fitness.result.SessionReadResult;
import com.solderbyte.openfit.util.OpenFitData;
import com.solderbyte.openfit.util.OpenFitIntent;
import com.solderbyte.openfit.ExerciseGPSStorage;
public class GoogleFit {
private static final String LOG_TAG = "OpenFit:GoogleFit";
private static Context context = null;
private static GoogleApiClient mClient = null;
private static boolean GAPI_CONNECTED = false;
private static ArrayList<Session> sessions = null;
private static ArrayList<DataSet> sessionsStepsDataSets = null;
private static ArrayList<DataSet> sessionsDistanceDataSets = null;
private static ArrayList<DataSet> sessionsCaloriesDataSets = null;
private static ArrayList<DataSet> sessionsActivitySegmentDataSets = null;
private static ArrayList<Session> sessionsExercise = null;
private static ArrayList<DataSet> sessionsExerciseDuration = null;
private static ArrayList<DataSet> sessionsExerciseCalorie = null;
private static ArrayList<DataSet> sessionsExerciseAvgHeartRate = null;
private static ArrayList<DataSet> sessionsExerciseMaxHeartRate = null;
private static ArrayList<DataSet> sessionsExerciseDistance = null;
private static ArrayList<DataSet> sessionsExerciseAvgSpeed = null;
private static ArrayList<DataSet> sessionsExerciseMaxSpeed = null;
private static ArrayList<DataSet> sessionsExerciseSteps = null;
private static ArrayList<DataSet> sessionsExerciseGPS = null;
private static ArrayList<Session> sessionsSleep = null;
private static ArrayList<PedometerData> pedometerList = null;
private static ArrayList<ExerciseData> excerciseList = null;
private static ArrayList<SleepData> sleepList = null;
private static ArrayList<SleepInfo> sleepInfoList = null;
private static ArrayList<HeartRateData> heartRateList = null;
private static ProfileData profileData = null;
private static Date lastPedometerSession = null;
private static Date lastRunningSession = null;
private static Date lastWalkingSession = null;
private static Date lastSleepSession = null;
private static Date lastProfileData = null;
private static Date lastPedometerStartTime = null;
private static Date lastCyclingSession = null;
private static Date lastHikingSession = null;
private static int lastPedometerSteps = 0;
private static float lastPedometerCals = 0;
private static float lastPedometerDist = 0;
private static SharedPreferences prefs;
private static String prefsSteps = "com.solderbyte.openfit.lastSteps";
private static String prefsCals = "com.solderbyte.openfit.lastCals";
private static String prefsDist = "com.solderbyte.openfit.lastDist";
public GoogleFit() {}
public GoogleFit(Context cntxt) {
Log.d(LOG_TAG, "Creating Google Fit without client");
context = cntxt;
this.buildFitnessClient(cntxt);
this.connectGoogleFit();
prefs = context.getSharedPreferences("com.solderbyte.openfit", Context.MODE_PRIVATE);
}
public GoogleFit(Context cntxt, GoogleApiClient client) {
Log.d(LOG_TAG, "Creating Google Fit");
context = cntxt;
mClient = client;
}
public void syncData() {
Log.d(LOG_TAG, "syncing data");
new readDataTask().execute();
}
public void setData(ArrayList<PedometerData> pList, ArrayList<ExerciseData> eList, ArrayList<SleepData> srList, ArrayList<SleepInfo> siList, ArrayList<HeartRateData> hList, ProfileData pData) {
Log.d(LOG_TAG, "setData");
pedometerList = pList;
excerciseList = eList;
sleepList = srList;
sleepInfoList = siList;
heartRateList = hList;
profileData = pData;
}
public void getData() {
Log.d(LOG_TAG, "getData");
new readDataTask().execute();
}
public void writeData() {
Log.d(LOG_TAG, "writeData");
new writeDataTask().execute();
}
public void parseDataSet(DataSet dataSet) {
for(DataPoint dp : dataSet.getDataPoints()) {
Date start = new Date(dp.getStartTime(TimeUnit.MILLISECONDS));
Date end = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
Log.d(LOG_TAG, "Type: " + dp.getDataType().getName());
Log.d(LOG_TAG, "Date: " + start + ":" + end);
for(Field field : dp.getDataType().getFields()) {
Log.d(LOG_TAG, "Field: " + field.getName() + " Value: " + dp.getValue(field));
}
}
}
public void delData() {
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.WEEK_OF_YEAR, -4);
long startTime = cal.getTimeInMillis();
DataDeleteRequest delRequest = new DataDeleteRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
.deleteAllData()
.deleteAllSessions()
.build();
Fitness.HistoryApi.deleteData(mClient, delRequest)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if(status.isSuccess()) {
Log.d(LOG_TAG, "Successfully deleted sessions");
}
else {
Log.d(LOG_TAG, "Failed to delete sessions");
}
}
});
}
private void buildFitnessClient(Context cntxt) {
Log.d(LOG_TAG, "buildFitnessClient");
mClient = new GoogleApiClient.Builder(cntxt)
.addApi(Fitness.CONFIG_API)
.addApi(Fitness.HISTORY_API)
.addApi(Fitness.SESSIONS_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addScope(new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(Bundle bundle) {
Log.d(LOG_TAG, "Google Fit connected");
GAPI_CONNECTED = true;
Intent msg = new Intent(OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_MSG, OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, true);
//sendBroadcast(msg);
//gFit = new GoogleFit(getBaseContext(), mClient);
}
@Override
public void onConnectionSuspended(int i) {
GAPI_CONNECTED = false;
Intent msg = new Intent(OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_MSG, OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
//sendBroadcast(msg);
if(i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.d(LOG_TAG, "Google Fit connection lost. Network Lost");
}
else if(i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.d(LOG_TAG, "Google Fit connection lost. Service Disconnected");
}
}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.d(LOG_TAG, "Google Fit connection failed. Cause: " + result.toString());
GAPI_CONNECTED = false;
Intent msg = new Intent(OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_MSG, OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
//sendBroadcast(msg);
}
}).build();
}
public void connectGoogleFit() {
if(mClient == null) {
Log.d(LOG_TAG, "GoogleFit is null");
return;
}
if(!mClient.isConnecting() && !mClient.isConnected()) {
Log.d(LOG_TAG, "Connecting to GoogleFit");
mClient.connect();
}
else {
Log.d(LOG_TAG, "GoogleFit already connected: ");
}
}
public void disconnectGoogleFit() {
if(mClient.isConnected()) {
Log.d(LOG_TAG, "Disconnecting to GoogleFit");
PendingResult<Status> pendingResult = Fitness.ConfigApi.disableFit(mClient);
pendingResult.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(Status status) {
if(status.isSuccess()) {
//GFIT_CONNECTED = false;
Log.d(LOG_TAG, "Google Fit disabled");
Intent msg = new Intent(OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_MSG, OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
//getActivity().sendBroadcast(msg);
mClient.disconnect();
} else {
Log.e(LOG_TAG, "Google Fit wasn't disabled " + status);
}
}
});
}
}
private class readDataTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
Log.d(LOG_TAG, "readDataTask");
Calendar cal = Calendar.getInstance();
Date now = new Date();
cal.setTime(now);
long endTime = cal.getTimeInMillis();
cal.add(Calendar.DAY_OF_MONTH, -3);
long startTime = cal.getTimeInMillis();
lastPedometerSteps = 0;
lastPedometerCals = 0;
lastPedometerDist = 0;
SessionReadRequest readRequest = new SessionReadRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
.read(DataType.TYPE_ACTIVITY_SEGMENT)
.build();
SessionReadResult sessionReadResult = Fitness.SessionsApi.readSession(mClient, readRequest).await(1, TimeUnit.MINUTES);
Log.d(LOG_TAG, "Session read was successful. Number of returned sessions is: " + sessionReadResult.getSessions().size());
for(Session session : sessionReadResult.getSessions()) {
Date start = new Date(session.getStartTime(TimeUnit.MILLISECONDS));
Date end = new Date(session.getEndTime(TimeUnit.MILLISECONDS));
Log.d(LOG_TAG, "Description: " + session.getDescription());
Log.d(LOG_TAG, "start: " + start + ", end: " + end);
Log.d(LOG_TAG, "Activity" + session.getActivity());
List<DataSet> dataSets = sessionReadResult.getDataSet(session);
for(DataSet dataSet : dataSets) {
for(DataPoint dp : dataSet.getDataPoints()) {
if(session.getActivity() == FitnessActivities.WALKING) {
long sTime = dp.getStartTime(TimeUnit.MILLISECONDS);
if(sTime % 600000 == 0) {
lastPedometerStartTime = new Date(sTime);
}
lastPedometerSession = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
}
else if(session.getActivity() == FitnessActivities.WALKING_FITNESS) {
lastWalkingSession = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
}
else if(session.getActivity() == FitnessActivities.RUNNING) {
lastRunningSession = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
}
else if(session.getActivity() == FitnessActivities.SLEEP) {
lastSleepSession = new Date(dp.getStartTime(TimeUnit.MILLISECONDS));
}
else if(session.getActivity() == FitnessActivities.BIKING) {
lastCyclingSession = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
}
else if(session.getActivity() == FitnessActivities.HIKING) {
lastHikingSession = new Date(dp.getEndTime(TimeUnit.MILLISECONDS));
}
}
}
}
if(lastPedometerSession != null) {
if(lastWalkingSession != null && lastPedometerSession.getTime() < lastWalkingSession.getTime()) {
lastPedometerSession = lastWalkingSession;
}
if(lastRunningSession != null && lastPedometerSession.getTime() < lastRunningSession.getTime()) {
lastPedometerSession = lastRunningSession;
}
if(lastCyclingSession != null && lastPedometerSession.getTime() < lastCyclingSession.getTime()) {
lastPedometerSession = lastCyclingSession;
}
if(lastHikingSession != null && lastPedometerSession.getTime() < lastHikingSession.getTime()) {
lastPedometerSession = lastHikingSession;
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(lastPedometerSession);
int minute = ((int) (calendar.get(Calendar.MINUTE) / 10.0) * 10);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
lastPedometerStartTime = calendar.getTime();
if(lastPedometerStartTime.getTime() == lastPedometerSession.getTime()) {
calendar.add(Calendar.MINUTE, -10);
lastPedometerStartTime = calendar.getTime();
}
}
Log.d(LOG_TAG, "Last session updated start: " + lastPedometerStartTime + ", end: " + lastPedometerSession);
lastPedometerSteps = prefs.getInt(prefsSteps, 0);
lastPedometerCals = prefs.getFloat(prefsCals, 0);
lastPedometerDist = prefs.getFloat(prefsDist, 0);
Log.d(LOG_TAG, "Last pedometer session from: " + lastPedometerStartTime + " to: " + lastPedometerSession + " steps: " + lastPedometerSteps + " cals: " + lastPedometerCals + " dist: " + lastPedometerDist);
Log.d(LOG_TAG, "Last walking session: " + lastWalkingSession);
Log.d(LOG_TAG, "Last running session: " + lastRunningSession);
Log.d(LOG_TAG, "Last cycling session: " + lastCyclingSession);
Log.d(LOG_TAG, "Last hiking session: " + lastHikingSession);
writeData();
return null;
}
}
private class writeDataTask extends AsyncTask<Void, Void, Void> {
private boolean insertPedometerData () {
boolean success = false;
if(pedometerList != null) {
Log.d(LOG_TAG, "write pedometerList");
DataSource stepsDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setName("Open Fit - step count")
.setType(DataSource.TYPE_RAW)
.build();
DataSource distanceDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_DISTANCE_DELTA)
.setName("Open Fit - step count")
.setType(DataSource.TYPE_RAW)
.build();
DataSource caloriesDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_CALORIES_EXPENDED)
.setName("Open Fit - step count")
.setType(DataSource.TYPE_RAW)
.build();
DataSource activitySegmentDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
.setName("Open Fit - activity segment")
.setType(DataSource.TYPE_RAW)
.build();
sessions = new ArrayList<Session>();
sessionsStepsDataSets = new ArrayList<DataSet>();
sessionsDistanceDataSets = new ArrayList<DataSet>();
sessionsCaloriesDataSets = new ArrayList<DataSet>();
sessionsActivitySegmentDataSets = new ArrayList<DataSet>();
for(int i = 0; i < pedometerList.size(); i++) {
int steps = pedometerList.get(i).getSteps();
float cals = pedometerList.get(i).getCalories();
float dist = pedometerList.get(i).getDistance();
Calendar cal = Calendar.getInstance();
Date startDate = new Date(pedometerList.get(i).getTimeStamp());
cal.setTime(startDate);
String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
String date = Integer.toString(cal.get(Calendar.DAY_OF_MONTH));
String year = Integer.toString(cal.get(Calendar.YEAR));
Date endDate = new Date(pedometerList.get(i).getTimeStampEnd());
if(lastPedometerSession != null && lastPedometerSession.getTime() > startDate.getTime()) {
Log.d(LOG_TAG, "Pedometer data already Synced: " + startDate + " --- " + endDate + " --- "+steps);
continue;
}
if(steps == 0) {
continue;
}
if(startDate.getTime() == endDate.getTime()) {
endDate = new Date(pedometerList.get(i).getTimeStampEnd() + 1000);
}
Log.d(LOG_TAG, "Syncing pedometer: " + startDate + " --- " + endDate + " steps: " + steps);
// create data points
DataSet dSteps = DataSet.create(stepsDataSource);
DataPoint pSteps = dSteps.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pSteps.getValue(Field.FIELD_STEPS).setInt(steps);
dSteps.add(pSteps);
DataSet dDistance = DataSet.create(distanceDataSource);
DataPoint pDistance = dDistance.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pDistance.getValue(Field.FIELD_DISTANCE).setFloat(dist);
dDistance.add(pDistance);
DataSet dCalories = DataSet.create(caloriesDataSource);
DataPoint pCalories = dCalories.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pCalories.getValue(Field.FIELD_CALORIES).setFloat(cals);
dCalories.add(pCalories);
DataSet dActivitySegmentDataSet = DataSet.create(activitySegmentDataSource);
DataPoint pActivitySegment = dActivitySegmentDataSet.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pActivitySegment.getValue(Field.FIELD_ACTIVITY).setActivity(FitnessActivities.WALKING);
dActivitySegmentDataSet.add(pActivitySegment);
Session session = new Session.Builder()
.setName("Open Fit Pedometer - " + month + " " + date + ", " + year)
.setDescription("Open Fit pedometer data gathered from Samsung Gear Fit")
.setActivity(FitnessActivities.WALKING)
.setStartTime(startDate.getTime(), TimeUnit.MILLISECONDS)
.setEndTime(endDate.getTime(), TimeUnit.MILLISECONDS)
.build();
sessionsStepsDataSets.add(dSteps);
sessionsDistanceDataSets.add(dDistance);
sessionsCaloriesDataSets.add(dCalories);
sessionsActivitySegmentDataSets.add(dActivitySegmentDataSet);
sessions.add(session);
}
if(sessions.size() == 0) {
success = true;
Log.d(LOG_TAG, "Pedometer data alredy synced");
}
for(int j = 0; j < sessions.size(); j++) {
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
.setSession(sessions.get(j))
.addDataSet(sessionsStepsDataSets.get(j))
.addDataSet(sessionsDistanceDataSets.get(j))
.addDataSet(sessionsCaloriesDataSets.get(j))
.addDataSet(sessionsActivitySegmentDataSets.get(j))
.build();
com.google.android.gms.common.api.Status insertStatus = Fitness.SessionsApi.insertSession(mClient, insertRequest).await(1, TimeUnit.MINUTES);
if(!insertStatus.isSuccess()) {
success = false;
Log.d(LOG_TAG, "Pedometer data: There was a problem inserting the session: " + insertStatus);
}
else {
success = true;
Log.d(LOG_TAG, "Pedometer data inserted: " + insertStatus);
}
}
}
return success;
}
private boolean insertExerciseData () {
boolean success = false;
if(excerciseList != null) {
Log.d(LOG_TAG, "write exerciseList");
DataSource caloriesDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_CALORIES_EXPENDED)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource avgHeartRateDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_HEART_RATE_BPM)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource maxHeartRateDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_HEART_RATE_BPM)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource avgSpeedDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_SPEED)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource maxSpeedDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_SPEED)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource distanceDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_DISTANCE_DELTA)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource stepsDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource locationDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_LOCATION_SAMPLE)
.setName("Open Fit - exercise")
.setType(DataSource.TYPE_RAW)
.build();
DataSource activitySegmentDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
.setName("Open Fit - activity segment")
.setType(DataSource.TYPE_RAW)
.build();
sessionsExercise = new ArrayList<Session>();
sessionsExerciseDistance = new ArrayList<DataSet>();
sessionsExerciseCalorie = new ArrayList<DataSet>();
sessionsExerciseAvgHeartRate = new ArrayList<DataSet>();
sessionsExerciseAvgSpeed = new ArrayList<DataSet>();
sessionsExerciseSteps = new ArrayList<DataSet>();
sessionsExerciseGPS = new ArrayList<DataSet>();
sessionsActivitySegmentDataSets = new ArrayList<DataSet>();
for(int i = 0; i < excerciseList.size(); i++) {
long exTimeStamp = excerciseList.get(i).getTimeStamp();
long exTimeStampEnd = excerciseList.get(i).getTimeStampEnd();
float calories = excerciseList.get(i).getCalories();
int avgHeartrate = excerciseList.get(i).getAvgHeartRate();
float distance = excerciseList.get(i).getDistance();
int type = excerciseList.get(i).getExerciseType();
float avgSpeed = excerciseList.get(i).getAvgSpeed();
float maxSpeed = excerciseList.get(i).getMaxSpeed();
int maxHeartrate = excerciseList.get(i).getMaxHeartRate();
Calendar cal = Calendar.getInstance();
Date startDate = new Date(exTimeStamp);
cal.setTime(startDate);
Date endDate = new Date(exTimeStampEnd);
String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
String date = Integer.toString(cal.get(Calendar.DAY_OF_MONTH));
String year = Integer.toString(cal.get(Calendar.YEAR));
if(lastPedometerSession != null && lastPedometerSession.getTime() >= endDate.getTime()) {
Log.d(LOG_TAG, "Exercise data already Synced: " + startDate + " --- " + endDate);
continue;
}
// get steps from pedometer for this exercise
int j = 0;
ArrayList<PedometerData> updatedPedometer = new ArrayList<PedometerData>();
long steps = 0;
while(true) {
if(j >= pedometerList.size()) {
break;
}
if(j < pedometerList.size() - 1 && pedometerList.get(j).getTimeStamp() < exTimeStamp && pedometerList.get(j + 1).getTimeStamp() > exTimeStamp) {
int firstj = j;
long st = 0;
float dst = 0;
float cls = 0;
int lastj = j;
while(j < pedometerList.size() - 1 && pedometerList.get(j).getTimeStampEnd() < exTimeStampEnd) {
st += pedometerList.get(j).getSteps();
dst += pedometerList.get(j).getDistance();
cls += pedometerList.get(j).getCalories();
j++;
lastj = j;
}
st += pedometerList.get(j).getSteps();
dst += pedometerList.get(j).getDistance();
cls += pedometerList.get(j).getCalories();
long lastTimeStamp = lastj < pedometerList.size() ? pedometerList.get(lastj).getTimeStampEnd() : pedometerList.get(lastj - 1).getTimeStampEnd();
if(lastTimeStamp < exTimeStampEnd) {
lastTimeStamp = exTimeStampEnd;
}
double stepsPerSec = (double) st / (lastTimeStamp - pedometerList.get(firstj).getTimeStamp());
steps = Math.abs(Math.round(stepsPerSec * (exTimeStampEnd - exTimeStamp)));
long startTimeStamp = pedometerList.get(firstj).getTimeStamp();
long endTimeStamp = exTimeStamp;
st = Math.abs(Math.round(stepsPerSec * (endTimeStamp - startTimeStamp)));
long bck_steps = steps;
if(type == OpenFitData.CYCLING_EXERCISE) {
st += Math.round(bck_steps / 2);
steps = 0;
}
float div = steps + st;
float newDst = div > 0 ? st * dst / div : 0;
float newCls = div > 0 ? st * cls / div : 0;
PedometerData pd = new PedometerData(startTimeStamp, (int) st, newDst, newCls);
pd.setTimeStampEnd(endTimeStamp);
updatedPedometer.add(pd);
startTimeStamp = exTimeStampEnd;
endTimeStamp = lastTimeStamp;
st = Math.abs(Math.round(stepsPerSec * (endTimeStamp - startTimeStamp)));
if(type == OpenFitData.CYCLING_EXERCISE) {
st += Math.round(bck_steps / 2);
steps = 0;
}
div = steps + st;
newDst = div > 0 ? st * dst / div : 0;
newCls = div > 0 ? st * cls / div : 0;
pd = new PedometerData(startTimeStamp, (int) st, newDst, newCls);
pd.setTimeStampEnd(endTimeStamp);
updatedPedometer.add(pd);
}
else if(j == pedometerList.size() - 1 && pedometerList.get(j).getTimeStamp() < exTimeStamp) {
float stepsPerSec = (float) pedometerList.get(j).getSteps() / (exTimeStampEnd - pedometerList.get(j).getTimeStamp());
steps = Math.abs(Math.round(stepsPerSec * (exTimeStampEnd - exTimeStamp)));
long startTimeStamp = pedometerList.get(j).getTimeStamp();
long endTimeStamp = exTimeStamp;
int st = Math.abs(Math.round(stepsPerSec * (endTimeStamp - startTimeStamp)));
if(type == OpenFitData.CYCLING_EXERCISE) {
st += steps;
steps = 0;
}
float newDst = st * pedometerList.get(j).getDistance() / (steps + st);
float newCls = st * pedometerList.get(j).getCalories() / (steps + st);
PedometerData pd = new PedometerData(startTimeStamp, st, newDst, newCls);
pd.setTimeStampEnd(endTimeStamp);
updatedPedometer.add(pd);
}
else {
updatedPedometer.add(pedometerList.get(j));
}
j++;
}
pedometerList = updatedPedometer;
Log.d(LOG_TAG, "Syncing exercise: " + startDate + " --- " + endDate + " steps: " + steps + " exercise_type: " + type);
if(startDate.getTime() == endDate.getTime()) {
continue;
}
// create data points
DataSet dCalories = DataSet.create(caloriesDataSource);
DataPoint pCalories = dCalories.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pCalories.getValue(Field.FIELD_CALORIES).setFloat(calories);
dCalories.add(pCalories);
DataSet dDistance = DataSet.create(distanceDataSource);
DataPoint pDistance = dDistance.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pDistance.getValue(Field.FIELD_DISTANCE).setFloat(distance);
dDistance.add(pDistance);
DataSet dHeartRateAVG = DataSet.create(avgHeartRateDataSource);
DataPoint pHeartRateAVG = dHeartRateAVG.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pHeartRateAVG.getValue(Field.FIELD_BPM).setFloat((float) avgHeartrate);
dHeartRateAVG.add(pHeartRateAVG);
DataSet dSteps = DataSet.create(stepsDataSource);
DataPoint pSteps = dSteps.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pSteps.getValue(Field.FIELD_STEPS).setInt((int)steps);
dSteps.add(pSteps);
String act = FitnessActivities.WALKING_FITNESS;
if(type == OpenFitData.RUN_EXERCISE) {
act = FitnessActivities.RUNNING;
}
if(type == OpenFitData.CYCLING_EXERCISE) {
act = FitnessActivities.BIKING;
}
if(type == OpenFitData.HIKING_EXERCISE) {
act = FitnessActivities.HIKING;
}
DataSet dActivitySegmentDataSet = DataSet.create(activitySegmentDataSource);
DataPoint pActivitySegment = dActivitySegmentDataSet.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pActivitySegment.getValue(Field.FIELD_ACTIVITY).setActivity(act);
dActivitySegmentDataSet.add(pActivitySegment);
DataSet dLocation = DataSet.create(locationDataSource);
DataSet dSpeedAVG = DataSet.create(avgSpeedDataSource);
ArrayList<GPSData> gpsData = ExerciseGPSStorage.getGpsDataListForExercise(exTimeStamp, exTimeStampEnd);
for(int k = 0; k < gpsData.size(); k++) {
// Log.d(LOG_TAG, "GPS DATA: totalDistance=" + gpsData.get(k).getTotalDistance() + ", lon=" + gpsData.get(k).getLon() + ", lat=" + gpsData.get(k).getLat() + ", altitude=" + gpsData.get(k).getAltitude() + ", timestamp=" + gpsData.get(k).getTimeStamp());
DataPoint pLocation = dLocation.createDataPoint().setTimestamp(gpsData.get(k).getTimeStamp(), TimeUnit.MILLISECONDS);
pLocation.getValue(Field.FIELD_LONGITUDE).setFloat(gpsData.get(k).getLon());
pLocation.getValue(Field.FIELD_LATITUDE).setFloat(gpsData.get(k).getLat());
pLocation.getValue(Field.FIELD_ACCURACY).setFloat(gpsData.get(k).getAccuracy());
pLocation.getValue(Field.FIELD_ALTITUDE).setFloat(gpsData.get(k).getAltitude());
dLocation.add(pLocation);
DataPoint pSpeedAVG = dSpeedAVG.createDataPoint().setTimestamp(gpsData.get(k).getTimeStamp(), TimeUnit.MILLISECONDS);
pSpeedAVG.getValue(Field.FIELD_SPEED).setFloat(gpsData.get(k).getSpeed());
dSpeedAVG.add(pSpeedAVG);
}
if(gpsData.size() == 0) {
DataPoint pSpeedAVG = dSpeedAVG.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pSpeedAVG.getValue(Field.FIELD_SPEED).setFloat(avgSpeed);
dSpeedAVG.add(pSpeedAVG);
}
Log.d(LOG_TAG, "GPS DATA: " + dLocation.getDataPoints().size());
Session session = new Session.Builder()
.setName("Open Fit Exercise - " + month + " " + date + ", " + year)
.setDescription("Open Fit exercise data gathered from Samsung Gear Fit")
.setActivity(act)
.setStartTime(startDate.getTime(), TimeUnit.MILLISECONDS)
.setEndTime(endDate.getTime(), TimeUnit.MILLISECONDS)
.build();
sessionsExerciseDistance.add(dDistance);
sessionsExerciseCalorie.add(dCalories);
sessionsExerciseAvgHeartRate.add(dHeartRateAVG);
sessionsExerciseAvgSpeed.add(dSpeedAVG);
sessionsExerciseSteps.add(dSteps);
sessionsExerciseGPS.add(dLocation);
sessionsActivitySegmentDataSets.add(dActivitySegmentDataSet);
sessionsExercise.add(session);
}
if(sessionsExercise.size() == 0) {
success = true;
}
Log.d(LOG_TAG, "Exercise data size: " + sessionsExercise.size());
for(int j = 0; j < sessionsExercise.size(); j++) {
SessionInsertRequest insertRequest;
int awaitMin = 1;
if(sessionsExerciseGPS.get(j).getDataPoints().size() > 0) {
insertRequest = new SessionInsertRequest.Builder()
.setSession(sessionsExercise.get(j))
.addDataSet(sessionsExerciseDistance.get(j))
.addDataSet(sessionsExerciseCalorie.get(j))
.addDataSet(sessionsExerciseAvgHeartRate.get(j))
.addDataSet(sessionsExerciseAvgSpeed.get(j))
.addDataSet(sessionsExerciseSteps.get(j))
.addDataSet(sessionsExerciseGPS.get(j))
.addDataSet(sessionsActivitySegmentDataSets.get(j))
.build();
awaitMin = 10;
}
else {
insertRequest = new SessionInsertRequest.Builder()
.setSession(sessionsExercise.get(j))
.addDataSet(sessionsExerciseDistance.get(j))
.addDataSet(sessionsExerciseCalorie.get(j))
.addDataSet(sessionsExerciseAvgHeartRate.get(j))
.addDataSet(sessionsExerciseAvgSpeed.get(j))
.addDataSet(sessionsExerciseSteps.get(j))
.addDataSet(sessionsActivitySegmentDataSets.get(j))
.build();
}
com.google.android.gms.common.api.Status insertStatus = Fitness.SessionsApi.insertSession(mClient, insertRequest).await(awaitMin, TimeUnit.MINUTES);
if(!insertStatus.isSuccess()) {
success = false;
Log.d(LOG_TAG, "Exercise data: There was a problem inserting the session: " + insertStatus);
}
else {
success = true;
Log.d(LOG_TAG, "Exercise data inserted: " + insertStatus);
}
}
}
return success;
}
private boolean insertSleepData () {
boolean success = false;
if(sleepList != null) {
Log.d(LOG_TAG, "write sleepList");
DataSource activitySegmentDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_ACTIVITY_SEGMENT)
.setName("Open Fit - activity segment")
.setType(DataSource.TYPE_RAW)
.build();
sessionsSleep = new ArrayList<Session>();
sessionsActivitySegmentDataSets = new ArrayList<DataSet>();
for(int i = 0; i < sleepList.size(); i++) {
int index = sleepList.get(i).getIndex() - 1;
long timestampStart = sleepList.get(i).getStartTimeStamp();
long timestampEnd = sleepList.get(i).getEndTimeStamp();
float efficiency = sleepList.get(i).getEfficiency();
int len = sleepList.get(i).getLen();
Calendar cal = Calendar.getInstance();
Date startDate = new Date(timestampStart);
cal.setTime(startDate);
Date endDate = new Date(timestampEnd);
String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
String date = Integer.toString(cal.get(Calendar.DAY_OF_MONTH));
String year = Integer.toString(cal.get(Calendar.YEAR));
if(lastSleepSession != null && lastSleepSession.getTime() >= startDate.getTime()) {
//Log.d(LOG_TAG, "Sleep info already Synced");
continue;
}
if(sleepInfoList.get(0).getIndex() > index + 1) {
continue;
}
index = index - sleepInfoList.get(0).getIndex() + 1;
// 0 - 29 SLEEP_AWAKE
// 30 - 79 SLEEP_LIGHT
// 80 - 100 SLEEP_DEEP
// Log.d(LOG_TAG, "START - END: " + startDate + " " + endDate);
DataSet dActivitySegmentDataSet = DataSet.create(activitySegmentDataSource);
for(int j = index; j < index + len; j++) {
// create sessions
int sleepType = sleepInfoList.get(j).getStatus();
long infoFrom = sleepInfoList.get(j).getTimeStamp();
long infoTo = 0;
if(j < index + len - 1) {
infoTo = sleepInfoList.get(j + 1).getTimeStamp();
}
else {
infoTo = timestampEnd;
}
String sleepAct = FitnessActivities.SLEEP_AWAKE;
if(sleepType >= 30 && sleepType < 80) {
sleepAct = FitnessActivities.SLEEP_LIGHT;
}
else if(sleepType >= 80) {
sleepAct = FitnessActivities.SLEEP_DEEP;
}
Date t = new Date(infoFrom);
Date tt = new Date(infoTo);
DataPoint pActivitySegment = dActivitySegmentDataSet.createDataPoint().setTimeInterval(infoFrom, infoTo, TimeUnit.MILLISECONDS);
pActivitySegment.getValue(Field.FIELD_ACTIVITY).setActivity(sleepAct);
dActivitySegmentDataSet.add(pActivitySegment);
}
// create sessions
Session sessionSleep = new Session.Builder()
.setName("Open Fit Sleep info - " + month + " " + date + ", " + year)
.setDescription("Open Fit sleep data gathered from Samsung Gear Fit")
.setActivity(FitnessActivities.SLEEP)
.setStartTime(startDate.getTime(), TimeUnit.MILLISECONDS)
.setEndTime(endDate.getTime(), TimeUnit.MILLISECONDS)
.build();
sessionsActivitySegmentDataSets.add(dActivitySegmentDataSet);
sessionsSleep.add(sessionSleep);
}
if(sessionsSleep.size() == 0) {
success = true;
Log.d(LOG_TAG, "Sleep data alredy synced");
}
for(int j = 0; j < sessionsSleep.size(); j++) {
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
.setSession(sessionsSleep.get(j))
.addDataSet(sessionsActivitySegmentDataSets.get(j))
.build();
com.google.android.gms.common.api.Status insertStatus = Fitness.SessionsApi.insertSession(mClient, insertRequest).await(1, TimeUnit.MINUTES);
if(!insertStatus.isSuccess()) {
success = false;
Log.d(LOG_TAG, "Sleep data: There was a problem inserting the session: " + insertStatus);
}
else {
success = true;
Log.d(LOG_TAG, "Sleep data inserted: " + insertStatus);
}
}
}
return success;
}
private boolean insertProfileData () {
boolean success = false;
if(profileData != null) {
Log.d(LOG_TAG, "write userData");
DataSource heightDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_HEIGHT)
.setName("Open Fit - profile data")
.setType(DataSource.TYPE_RAW)
.build();
DataSource weightDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_WEIGHT)
.setName("Open Fit - profile data")
.setType(DataSource.TYPE_RAW)
.build();
Calendar cal = Calendar.getInstance();
Date startDate = new Date(profileData.getTimeStamp());
cal.setTime(startDate);
cal.add(Calendar.SECOND, 1);
Date endDate = new Date(cal.getTimeInMillis());
DataSet dHeight = DataSet.create(heightDataSource);
DataPoint pHeight = dHeight.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pHeight = pHeight.setFloatValues(profileData.getHeight() / 100);
dHeight.add(pHeight);
DataSet dWeight = DataSet.create(weightDataSource);
DataPoint pWeight = dWeight.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pWeight = pWeight.setFloatValues(profileData.getWeight());
dWeight.add(pWeight);
com.google.android.gms.common.api.Status insertStatusH = Fitness.HistoryApi.insertData(mClient, dHeight).await(1, TimeUnit.MINUTES);
com.google.android.gms.common.api.Status insertStatusW = Fitness.HistoryApi.insertData(mClient, dWeight).await(1, TimeUnit.MINUTES);
if(!insertStatusH.isSuccess() || !insertStatusW.isSuccess()) {
success = false;
Log.d(LOG_TAG, "Profile data: There was a problem inserting the session");
}
else {
success = true;
Log.d(LOG_TAG, "Profile data inserted: " + insertStatusW);
}
}
return success;
}
private boolean insertHeartRate () {
boolean success = true;
if(heartRateList != null) {
Log.d(LOG_TAG, "write heartRate");
DataSource bpmDataSource = new DataSource.Builder()
.setAppPackageName("com.solderbyte.openfit")
.setDataType(DataType.TYPE_HEART_RATE_BPM)
.setName("Open Fit - heartrate data")
.setType(DataSource.TYPE_RAW)
.build();
for(int i = 0; i < heartRateList.size(); i++) {
long timeStamp = heartRateList.get(i).getTimeStamp();
float bpm = (float) heartRateList.get(i).getHeartRate();
Calendar cal = Calendar.getInstance();
Date startDate = new Date(timeStamp);
cal.setTime(startDate);
cal.add(Calendar.SECOND, 1);
Date endDate = new Date(cal.getTimeInMillis());
DataSet dBPM = DataSet.create(bpmDataSource);
DataPoint pBPM = dBPM.createDataPoint().setTimeInterval(startDate.getTime(), endDate.getTime(), TimeUnit.MILLISECONDS);
pBPM = pBPM.setFloatValues(bpm);
dBPM.add(pBPM);
com.google.android.gms.common.api.Status insertStatusBPM = Fitness.HistoryApi.insertData(mClient, dBPM).await(1, TimeUnit.MINUTES);
if(!insertStatusBPM.isSuccess()) {
success &= false;
Log.d(LOG_TAG, "Profile data: There was a problem inserting the session");
}
else {
success &= true;
Log.d(LOG_TAG, "Profile data inserted: " + insertStatusBPM);
}
}
}
return success;
}
private void updateLastPedo () {
if(lastPedometerStartTime != null) {
for(int i = 0; i < pedometerList.size(); i++) {
PedometerData p = pedometerList.get(i);
if(lastPedometerStartTime.getTime() == p.getTimeStamp() && p.getTimeStamp() < lastPedometerSession.getTime() && p.getTimeStampEnd() > lastPedometerSession.getTime() && lastPedometerSteps > 0) {
Log.d(LOG_TAG, "Original: " + new Date(p.getTimeStamp()) + " to: " + new Date(p.getTimeStampEnd()) + " steps: " + p.getSteps() + " cals: " + p.getCalories() + " dist: " + p.getDistance());
PedometerData p1 = new PedometerData(lastPedometerStartTime.getTime(), lastPedometerSteps, lastPedometerDist, lastPedometerCals);
p1.setTimeStampEnd(lastPedometerSession.getTime());
PedometerData p2 = new PedometerData(lastPedometerSession.getTime(), p.getSteps() - lastPedometerSteps, p.getDistance() - lastPedometerDist, p.getCalories() - lastPedometerCals);
p2.setTimeStampEnd(p.getTimeStampEnd());
Log.d(LOG_TAG, "Update1: " + new Date(p1.getTimeStamp()) + " to: " + new Date(p1.getTimeStampEnd()) + " steps: " + p1.getSteps() + " cals: " + p1.getCalories() + " dist: " + p1.getDistance());
Log.d(LOG_TAG, "Update2: " + new Date(p2.getTimeStamp()) + " to: " + new Date(p2.getTimeStampEnd()) + " steps: " + p2.getSteps() + " cals: " + p2.getCalories() + " dist: " + p2.getDistance());
pedometerList.add(i, p1);
pedometerList.add(i + 1, p2);
pedometerList.remove(i + 2);
break;
}
}
}
}
protected Void doInBackground(Void... params) {
Log.d(LOG_TAG, "writeDataTask");
int steps = 0;
float cals = 0;
float dist = 0;
if(pedometerList != null && pedometerList.size() > 0) {
PedometerData pd = pedometerList.get(pedometerList.size() - 1);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.set(Calendar.MINUTE, 10);
Log.d(LOG_TAG, "Last pedometer data from: " + new Date(pd.getTimeStamp()) + " to: " + new Date(pd.getTimeStampEnd()) + " steps: " + pd.getSteps() + " cals: " + pd.getCalories() + " dist: " + pd.getDistance());
if(pd.getTimeStampEnd() - pd.getTimeStamp() != cal.getTimeInMillis()) {
steps = pd.getSteps();
cals = pd.getCalories();
dist = pd.getDistance();
}
else {
steps = 0;
cals = 0;
dist = 0;
}
}
updateLastPedo();
boolean successExercise = insertExerciseData();
boolean successPedometer = insertPedometerData();
boolean successSleep = insertSleepData();
boolean successProfileData = insertProfileData();;
boolean successHeartRate = insertHeartRate();
if(successPedometer) {
Log.d(LOG_TAG, "Save to prefs steps: " + steps + " cals: " + cals + " dist: " + dist);
prefs.edit().putInt(prefsSteps, steps).commit();
prefs.edit().putFloat(prefsCals, cals).commit();
prefs.edit().putFloat(prefsDist, dist).commit();
}
Intent msg = new Intent(OpenFitIntent.INTENT_GOOGLE_FIT);
msg.putExtra(OpenFitIntent.INTENT_EXTRA_MSG, OpenFitIntent.INTENT_GOOGLE_FIT_SYNC_STATUS);
if(!successExercise) {
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
Log.d(LOG_TAG, "There was a problem inserting excercise data");
}
else if(!successPedometer) {
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
Log.d(LOG_TAG, "There was a problem inserting pedometer data");
}
else if(!successSleep) {
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
Log.d(LOG_TAG, "There was a problem inserting sleep data");
}
else if(!successProfileData) {
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
Log.d(LOG_TAG, "There was a problem inserting profile data");
}
else if(!successHeartRate) {
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, false);
Log.d(LOG_TAG, "There was a problem inserting heartrate data");
}
else {
Log.d(LOG_TAG, "Data insert was successful! ");
msg.putExtra(OpenFitIntent.INTENT_EXTRA_DATA, true);
}
Log.d(LOG_TAG, "Sending context");
context.sendBroadcast(msg);
return null;
}
}
}