package com.tutsplus.googlefit; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; 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.Scope; import com.google.android.gms.common.api.Status; import com.google.android.gms.fitness.Fitness; 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.DataDeleteRequest; import com.google.android.gms.fitness.request.DataReadRequest; import com.google.android.gms.fitness.request.DataUpdateRequest; import com.google.android.gms.fitness.result.DailyTotalResult; import com.google.android.gms.fitness.result.DataReadResult; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, View.OnClickListener { private Button mButtonViewWeek; private Button mButtonViewToday; private Button mButtonAddSteps; private Button mButtonUpdateSteps; private Button mButtonDeleteSteps; private GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); mGoogleApiClient = new GoogleApiClient.Builder(this) .addApi(Fitness.HISTORY_API) .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE)) .addConnectionCallbacks(this) .enableAutoManage(this, 0, this) .build(); } private void initViews() { mButtonViewWeek = (Button) findViewById(R.id.btn_view_week); mButtonViewToday = (Button) findViewById(R.id.btn_view_today); mButtonAddSteps = (Button) findViewById(R.id.btn_add_steps); mButtonUpdateSteps = (Button) findViewById(R.id.btn_update_steps); mButtonDeleteSteps = (Button) findViewById(R.id.btn_delete_steps); mButtonViewWeek.setOnClickListener(this); mButtonViewToday.setOnClickListener(this); mButtonAddSteps.setOnClickListener(this); mButtonUpdateSteps.setOnClickListener(this); mButtonDeleteSteps.setOnClickListener(this); } public void onConnected(@Nullable Bundle bundle) { Log.e("HistoryAPI", "onConnected"); } //In use, call this every 30 seconds in active mode, 60 in ambient on watch faces private void displayStepDataForToday() { DailyTotalResult result = Fitness.HistoryApi.readDailyTotal( mGoogleApiClient, DataType.TYPE_STEP_COUNT_DELTA ).await(1, TimeUnit.MINUTES); showDataSet(result.getTotal()); } private void displayLastWeeksData() { Calendar cal = Calendar.getInstance(); Date now = new Date(); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.add(Calendar.WEEK_OF_YEAR, -1); long startTime = cal.getTimeInMillis(); java.text.DateFormat dateFormat = DateFormat.getDateInstance(); Log.e("History", "Range Start: " + dateFormat.format(startTime)); Log.e("History", "Range End: " + dateFormat.format(endTime)); //Check how many steps were walked and recorded in the last 7 days DataReadRequest readRequest = new DataReadRequest.Builder() .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA) .bucketByTime(1, TimeUnit.DAYS) .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS) .build(); DataReadResult dataReadResult = Fitness.HistoryApi.readData(mGoogleApiClient, readRequest).await(1, TimeUnit.MINUTES); //Used for aggregated data if (dataReadResult.getBuckets().size() > 0) { Log.e("History", "Number of buckets: " + dataReadResult.getBuckets().size()); for (Bucket bucket : dataReadResult.getBuckets()) { List<DataSet> dataSets = bucket.getDataSets(); for (DataSet dataSet : dataSets) { showDataSet(dataSet); } } } //Used for non-aggregated data else if (dataReadResult.getDataSets().size() > 0) { Log.e("History", "Number of returned DataSets: " + dataReadResult.getDataSets().size()); for (DataSet dataSet : dataReadResult.getDataSets()) { showDataSet(dataSet); } } } private void showDataSet(DataSet dataSet) { Log.e("History", "Data returned for Data type: " + dataSet.getDataType().getName()); DateFormat dateFormat = DateFormat.getDateInstance(); DateFormat timeFormat = DateFormat.getTimeInstance(); for (DataPoint dp : dataSet.getDataPoints()) { Log.e("History", "Data point:"); Log.e("History", "\tType: " + dp.getDataType().getName()); Log.e("History", "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS))); Log.e("History", "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS))); for(Field field : dp.getDataType().getFields()) { Log.e("History", "\tField: " + field.getName() + " Value: " + dp.getValue(field)); } } } private void addStepDataToGoogleFit() { //Adds steps spread out evenly from start time to end time Calendar cal = Calendar.getInstance(); Date now = new Date(); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.add(Calendar.HOUR_OF_DAY, -1); long startTime = cal.getTimeInMillis(); DataSource dataSource = new DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setName("Step Count") .setType(DataSource.TYPE_RAW) .build(); int stepCountDelta = 1000000; DataSet dataSet = DataSet.create(dataSource); DataPoint point = dataSet.createDataPoint() .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS); point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta); dataSet.add(point); Status status = Fitness.HistoryApi.insertData(mGoogleApiClient, dataSet).await(1, TimeUnit.MINUTES); if (!status.isSuccess()) { Log.e( "History", "Problem with inserting data: " + status.getStatusMessage()); } else { Log.e( "History", "data inserted" ); } } private void updateStepDataOnGoogleFit() { //If two entries overlap, the new data is dropped when trying to insert. Instead, you need to use update Calendar cal = Calendar.getInstance(); Date now = new Date(); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.add(Calendar.HOUR_OF_DAY, -1); long startTime = cal.getTimeInMillis(); DataSource dataSource = new DataSource.Builder() .setAppPackageName(this) .setDataType(DataType.TYPE_STEP_COUNT_DELTA) .setName("Step Count") .setType(DataSource.TYPE_RAW) .build(); int stepCountDelta = 2000000; DataSet dataSet = DataSet.create(dataSource); DataPoint point = dataSet.createDataPoint() .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS); point.getValue(Field.FIELD_STEPS).setInt(stepCountDelta); dataSet.add(point); DataUpdateRequest updateRequest = new DataUpdateRequest.Builder().setDataSet(dataSet).setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS).build(); Fitness.HistoryApi.updateData(mGoogleApiClient, updateRequest).await(1, TimeUnit.MINUTES); } private void deleteStepDataOnGoogleFit() { Calendar cal = Calendar.getInstance(); Date now = new Date(); cal.setTime(now); long endTime = cal.getTimeInMillis(); cal.add(Calendar.DAY_OF_YEAR, -1); long startTime = cal.getTimeInMillis(); DataDeleteRequest request = new DataDeleteRequest.Builder() .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS) .addDataType(DataType.TYPE_STEP_COUNT_DELTA) .build(); Fitness.HistoryApi.deleteData(mGoogleApiClient, request).await(1, TimeUnit.MINUTES); } @Override public void onConnectionSuspended(int i) { Log.e("HistoryAPI", "onConnectionSuspended"); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Log.e("HistoryAPI", "onConnectionFailed"); } @Override public void onClick(View v) { switch(v.getId()) { case R.id.btn_view_week: { new ViewWeekStepCountTask().execute(); break; } case R.id.btn_view_today: { new ViewTodaysStepCountTask().execute(); break; } case R.id.btn_add_steps: { new AddStepsToGoogleFitTask().execute(); break; } case R.id.btn_update_steps: { new UpdateStepsOnGoogleFitTask().execute(); break; } case R.id.btn_delete_steps: { new DeleteYesterdaysStepsTask().execute(); break; } } } private class ViewWeekStepCountTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { displayLastWeeksData(); return null; } } private class ViewTodaysStepCountTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { displayStepDataForToday(); return null; } } private class AddStepsToGoogleFitTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { addStepDataToGoogleFit(); displayLastWeeksData(); return null; } } private class UpdateStepsOnGoogleFitTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { updateStepDataOnGoogleFit(); displayLastWeeksData(); return null; } } private class DeleteYesterdaysStepsTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { deleteStepDataOnGoogleFit(); displayLastWeeksData(); return null; } } }