Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add includeBmrAvg #298

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 77 additions & 27 deletions android/src/main/java/com/reactnative/googlefit/CalorieHistory.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessOptions;
import com.google.android.gms.fitness.data.Bucket;
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.request.DataReadRequest;
import com.google.android.gms.fitness.result.DataReadResponse;
import com.google.android.gms.fitness.result.DataReadResult;

import org.json.JSONObject;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;

import java.text.DateFormat;
import java.text.Format;
Expand All @@ -54,7 +57,7 @@ public CalorieHistory(ReactContext reactContext, GoogleFitManager googleFitManag
this.googleFitManager = googleFitManager;
}

public ReadableArray aggregateDataByDate(long startTime, long endTime, boolean basalCalculation, int bucketInterval, String bucketUnit) {
public ReadableArray aggregateDataByDate(long startTime, long endTime, boolean includeBmrAvg, int bucketInterval, String bucketUnit) {

DateFormat dateFormat = DateFormat.getDateInstance();
Log.i(TAG, "Range Start: " + dateFormat.format(startTime));
Expand All @@ -78,15 +81,15 @@ public ReadableArray aggregateDataByDate(long startTime, long endTime, boolean b
for (Bucket bucket : dataReadResult.getBuckets()) {
List<DataSet> dataSets = bucket.getDataSets();
for (DataSet dataSet : dataSets) {
processDataSet(dataSet, map, basalCalculation);
processDataSet(dataSet, map, includeBmrAvg);
}
}
}
//Used for non-aggregated data
else if (dataReadResult.getDataSets().size() > 0) {
Log.i(TAG, "Number of returned DataSets: " + dataReadResult.getDataSets().size());
for (DataSet dataSet : dataReadResult.getDataSets()) {
processDataSet(dataSet, map, basalCalculation);
processDataSet(dataSet, map, includeBmrAvg);
}
}

Expand All @@ -95,24 +98,23 @@ else if (dataReadResult.getDataSets().size() > 0) {


// utility function that gets the basal metabolic rate averaged over a week
private float getBasalAVG(long _et) throws Exception {
private float getBasalAVG(long endTime) throws Exception {
float basalAVG = 0;
Calendar cal = java.util.Calendar.getInstance();
cal.setTime(new Date(_et));
Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(new Date(endTime));
//set start time to a week before end time
cal.add(Calendar.WEEK_OF_YEAR, -1);
long nst = cal.getTimeInMillis();
calendar.add(Calendar.DAY_OF_YEAR, -1);
long startTime = calendar.getTimeInMillis();

DataReadRequest.Builder builder = new DataReadRequest.Builder();
builder.aggregate(DataType.TYPE_BASAL_METABOLIC_RATE, DataType.AGGREGATE_BASAL_METABOLIC_RATE_SUMMARY);
builder.bucketByTime(1, TimeUnit.DAYS);
builder.setTimeRange(nst, _et, TimeUnit.MILLISECONDS);
builder.bucketByTime(1, TimeUnit.HOURS);
builder.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS);
DataReadRequest readRequest = builder.build();

DataReadResult dataReadResult = Fitness.HistoryApi.readData(googleFitManager.getGoogleApiClient(), readRequest).await();

if (dataReadResult.getStatus().isSuccess()) {
JSONObject obj = new JSONObject();
if (dataReadResult.getStatus().isSuccess()) { ;
int avgsN = 0;
for (Bucket bucket : dataReadResult.getBuckets()) {
// in the com.google.bmr.summary data type, each data point represents
Expand All @@ -130,40 +132,88 @@ private float getBasalAVG(long _et) throws Exception {
} else throw new Exception(dataReadResult.getStatus().getStatusMessage());
}

private float getActivityCal(long startTime, long endTime) throws Exception {
float activityCal = 0.0f;

DataReadRequest readRequest = new DataReadRequest.Builder()
.aggregate(DataType.TYPE_ACTIVITY_SEGMENT)
.aggregate(DataType.TYPE_CALORIES_EXPENDED)
.bucketByActivitySegment(1, TimeUnit.SECONDS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();

FitnessOptions fitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_ACTIVITY_SEGMENT, FitnessOptions.ACCESS_READ)
.addDataType(DataType.TYPE_CALORIES_EXPENDED, FitnessOptions.ACCESS_READ)
.build();

private void processDataSet(DataSet dataSet, WritableArray map, boolean basalCalculation) {
GoogleSignInAccount googleSignInAccount =
GoogleSignIn.getAccountForExtension(this.mReactContext, fitnessOptions);

try {
Task<DataReadResponse> task = Fitness.getHistoryClient(this.mReactContext, googleSignInAccount)
.readData(readRequest);

DataReadResponse response = Tasks.await(task, 30, TimeUnit.SECONDS);

if (response.getStatus().isSuccess()) {
for (Bucket bucket : response.getBuckets()) {
String activityName = bucket.getActivity();
if (bucket.getDataSets().isEmpty() || activityName.equals("unknown")) continue;
for (DataSet dataSet : bucket.getDataSets()) {
for (DataPoint dataPoint : dataSet.getDataPoints()) {
for (Field field : dataPoint.getDataType().getFields()) {
String fieldName = field.getName();
if (!fieldName.equals("calories")) continue;
activityCal += dataPoint.getValue(field).asFloat();
}
}
}
}
} else {
Log.w(TAG, "There was an error reading data from Google Fit" + response.getStatus().toString());
}
} catch (Exception e) {
Log.w(TAG, "Exception: " + e);
}
return activityCal;
}

private void processDataSet(DataSet dataSet, WritableArray map, boolean includeBmrAvg) {
Log.i(TAG, "Data returned for Data type: " + dataSet.getDataType().getName());
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat timeFormat = DateFormat.getTimeInstance();
Format formatter = new SimpleDateFormat("EEE");
WritableMap stepMap = Arguments.createMap();


for (DataPoint dp : dataSet.getDataPoints()) {
long startTime = dp.getStartTime(TimeUnit.MILLISECONDS);
long endTime = dp.getEndTime(TimeUnit.MILLISECONDS);
Log.i(TAG, "Data point:");
Log.i(TAG, "\tType: " + dp.getDataType().getName());
Log.i(TAG, "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
Log.i(TAG, "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
Log.i(TAG, "\tStart: " + dateFormat.format(startTime) + " " + timeFormat.format(startTime));
Log.i(TAG, "\tEnd: " + dateFormat.format(endTime) + " " + timeFormat.format(endTime));

String day = formatter.format(new Date(dp.getStartTime(TimeUnit.MILLISECONDS)));
String day = formatter.format(new Date(startTime));
Log.i(TAG, "Day: " + day);

for (Field field : dp.getDataType().getFields()) {
Log.i("History", "\tField: " + field.getName() +
" Value: " + dp.getValue(field));

stepMap.putString("day", day);
stepMap.putDouble("startDate", dp.getStartTime(TimeUnit.MILLISECONDS));
stepMap.putDouble("endDate", dp.getEndTime(TimeUnit.MILLISECONDS));
float basal = 0;
if (basalCalculation) {
stepMap.putDouble("startDate", startTime);
stepMap.putDouble("endDate", endTime);
float calorie = 0.0f;
if (!includeBmrAvg) {
try {
basal = getBasalAVG(dp.getEndTime(TimeUnit.MILLISECONDS));
calorie = getActivityCal(startTime, endTime);
} catch (Exception e) {
e.printStackTrace();
}
} else {
calorie = dp.getValue(field).asFloat();
}
stepMap.putDouble("calorie", dp.getValue(field).asFloat() - basal);
stepMap.putDouble("calorie", calorie);
map.pushMap(stepMap);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,13 @@ public void saveHeight(ReadableMap heightSample,
@ReactMethod
public void getDailyCalorieSamples(double startDate,
double endDate,
boolean basalCalculation,
boolean includeBmrAvg,
int bucketInterval,
String bucketUnit,
Promise promise) {

try {
promise.resolve(mGoogleFitManager.getCalorieHistory().aggregateDataByDate((long) startDate, (long) endDate, basalCalculation, bucketInterval, bucketUnit));
promise.resolve(mGoogleFitManager.getCalorieHistory().aggregateDataByDate((long) startDate, (long) endDate, includeBmrAvg, bucketInterval, bucketUnit));
} catch (IllegalViewOperationException e) {
promise.reject(e);
}
Expand Down
6 changes: 3 additions & 3 deletions index.android.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ declare module 'react-native-google-fit' {
) => Promise<MoveMinutesResponse[]>;
/**
* Get the total calories per day over a specified date range.
* @param {Object} options getDailyCalorieSamples accepts an options object containing required startDate: ISO8601Timestamp and endDate: ISO8601Timestamp. optional basalCalculation - {true || false} should we substract the basal metabolic rate averaged over a week
* @param {Object} options getDailyCalorieSamples accepts an options object containing required startDate: ISO8601Timestamp and endDate: ISO8601Timestamp. optional includeBmrAvg - {true || false} should we include the basal metabolic rate averaged over a week
*/
getDailyCalorieSamples: (
options: StartAndEndDate & { basalCalculation?: boolean } & Partial<BucketOptions>
getDailyCalorieSamples: (
options: StartAndEndDate & { includeBmrAvg?: boolean } & Partial<BucketOptions>
) => Promise<CalorieResponse[]>;

getDailyNutritionSamples: (
Expand Down
10 changes: 4 additions & 6 deletions index.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,15 @@ class RNGoogleFit {
* Get the total calories per day over a specified date range.
* @param {Object} options getDailyCalorieSamples accepts an options object containing:
* required startDate: ISO8601Timestamp and endDate: ISO8601Timestamp
* optional basalCalculation - {true || false} should we substract the basal metabolic rate averaged over a week
* optional includeBmrAvg- {true || false} should we include the basal metabolic rate averaged over a week
*/

getDailyCalorieSamples = async (options) => {
const basalCalculation = options.basalCalculation !== false
const { startDate, endDate, bucketInterval, bucketUnit } = prepareInput(options);

getDailyCalorieSamples = async ({ includeBmrAvg = true, ...restOptions }) => {
const { startDate, endDate, bucketInterval, bucketUnit } = prepareInput(restOptions);
const result = await googleFit.getDailyCalorieSamples(
startDate,
endDate,
basalCalculation,
includeBmrAvg,
bucketInterval,
bucketUnit,
);
Expand Down