package com.solderbyte.openfit; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Comparator; import java.util.Collections; import com.solderbyte.openfit.util.OpenFitData; import android.util.Log; public class Fitness { private static final String LOG_TAG = "OpenFit:Fitness"; private static ByteArrayOutputStream fitnessStream = new ByteArrayOutputStream(0); private static int size = 0; private static boolean pendingData = false; private static PedometerTotal pedometerTotal = null; private static ArrayList<PedometerData> pedometerList = new ArrayList<PedometerData>(); private static ArrayList<PedometerData> pedometerDailyList = new ArrayList<PedometerData>(); private static ArrayList<ExerciseData> exerciseDataList = new ArrayList<ExerciseData>(); private static ArrayList<SleepInfo> sleepInfoList = new ArrayList<SleepInfo>(); private static ArrayList<SleepData> sleepList = new ArrayList<SleepData>(); private static ArrayList<HeartRateData> heartRateList = new ArrayList<HeartRateData>(); private static ProfileData profileData = null; public static int getSize() { return size; } public static PedometerTotal getPedometerTotal() { return pedometerTotal; } public static ArrayList<PedometerData> getPedometerList() { return pedometerList; } public static ArrayList<PedometerData> getPedometerDailyList() { return pedometerDailyList; } public static ArrayList<ExerciseData> getExerciseDataList() { class cmp implements Comparator<ExerciseData> { @Override public int compare(ExerciseData ex1, ExerciseData ex2) { return ((Integer)ex1.getExerciseType()).compareTo((Integer)ex2.getExerciseType()); } } // Collections.sort(exerciseDataList, new cmp()); return exerciseDataList; } public static ArrayList<SleepInfo> getSleepInfoList() { return sleepInfoList; } public static ArrayList<SleepData> getSleepList() { return sleepList; } public static ArrayList<HeartRateData> getHeartRateList() { return heartRateList; } public static PedometerData[] getPedometerArray() { PedometerData[] p = new PedometerData[pedometerList.size()]; for(int i = 0; i < pedometerList.size(); i++) { p[i] = pedometerList.get(i); } return p; } public static ProfileData getProfileData() { return profileData; } public static void clearFitnessData() { fitnessStream = null; fitnessStream = new ByteArrayOutputStream(0); pedometerTotal = null; pedometerList = new ArrayList<PedometerData>(); pedometerDailyList = new ArrayList<PedometerData>(); exerciseDataList = new ArrayList<ExerciseData>(); sleepInfoList = new ArrayList<SleepInfo>(); sleepList = new ArrayList<SleepData>(); heartRateList = new ArrayList<HeartRateData>(); } public static boolean isPendingData() { return pendingData; } public static boolean isFitnessData(byte[] data) { ByteBuffer buffer = ByteBuffer.wrap(data); buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); byte type = buffer.get(); if(OpenFitApi.byteArrayToHexString(data).contains(OpenFitApi.byteArrayToHexString(OpenFitApi.getFitnessCycling()))) { return false; } if(OpenFitApi.byteArrayToHexString(data).contains(OpenFitApi.byteArrayToHexString(OpenFitApi.getFitnessRunning()))) { return false; } if(type == 2) { if(data.length <= 6) { return false; } size = buffer.getInt(); int msgType = buffer.getInt(); Log.d(LOG_TAG, "msgType: " + msgType); if(msgType == OpenFitData.FITNESS_MENU || msgType == OpenFitData.FITNESS_CANCEL || msgType == OpenFitData.FITNESS_UNKOWN) { return false; } pendingData = true; clearFitnessData(); return true; } else { return false; } } public static void addData(byte[] data) { try { fitnessStream.write(data); //Log.d(LOG_TAG, "Adding data to buffer: " + data.length); } catch (IOException e) { Log.e(LOG_TAG, "Error writting fitness data to buffer"); e.printStackTrace(); } if(fitnessStream.size() > size && fitnessStream.size() < (size + 6)) { Log.d(LOG_TAG, "Received all message data"); pendingData = false; } } @SuppressWarnings("unused") public static void parseData() { Log.d(LOG_TAG, "Parsing data"); ByteBuffer buffer = ByteBuffer.wrap(fitnessStream.toByteArray()); buffer = buffer.order(ByteOrder.LITTLE_ENDIAN); if(buffer.capacity() < 14) { return; } byte msgType = buffer.get(); int msgSize = buffer.getInt(); int byte4 = buffer.getInt(); int byte1 = buffer.getInt(); byte byteFF = buffer.get(); Log.d(LOG_TAG, "type: " + msgType); Log.d(LOG_TAG, "msgSize: " + msgSize); while(buffer.hasRemaining()) { byte fitnessType = buffer.get(); Log.d(LOG_TAG, "Fitness type: " + fitnessType); if(fitnessType == OpenFitData.DATA_TYPE_USER_PROFILE) { Log.d(LOG_TAG, "User Profile"); parseUserProfile(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_PEDOMETER_PROFILE) { Log.d(LOG_TAG, "Pedometer Profile"); parsePedometerProfile(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_PEDO_RESULTRECORD) { Log.d(LOG_TAG, "Pedometer Result Record"); parsePedoResultRecord(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_HEARTRATE_RESULTRECORD) { Log.d(LOG_TAG, "Heartrate Result Record"); parseHeartrateResultRecord(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_PEDO_INFO) { Log.d(LOG_TAG, "Pedometer Info"); parsePedoInfo(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_SLEEP_INFO) { Log.d(LOG_TAG, "Sleep Info"); parseSleepInfo(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_SLEEP_RESULTRECORD) { Log.d(LOG_TAG, "Sleep Result Record"); parseSleepResultRecord(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_COACHING_VARS) { Log.d(LOG_TAG, "Coaching Vars"); parseCoachingVars(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_COACHING_EXERCISERESULT) { Log.d(LOG_TAG, "Coaching Excercise Result"); parseCoachingExerciseResult(buffer); } else if(fitnessType == OpenFitData.DATA_TYPE_COACHING_RESULTRECORD) { Log.d(LOG_TAG, "Coaching Result Record"); parseCoachingResultRecord(buffer); } else { Log.d(LOG_TAG, "Unsupported: " + fitnessType); //logBuffer(buffer); depleteBuffer(buffer); } } Log.d(LOG_TAG, "remaining buffer: " + buffer.remaining()); } public static void parseUserProfile(ByteBuffer buffer) { int userProfileSize = buffer.getInt(); Log.d(LOG_TAG, "User profile: " + userProfileSize); long timeStamp = 0; int age = 0; float height = 0; float weight = 0; int gender = 0; int birthday = 0; int heightUnit = 0; int weightUnit = 0; int distanceUnit = 0; int activity = 0; for(int i = 0; i < 10; i++) { if(buffer.hasRemaining()) { if(i == 0) { timeStamp = buffer.getInt() * 1000L; } if(i == 1) { age = buffer.getInt(); } if(i == 2) { height = Float.intBitsToFloat(buffer.getInt()); } if(i == 2) { weight = Float.intBitsToFloat(buffer.getInt()); } if(i == 2) { gender = buffer.getInt(); } if(i == 2) { birthday = buffer.getInt(); } if(i == 2) { heightUnit = buffer.getInt(); } if(i == 2) { weightUnit = buffer.getInt(); } if(i == 2) { distanceUnit = buffer.getInt(); } if(i == 2) { activity = buffer.getInt(); } } else { break; } } profileData = new ProfileData(timeStamp, age, height, weight, gender, birthday, heightUnit, weightUnit, distanceUnit, activity); Date date = new Date(timeStamp); Log.d(LOG_TAG, "time stamp: " + timeStamp); Log.d(LOG_TAG, "date: " + date); Log.d(LOG_TAG, "age: " + age); Log.d(LOG_TAG, "height: " + height + OpenFitData.getHeightUnit(heightUnit)); Log.d(LOG_TAG, "weight: " + weight + OpenFitData.getWeightUnit(weightUnit)); Log.d(LOG_TAG, "gender: " + OpenFitData.getGender(gender)); Log.d(LOG_TAG, "activity: " + activity); Log.d(LOG_TAG, "birthday: " + birthday); Log.d(LOG_TAG, "distanceUnit: " + OpenFitData.getDistanceUnit(distanceUnit)); } public static void parsePedoInfo(ByteBuffer buffer) { int pedometerSize = buffer.getInt(); Log.d(LOG_TAG, "Pedometer info size: " + pedometerSize); Calendar cal = Calendar.getInstance(); int pedometerTotalSteps = 0; float pedometerTotalDistance = 0; float pedometerTotalCalorie = 0; int currentDay = 0; int dailySteps = 0; float dailyDistance = 0; float dailyCalorie = 0; for(int i = 0; i < pedometerSize; i++) { long timeStamp = buffer.getInt() * 1000L; int step = buffer.getInt(); float distance = Float.intBitsToFloat(buffer.getInt()); float calorie = Float.intBitsToFloat(buffer.getInt()); Date date = new Date(timeStamp); cal.setTime(date); int day = cal.get(Calendar.DAY_OF_MONTH); if(day != currentDay) { currentDay = day; if(i == 0) { dailySteps += step; dailyDistance += distance; dailyCalorie += calorie; } else if(i == (pedometerSize - 1)) { pedometerDailyList.add(new PedometerData(timeStamp, dailySteps, dailyDistance, dailyCalorie)); } else { pedometerDailyList.add(new PedometerData(timeStamp, dailySteps, dailyDistance, dailyCalorie)); dailySteps = 0; dailyDistance = 0; dailyCalorie = 0; dailySteps += step; dailyDistance += distance; dailyCalorie += calorie; } } else { dailySteps += step; dailyDistance += distance; dailyCalorie += calorie; } pedometerTotalSteps += step; pedometerTotalDistance += distance; pedometerTotalCalorie += calorie; pedometerList.add(new PedometerData(timeStamp, step, distance, calorie)); } long timeEnd = pedometerList.get(pedometerList.size() - 1).getTimeStampEnd(); Date now = new Date(); if(timeEnd > now.getTime()) { Log.d(LOG_TAG, "Last time " + new Date(timeEnd) + " cutted to " + now); pedometerList.get(pedometerList.size() - 1).setTimeStampEnd(now.getTime()); } pedometerTotal = new PedometerTotal(pedometerTotalSteps, pedometerTotalDistance, pedometerTotalCalorie); Log.d(LOG_TAG, "totalSteps: " + pedometerTotal.getSteps()); Log.d(LOG_TAG, "totalDistance: " + pedometerTotal.getDistance()); Log.d(LOG_TAG, "totalCalorie: " + pedometerTotal.getCalories()); } @SuppressWarnings("unused") public static void parseSleepInfo(ByteBuffer buffer) { int sleepSize = buffer.getInt(); Log.d(LOG_TAG, "Sleep info size: " + sleepSize); for(int i = 0; i < sleepSize; i++) { int index = buffer.getInt(); long timeStamp = buffer.getInt() * 1000L; int status = buffer.getInt(); Date date = new Date(timeStamp); sleepInfoList.add(new SleepInfo(index, timeStamp, status)); /*Log.d(LOG_TAG, "idex: " + index); Log.d(LOG_TAG, "date: " + date.toString()); Log.d(LOG_TAG, "status: " + status);*/ } } public static void parseSleepResultRecord(ByteBuffer buffer) { int sleepSize = buffer.getInt(); Log.d(LOG_TAG, "Sleep result record size: " + sleepSize); for(int i = 0; i < sleepSize; i++) { long startTimeStamp = buffer.getInt() * 1000L; long endTimeStamp = buffer.getInt() * 1000L; float efficiency = buffer.getFloat(); int index = buffer.getInt(); int len = buffer.getInt(); Date startDate = new Date(startTimeStamp); Date endDate = new Date(endTimeStamp); sleepList.add(new SleepData(startTimeStamp, endTimeStamp, efficiency, index, len)); /*Log.d(LOG_TAG, "index: " + index); Log.d(LOG_TAG, "startDate: " + startDate.toString()); Log.d(LOG_TAG, "endDate: " + endDate.toString()); Log.d(LOG_TAG, "efficiency: " + efficiency); Log.d(LOG_TAG, "len: " + len);*/ } } public static void parsePedometerProfile(ByteBuffer buffer) { int index = buffer.getInt(); long n = buffer.getInt() * 1000L; int n2 = buffer.getInt(); if(!buffer.hasRemaining()) { return; } long n3 = buffer.getInt() * 1000L; Date timeStamp = new Date(n); int goal = n2; Date pedometer = new Date(n3); /*Log.d(LOG_TAG, "index: " + index); Log.d(LOG_TAG, "timeStamp: " + timeStamp); Log.d(LOG_TAG, "goal: " + goal); Log.d(LOG_TAG, "pedometer: " + pedometer);*/ } public static void parsePedoResultRecord(ByteBuffer buffer) { Log.d(LOG_TAG, "Pedometer Goal History"); logBuffer(buffer); /*int n = buffer.getInt(); int n2 = n + 1; for (n = 1; n < n2; ++n) { long n3 = buffer.getInt() * 1000L; int n4 = buffer.getInt(); Date timeStamp = new Date(n3); Log.d(LOG_TAG, "timeStamp: " + timeStamp); Log.d(LOG_TAG, "goal: " + n4); }*/ } public static void parseHeartrateResultRecord(ByteBuffer buffer) { Log.d(LOG_TAG, "Heartrater result record"); int n = buffer.getInt(); for (int i = 0; i < n; ++i) { long date = buffer.getInt() * 1000L; int hr = buffer.getInt(); Date timeStamp = new Date(date); heartRateList.add(new HeartRateData(date, hr)); Log.d(LOG_TAG, "timeStamp: " + timeStamp); Log.d(LOG_TAG, "heartRate: " + hr); } } public static void parseCoachingVars(ByteBuffer buffer) { Log.d(LOG_TAG, "Coaching vars"); int ac = buffer.getInt(); byte maxHeartrate = buffer.get(); long maxMET = buffer.getLong(); int recovery = buffer.getInt(); long startDate = buffer.getLong() * 1000L; int trainingLevel = buffer.getInt(); long lastTrainingLevel = buffer.getLong(); int previousToPrevious = buffer.getInt(); int previousTrainingLevel = buffer.getInt(); byte lastestFeedbackPhraseNumber = buffer.get(); long lastestExerciseTime = buffer.getLong() * 1000L; /*Log.d(LOG_TAG, "ac: " + ac); Log.d(LOG_TAG, "maxHeartrate: " + maxHeartrate); Log.d(LOG_TAG, "maxMET: " + maxMET); Log.d(LOG_TAG, "recovery: " + recovery); Log.d(LOG_TAG, "timeStamp: " + new Date(startDate)); Log.d(LOG_TAG, "trainingLevel: " + trainingLevel); Log.d(LOG_TAG, "lastTrainingLevel: " + lastTrainingLevel); Log.d(LOG_TAG, "previousToPrevious: " + previousToPrevious); Log.d(LOG_TAG, "previousTrainingLevel: " + previousTrainingLevel); Log.d(LOG_TAG, "lastestFeedbackPhraseNumber: " + lastestFeedbackPhraseNumber); Log.d(LOG_TAG, "lastestExerciseTime: " + new Date(lastestExerciseTime));*/ } public static void parseCoachingExerciseResult(ByteBuffer buffer) { int exerciseSize = buffer.getInt(); Log.d(LOG_TAG, "Coaching exercise result size: " + exerciseSize); for(int i = 0; i < exerciseSize; i++) { long endTime = buffer.getLong() * 1000L; double distance = buffer.getDouble(); int trainingLoadPeak = buffer.getInt(); int maxMET = buffer.getInt(); int recovery = buffer.getInt(); /*Log.d(LOG_TAG, "endTime: " + new Date(endTime)); Log.d(LOG_TAG, "distance: " + distance); Log.d(LOG_TAG, "trainingLoadPeak: " + trainingLoadPeak); Log.d(LOG_TAG, "maxMET: " + maxMET); Log.d(LOG_TAG, "recovery: " + recovery);*/ } } public static void parseCoachingResultRecord(ByteBuffer buffer) { int exerciseSize = buffer.getInt(); Log.d(LOG_TAG, "Coaching result record size: " + exerciseSize); for(int i = 0; i < exerciseSize; i++) { long timeStamp = buffer.getInt() * 1000L; long duration = buffer.getInt(); float calorie = buffer.getFloat(); int heartrate = buffer.getInt(); float distance = buffer.getFloat(); byte fitnessLevel = buffer.get(); int type = buffer.getInt(); float avgSpeed = buffer.getFloat(); float maxSpeed = buffer.getFloat(); float maxAlt = buffer.getFloat(); float minAlt = buffer.getFloat(); int maxHeartrate = buffer.getInt(); float inclinedDistance = buffer.getFloat(); float declinedDistance = buffer.getFloat(); exerciseDataList.add(new ExerciseData(timeStamp, duration, calorie, heartrate, distance, fitnessLevel, type, avgSpeed, maxSpeed, maxHeartrate, maxAlt, minAlt, inclinedDistance, declinedDistance)); Log.d(LOG_TAG, "timeStamp: " + new Date(timeStamp)); Log.d(LOG_TAG, "timeStampEnd: " + new Date(timeStamp + duration*1000)); Log.d(LOG_TAG, "type: " + type); /* Log.d(LOG_TAG, "timeStamp: " + new Date(timeStamp)); Log.d(LOG_TAG, "duration: " + duration); Log.d(LOG_TAG, "calorie: " + calorie); Log.d(LOG_TAG, "heartrate: " + heartrate); Log.d(LOG_TAG, "distance: " + distance); Log.d(LOG_TAG, "fitnessLevel: " + fitnessLevel); Log.d(LOG_TAG, "type: " + type); Log.d(LOG_TAG, "avgSpeed: " + avgSpeed); Log.d(LOG_TAG, "maxSpeed: " + maxSpeed); Log.d(LOG_TAG, "maxHeartrate: " + maxHeartrate); Log.d(LOG_TAG, "maxAlt: " + maxAlt); Log.d(LOG_TAG, "minAlt: " + minAlt); Log.d(LOG_TAG, "inclinedDistance: " + inclinedDistance); Log.d(LOG_TAG, "declinedDistance: " + declinedDistance); */ } } @SuppressWarnings("unused") public static void depleteBuffer(ByteBuffer buffer) { while(buffer.hasRemaining()) { byte b = buffer.get(); } } public static void logBuffer(ByteBuffer buffer) { int remaining = buffer.capacity() - buffer.position(); Log.d(LOG_TAG, "Remaining" + remaining); byte[] b = new byte[remaining]; for(int i = 0; i < remaining; i++) { b[i] = buffer.get(); } Log.d(LOG_TAG, "logBuffer:" + OpenFitApi.byteArrayToHexString(b)); } }