Giter Club home page Giter Club logo

fit-samples's Introduction

Android Fit Samples Repository

The Google Fit APIs, including the Google Fit REST API, will no longer be available after June 30, 2025. As of May 1, 2024, developers cannot sign up to use these APIs.

For instructions on which API or platform to migrate to, visit the Health Connect migration guide. For a comparison of Health Connect with the Google Fit APIs and the Fitbit Web APIs, visit the Health Connect comparison guide.

Learn more about Health Connect and how to integrate with the API.


This repository contains a set of individual Android Studio projects to help you get started writing/understanding Fit features in Android.

fit-samples's People

Contributors

breanatate avatar codingjeremy avatar garanj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fit-samples's Issues

Not getting data as well as getting steps not set error

Hi,
I am getting an error where i am not recieving any data from the google fit api, I have copied the same code that is used in this github and still arent getting any data. Also, When i click the update steps button on the menu my app crashes and says " java.lang.IllegalArgumentException: steps not set
at com.google.android.gms.fitness.data.DataSet.zzb(com.google.android.gms:play-services-fitness@@18.0.0:115)
at com.google.android.gms.fitness.data.DataSet.add(com.google.android.gms:play-services-fitness@@18.0.0:43)
at lirik.myapplication.ShowActivityData.updateFitnessData(ShowActivityData.java:424)
at lirik.myapplication.ShowActivityData.updateData(ShowActivityData.java:351)
at lirik.myapplication.ShowActivityData.updateAndReadData(ShowActivityData.java:335)"

here is my code:

``
/**

  • This sample demonstrates how to use the History API of the Google Fit platform to insert data,

  • query against existing data, and remove data. It also demonstrates how to authenticate a user

  • with Google Play Services and how to properly represent data in a {@link DataSet}.
    */
    public class ShowActivityData extends AppCompatActivity {
    private ArrayList personalStepData = new ArrayList<>();

    public static final String TAG = "BasicHistoryApi";
    // Identifier to identify the sign in activity.
    private static final int REQUEST_OAUTH_REQUEST_CODE = 1;

    @OverRide
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_show_data);
    // This method sets up our custom logger, which will print all log messages to the device
    // screen, as well as to adb logcat.
    initializeLogging();

     FitnessOptions fitnessOptions =
             FitnessOptions.builder()
                     .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
                     .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
                     .build();
     if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) {
         GoogleSignIn.requestPermissions(
                 this,
                 REQUEST_OAUTH_REQUEST_CODE,
                 GoogleSignIn.getLastSignedInAccount(this),
                 fitnessOptions);
     } else {
         insertAndReadData();
     }
    

    }

    @OverRide
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
    if (requestCode == REQUEST_OAUTH_REQUEST_CODE) {
    insertAndReadData();
    }
    }
    }

    /**

    • Inserts and reads data by chaining {@link Task} from {@link #insertData()} and {@link
    • #readHistoryData()}.
      */
      private void insertAndReadData() {
      insertData()
      .continueWithTask(
      new Continuation<Void, Task>() {
      @OverRide
      public Task then(@nonnull Task task) throws Exception {
      return readHistoryData();
      }
      });
      }

    /** Creates a {@link DataSet} and inserts it into user's Google Fit history. */
    private Task insertData() {
    // Create a new dataset and insertion request.
    DataSet dataSet = insertFitnessData();

     // Then, invoke the History API to insert the data.
     Log.i(TAG, "Inserting the dataset in the History API.");
     return Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
             .insertData(dataSet)
             .addOnCompleteListener(
                     new OnCompleteListener<Void>() {
                         @Override
                         public void onComplete(@NonNull Task<Void> task) {
                             if (task.isSuccessful()) {
                                 // At this point, the data has been inserted and can be read.
                                 Log.i(TAG, "Data insert was successful!");
                             } else {
                                 Log.e(TAG, "There was a problem inserting the dataset.", task.getException());
                             }
                         }
                     });
    

    }

    /**

    • Asynchronous task to read the history data. When the task succeeds, it will print out the data.
      */
      private Task readHistoryData() {
      // Begin by creating the query.
      DataReadRequest readRequest = queryFitnessData();

      // Invoke the History API to fetch the data with the query
      return Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
      .readData(readRequest)
      .addOnSuccessListener(
      new OnSuccessListener() {
      @OverRide
      public void onSuccess(DataReadResponse dataReadResponse) {
      // For the sake of the sample, we'll print the data so we can see what we just
      // added. In general, logging fitness information should be avoided for privacy
      // reasons.
      printData(dataReadResponse);
      }
      })
      .addOnFailureListener(
      new OnFailureListener() {
      @OverRide
      public void onFailure(@nonnull Exception e) {
      Log.e(TAG, "There was a problem reading the data.", e);
      }
      });
      }

    /**

    • Creates and returns a {@link DataSet} of step count data for insertion using the History API.
      */
      private DataSet insertFitnessData() {
      Log.i(TAG, "Creating a new data insert request.");

      // [START build_insert_data_request]
      // Set a start and end time for our data, using a start time of 1 hour before this moment.
      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();

      // Create a data source
      DataSource dataSource =
      new DataSource.Builder()
      .setAppPackageName(this)
      .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
      .setStreamName(TAG + " - step count")
      .setType(DataSource.TYPE_RAW)
      .build();

      // Create a data set
      int stepCountDelta = 950;
      DataSet dataSet = DataSet.create(dataSource);
      // For each data point, specify a start time, end time, and the data value -- in this case,
      // the number of new steps.
      DataPoint dataPoint =
      dataSet.createDataPoint().setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
      dataPoint.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
      dataSet.add(dataPoint);
      // [END build_insert_data_request]

      return dataSet;
      }

    /** Returns a {@link DataReadRequest} for all step count changes in the past week. */
    public static DataReadRequest queryFitnessData() {
    // [START build_read_data_request]
    // Setting a start and end date using a range of 1 week before this moment.
    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 = getDateInstance();
     Log.i(TAG, "Range Start: " + dateFormat.format(startTime));
     Log.i(TAG, "Range End: " + dateFormat.format(endTime));
    
     DataReadRequest readRequest =
             new DataReadRequest.Builder()
                     // The data request can specify multiple data types to return, effectively
                     // combining multiple data queries into one call.
                     // In this example, it's very unlikely that the request is for several hundred
                     // datapoints each consisting of a few steps and a timestamp.  The more likely
                     // scenario is wanting to see how many steps were walked per day, for 7 days.
                     .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
                     // Analogous to a "Group By" in SQL, defines how data should be aggregated.
                     // bucketByTime allows for a time span, whereas bucketBySession would allow
                     // bucketing by "sessions", which would need to be defined in code.
                     .bucketByTime(1, TimeUnit.DAYS)
                     .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                     .build();
     // [END build_read_data_request]
    
     return readRequest;
    

    }

    /**

    • Logs a record of the query result. It's possible to get more constrained data sets by
    • specifying a data source or data type, but for demonstrative purposes here's how one would dump
    • all the data. In this sample, logging also prints to the device screen, so we can see what the
    • query returns, but your app should not log fitness information as a privacy consideration. A
    • better option would be to dump the data you receive to a local data directory to avoid exposing
    • it to other applications.
      */
      public static void printData(DataReadResponse dataReadResult) {
      // [START parse_read_data_result]
      // If the DataReadRequest object specified aggregated data, dataReadResult will be returned
      // as buckets containing DataSets, instead of just DataSets.
      if (dataReadResult.getBuckets().size() > 0) {
      Log.i(
      TAG, "Number of returned buckets of DataSets is: " + dataReadResult.getBuckets().size());
      for (Bucket bucket : dataReadResult.getBuckets()) {
      List dataSets = bucket.getDataSets();
      for (DataSet dataSet : dataSets) {
      dumpDataSet(dataSet);
      }
      }
      } else if (dataReadResult.getDataSets().size() > 0) {
      Log.i(TAG, "Number of returned DataSets is: " + dataReadResult.getDataSets().size());
      for (DataSet dataSet : dataReadResult.getDataSets()) {
      dumpDataSet(dataSet);
      }
      }
      // [END parse_read_data_result]
      }

    // [START parse_dataset]
    private static void dumpDataSet(DataSet dataSet) {
    //Log.i(TAG, "Data returned for Data type: " + dataSet.getDataType().getName());
    DateFormat dateFormat = getTimeInstance();

     for (DataPoint dp : dataSet.getDataPoints()) {
         Log.i(TAG, "Data point:");
         Log.i(TAG, "\tType: " + dp.getDataType().getName());
         Log.i(TAG, "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
         Log.i(TAG, "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)));
         for (Field field : dp.getDataType().getFields()) {
             Log.i(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field));
         }
     }
    

    }
    // [END parse_dataset]

    /**

    • Deletes a {@link DataSet} from the History API. In this example, we delete all step count data

    • for the past 24 hours.
      */
      private void deleteData() {
      Log.i(TAG, "Deleting today's step count data.");

      // [START delete_dataset]
      // Set a start and end time for our data, using a start time of 1 day before this moment.
      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();

      // Create a delete request object, providing a data type and a time interval
      DataDeleteRequest request =
      new DataDeleteRequest.Builder()
      .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
      .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
      .build();

      // Invoke the History API with the HistoryClient object and delete request, and then
      // specify a callback that will check the result.
      Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
      .deleteData(request)
      .addOnCompleteListener(
      new OnCompleteListener() {
      @OverRide
      public void onComplete(@nonnull Task task) {
      if (task.isSuccessful()) {
      Log.i(TAG, "Successfully deleted today's step count data.");
      } else {
      Log.e(TAG, "Failed to delete today's step count data.", task.getException());
      }
      }
      });
      }

    /**

    • Updates and reads data by chaning {@link Task} from {@link #updateData()} and {@link
    • #readHistoryData()}.
      */
      private void updateAndReadData() {
      updateData()
      .continueWithTask(
      new Continuation<Void, Task>() {
      @OverRide
      public Task then(@nonnull Task task) throws Exception {
      return readHistoryData();
      }
      });
      }

    /**

    • Creates a {@link DataSet},then makes a {@link DataUpdateRequest} to update step data. Then

    • invokes the History API with the HistoryClient object and update request.
      */
      private Task updateData() {
      // Create a new dataset and update request.
      DataSet dataSet = updateFitnessData();
      long startTime = 0;
      long endTime = 0;

      // Get the start and end times from the dataset.
      for (DataPoint dataPoint : dataSet.getDataPoints()) {
      startTime = dataPoint.getStartTime(TimeUnit.MILLISECONDS);
      endTime = dataPoint.getEndTime(TimeUnit.MILLISECONDS);
      }

      // [START update_data_request]
      Log.i(TAG, "Updating the dataset in the History API.");

      DataUpdateRequest request =
      new DataUpdateRequest.Builder()
      .setDataSet(dataSet)
      .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
      .build();

      // Invoke the History API to update data.
      return Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
      .updateData(request)
      .addOnCompleteListener(
      new OnCompleteListener() {
      @OverRide
      public void onComplete(@nonnull Task task) {
      if (task.isSuccessful()) {
      // At this point the data has been updated and can be read.
      Log.i(TAG, "Data update was successful.");
      } else {
      Log.e(TAG, "There was a problem updating the dataset.", task.getException());
      }
      }
      });
      }

    /** Creates and returns a {@link DataSet} of step count data to update. */
    private DataSet updateFitnessData() {
    Log.i(TAG, "Creating a new data update request.");

     // [START build_update_data_request]
     // Set a start and end time for the data that fits within the time range
     // of the original insertion.
     Calendar cal = Calendar.getInstance();
     Date now = new Date();
     cal.setTime(now);
     cal.add(Calendar.MILLISECOND, 0);
     long endTime = cal.getTimeInMillis();
     cal.add(Calendar.MILLISECOND, -50);
     long startTime = cal.getTimeInMillis();
    
     // Create a data source
     DataSource dataSource =
             new DataSource.Builder()
                     .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
                     .setType(DataSource.TYPE_DERIVED)
                     .setStreamName("estimated_steps")
                     .setAppPackageName("com.google.android.gms")
                     .build();
    
     // Create a data set
    
     DataSet dataSet = DataSet.create(dataSource);
     int stepCountDelta = 1000;
     // For each data point, specify a start time, end time, and the data value -- in this case,
     // the number of new steps.
     DataPoint d = DataPoint.builder(dataSource).setTimeInterval(startTime,endTime,TimeUnit.MILLISECONDS).build();
     DataPoint dataPoint = dataSet.createDataPoint().setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS);
     dataPoint.getValue(Field.FIELD_STEPS).setInt(stepCountDelta);
    
     d.getValue(Field.FIELD_STEPS);
     personalStepData.add((d.getValue(Field.FIELD_STEPS).asInt()));
    
     dataSet.add(d);
     // [END build_update_data_request]
    
     return dataSet;
    

    }
    }

How to get heart points?

Issue by TahaNaqvi
Thursday Apr 11, 2019 at 06:51 GMT
Originally opened as googlearchive/android-fit#49


Here is my code :

Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
.readDailyTotalFromLocalDevice(DataType.TYPE_HEART_POINTS)
.addOnSuccessListener(new OnSuccessListener() {
@OverRide
public void onSuccess(DataSet dataSet) {
showDataSet(dataSet);
}
})
.addOnFailureListener(new OnFailureListener() {
@OverRide
public void onFailure(@nonnull Exception e) {
Log.d(LOG_TAG, "onFailure: " + e.getMessage());
}
});

FitnessOptions fitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_HEART_POINTS, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_HEART_POINTS, FitnessOptions.ACCESS_READ)
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.TYPE_DISTANCE_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_DISTANCE_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.TYPE_CALORIES_EXPENDED, FitnessOptions.ACCESS_READ)
.build();

    if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) {
        GoogleSignIn.requestPermissions(
                this, // your activity
                GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                GoogleSignIn.getLastSignedInAccount(this),
                fitnessOptions);
    } else {
        accessGoogleFit();
    }

I am getting this error (5000: Application needs OAuth consent from the user) while I have given permission as mentioned above.

Signed APK doesn't show subsription page.

Issue by saravanan72
Friday May 18, 2018 at 10:30 GMT
Originally opened as googlearchive/android-fit#35


Hi,
I have tried this google fitness API as a sample one. When i am getting apk in debug format, it run perfectly .When i run this , initially it subscribe by using gmail account and provides step count value as i expect. But when i try with signed APK, its doesn't work. It doesn't show the subscription dialog and also the count doesn't show without subscription. Please give solution regarding that. Thanks.

Error

Issue by jaag12
Thursday Nov 16, 2017 at 09:09 GMT
Originally opened as googlearchive/android-fit#28


Error when trying new versions of Google Fit samples,

E/AndroidRuntime: FATAL EXCEPTION: GoogleApiHandler Process: com.google.android.gms.fit.samples.basicrecordingapi, PID: 22949 java.lang.NullPointerException: Attempt to invoke virtual method 'android.accounts.Account com.google.android.gms.auth.api.signin.GoogleSignInAccount.getAccount()' on a null object reference at com.google.android.gms.common.api.GoogleApi.zzagd(Unknown Source) at com.google.android.gms.common.api.GoogleApi.zza(Unknown Source) at com.google.android.gms.common.api.internal.zzbr.<init>(Unknown Source) at com.google.android.gms.common.api.internal.zzbp.zzb(Unknown Source) at com.google.android.gms.common.api.internal.zzbp.handleMessage(Unknown Source) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:158) at android.os.HandlerThread.run(HandlerThread.java:61)

have changed the methods and I have noticed that since then my application using the old methods does not record data for DataType TYPE_ACTIVITY_SEGMENT, TYPE_STEP_COUNT_DELTA and sometimes TYPE_HEART_RATE_BPM. What is the solution?

Data differs from the actual Google Fit App

Issue by sushantgiri
Thursday Aug 24, 2017 at 09:01 GMT
Originally opened as googlearchive/android-fit#25


I am building a fitness application where I pull certain data (Steps and Calories) from google fit. I am fetching a week data. The output of the google fit api doesn't match with the google fit data. The output is so random and doesn't have a definite pattern.

Steps From Google Fit API:
Code Used:
private DataReadRequest queryFitnessData()
{
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 = getDateInstance();
Timber.e("Range Start: " + dateFormat.format(startTime));
Timber.e("Range End: " + dateFormat.format(endTime));
return new DataReadRequest.Builder()
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.build();
}

public Observable getStepsCount(GoogleApiClient googleApiClient) {
return Observable.create(subscriber -> {
DataReadResult result =
Fitness.HistoryApi.readData(googleApiClient, queryFitnessData()).await(1, TimeUnit.MINUTES);
if (result.getStatus().isSuccess()) {
subscriber.onNext(result);
} else {
subscriber.onError(new Exception("Exception"));
}
});
}

Output
Start Date: 17th August 2017 End Date: 24th August 2017

17-18 -> 4080
18-19 -> 3837
19-19 -> 7
20-21 -> 2212
21-22 -> 4665
23-23 -> 2949
23-24 -> 6131

Any help would be greatly appreciated. If required, apk can also be shared.

WearOS error 17: Error resolution was canceled by the user, original error message: INVALID_ACCOUNT: null

In my fork, I have added a WearOS module to BasicRecordingApiKotlin. I have the regular mobile module version working correctly and am able to push and pull data from Google Fit. The Google Fit specific code and OAuth settings on console.developer.google.com are exactly same as the mobile app version however only on WearOS versions am I receiving this error
error 17: Error resolution was canceled by the user, original error message: INVALID_ACCOUNT: null
when running Fitness.getRecordingClient(this, getGoogleAccount()).subscribe(DataType.TYPE_CALORIES_EXPENDED)
always entering onFailureListener.

The main question I have is, is there something specifically different either in code or in app/project setup that needs to be done for WearOS that I'm not doing currently? Or can someone point to a repo that has a working up-to-date Google Fit WearOS Kotlin sample?

My Setup: 
MacOS Catalina 10.15.7
Android Studio: 4.1.1
Kotlin Version: 1.3.61
com.google.android.gms:play-services-fitness: 20.0.0
com.google.android.gms:play-services-auth: 19.0.0

Physical Device: 
TicWatch Pro
System Version: H
WearOS by Google: 2.19
Android security patch level: June 1, 2020

I have also opened a question on stackoverflow.com. It has many screenshots which might be relevant but I thought might not need to be duplicated here

Thanks and I appreciate any help and will add more information if requested or something is unclear.

P.S.: I also got BasicHistorySessionApiKotlin mobile module version working and the added WearOS module gets same error

Getting error in onactivityResult

Hello Everyone

i want to use google fir api after using step counter i am getting result code 0 so how can i fix this issue.

Thanks in advance

is there any way to get the actual create time for a session?

Issue by zjx
Wednesday Jan 16, 2019 at 02:15 GMT
Originally opened as googlearchive/android-fit#46


looks like the fit system will use the end time as the "timestamp" field which may not be the actual create time of a session. For example,

a running session may happened from 13:00 to 14:00 on a third party app but the actual sync to google fit happens on 18:00 triggered by user manually.

my app just want to retrieve the New Sessions since the last read but if can not get the actual create time in the google fit then there is no way to do this?

any suggestions? Thx.

couldnt get account info

Issue by saravanan72
Thursday Mar 08, 2018 at 06:03 GMT
Originally opened as googlearchive/android-fit#31


java.lang.NullPointerException: Attempt to invoke virtual method 'android.accounts.Account com.google.android.gms.auth.api.signin.GoogleSignInAccount.getAccount()' on a null object reference

error caught in step counter

Values that returned from History API is not the same with Google Fit App

Issue by panjiyudasetya
Wednesday Oct 31, 2018 at 05:00 GMT
Originally opened as googlearchive/android-fit#42


What happened

Step count value that I've been received from History API was different with step count values that has been displayed in Fit App. Even problem solving for different values between Fit History Api and Google Fit App has been mentioned here, sometimes this problem still occurred in certain device.

In my case, I was using :

  • Phone HTC One_E8 dual sim
  • Android version 6.0.1
  • Google Play services 14.3.66
Fit API Prober Fit App

As you can see that in Fit API prober, I got 3300 datapoint for today step count, meanwhile in Fit App, 2433 datapoint has been displayed. The margin is quite huge in this case.

What was expected

History API return same value with Google Fit App.

Code Snippets

As for addition, both approach are returning 3300 datapoint rather than 2433 datapoint.

History API today step count
        Fitness.getHistoryClient(mContext, GoogleSignIn.getLastSignedInAccount(mContext))
            .readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
            .addOnSuccessListener(new OnSuccessListener<DataSet>() {
                @Override
                public void onSuccess(DataSet dataSet) {
                    int totalStepCount = extractHistoryFromDataSet(dataSet);
                    callback.onResult(totalStepCount);
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    callback.onError(e.getMessage());
                }
            });
History API through step count aggregation
DataSource getFitStepCountDataSource() {
        return new DataSource.Builder()
                .setDataType(DataType.TYPE_STEP_COUNT_DELTA)
                .setType(DataSource.TYPE_DERIVED)
                .setStreamName("estimated_steps")
                .setAppPackageName("com.google.android.gms")
                .build();
}

Task<DataReadResponse> readHistory(long startTime, long endTime) {
        DataReadRequest request = new DataReadRequest.Builder()
            .aggregate(getFitStepCountDataSource(), DataType.AGGREGATE_STEP_COUNT_DELTA)
            .bucketByTime(1, TimeUnit.DAYS)
            .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
            .enableServerQueries()
            .build();
        return Fitness.getHistoryClient(mContext, GoogleSignIn.getLastSignedInAccount(mContext))
            .readData(request);
}

Error: No permission to read data for this private data source.

Issue by Zaszczyk
Thursday Nov 22, 2018 at 09:13 GMT
Originally opened as googlearchive/android-fit#43


I use Google Fit REST API for over 2 years and everything was fine already. However since 20th November I am occuring the only reply on route:

/me/dataSources/derived:com.google.location.sample:com.google.android.gms:merge_high_fidelity/datasets/

( 'domain' => 'global', 
'reason' => 'forbidden', 
'message' => 'No permission to read data for this private data source.', )

I had not changed anything in my code, did Google change something?

Error : Request code was : 0 for basic history api kotlin

Hi,
I have followed the all the steps to configure this app but every time i get this error and the same steps were followed for different sample apps it seems to work fine except for BasicHistoryApi

E/BasicHistoryApi: There was an error signing into Fit. Check the troubleshooting section of the README
for potential issues.
Request code was: 0
Result code was: 0

Error: Fitness api can't request data for big time intervals [E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!]

Hello! My google fit app doesn't work for 2 months.
I started to debug the application and I was able to find these errors from adb logcat:

2020-11-22 17:04:48.804 16111-16143/? E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 1330200)
E/FitAndroidFutures: While reading data with request: DataReadRequest{bucket by intervals: active_minutes heart_minutes calories.expended distance.delta d:step_count.delta:gms:estimated_steps (2020-11-22 00:00:00 - 2020-11-22 17:04:41) +server}
    him: java.lang.IllegalStateException: hrb: 8: 
        at hii.a(Unknown Source:4)
        at qei.a(PG:2)
        at rhf.e(Unknown Source:2)
        at rhh.run(PG:11)
        at rjp.execute(PG:1)
        at rhv.r(PG:1)
        at rhv.n(PG:11)
        at rhv.l(PG:5)
        at rlm.run(PG:10)
...

Please pay attention to the line "FAILED BINDER TRANSACTION !!! (parcel size = 1330200" - google fit can't get the data from the android service because the response is too large to be returned through IPC.

Also, I'm developing an application that uses the fitness api and also I noticed that gms Task api doesn't return anything and even doesn't call "onComplete" listener in similar cases when google fit service can't deliver the result to a requester.
I think a reading task should be completed anyways if Binder fails for some reason.

Connecting to Google Fit Consent Screen Denying one of multi permissions will not connect.

My app is trying to connect to Google Fit. The user is prompted to pick a Google Account and once picked, the "Consent Screen" shows up requiring users to accept or deny each permission. There are separate screens for each permission. Once the user has gone through each permission pop up to accept or deny, a main screen appears that shows a list of all the permissions with check marks next to the ones that the user had allowed. If the user denies one or more of the permissions, it usually closes the pop up, shows a spinner, and then restarts the consent screen pop ups to force the user to go through each permission pop up and then continues to the main pop up of the whole list of permissions.

Does Google Fit API only works with gmail account?

What happened

I'm trying to use Fitness API services on my app and it was running well so far. I can obtain any data that I need from Fit App until it wont work anymore when I'm using corporate account outside gmail on the authorisation pop up, for example [email protected].

Steps to reproduce

  • Add another account in your device (outside gmail, eg: your email account for work)
  • Open your app, ask for fitness permission (two account will appear eg: [email protected] and [email protected] through permission dialog)
  • When you authorise fit permission for [email protected] account, fitness data should be retrieve-able.
  • When you authorise fit permission for [email protected] account, fitness data is not retrieve-able. For example, if you get step count it always return 0 value.

Main concern

So what I want to know is, does Fitness API only works with gmail account? They do not mention anything about that on the authorization pages:

It would be nice if someone can point me out to a relevant article or something similar. Thank you.

Error:Could not find com.googlecode.json-simple:json-simple:1.1.

Issue by iakovosvo
Tuesday Dec 12, 2017 at 11:51 GMT
Originally opened as googlearchive/android-fit#29


I get the following error while trying to open the BasicSensorsApi project:

Error:Could not find com.googlecode.json-simple:json-simple:1.1.
Searched in the following locations:
file:/Applications/Android Studio 3.0 Preview.app/Contents/gradle/m2repository/com/googlecode/json-simple/json-simple/1.1/json-simple-1.1.pom
file:/Applications/Android Studio 3.0 Preview.app/Contents/gradle/m2repository/com/googlecode/json-simple/json-simple/1.1/json-simple-1.1.jar
https://dl.google.com/dl/android/maven2/com/googlecode/json-simple/json-simple/1.1/json-simple-1.1.pom
https://dl.google.com/dl/android/maven2/com/googlecode/json-simple/json-simple/1.1/json-simple-1.1.jar
Required by:
project : > com.android.tools.build:gradle:3.0.0 > com.android.tools.build:gradle-core:3.0.0 > com.android.tools.build:builder:3.0.0

GoogleSignIn.hasPermissions always return true even if I call disableFit

Issue by norio-agoop
Wednesday Mar 27, 2019 at 09:06 GMT
Originally opened as googlearchive/android-fit#48


Hi,

The situation

I'm trying to enable/disable google fit in my app with a Switch View.

When I turn off this switch, I call below code.

Fitness.getConfigClient(context, account).disableFit()
                .addOnSuccessListener {
                    Timber.d("disconnectGoogleFit: onSuccess")
                }
                ...

After onSuccess, I turn on switch to connect google fit and call below.

if (GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions){
 return
}
GoogleSignIn.requestPermissions(
        this, // your activity
        GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
        GoogleSignIn.getLastSignedInAccount(this),
        fitnessOptions);

Nothing happens because GoogleSignIn.hasPermissions always return true.

What I want to do

I'd like to check whether Google fit permission is granted or not before calling GoogleSignIn.requestPermissions

Please tell me how to do this.

Thank you


Update

I think I have found a solution that disconnecting app through Google Fit App. After this, GoogleSignIn.hasPermissions return false.
But I am curious how can do this programmatically.

Solved

GoogleSignInClient.revokeAccess works. I don't know the reasons why.

 val signInOptions = GoogleSignInOptions.Builder().addExtension(fitnessOptions).build()
            val client = GoogleSignIn.getClient(context, signInOptions)
            client.revokeAccess()
                .addOnSuccessListener {
                    Timber.d("disconnectGoogleFit: onSuccess")
                }

Question

I'd like to ask you what is the diffrences between Fitness.getConfigClient(context, account).disableFit() and GoogleSignInClient.revokeAccess?

Thank you

sphal namespace is not configured for this process.

Issue by ankitaturani573
Saturday Mar 31, 2018 at 20:15 GMT
Originally opened as googlearchive/android-fit#32


I am trying to run the BasicSensorsApi code but getting this error after choosing the gmail account.
I am using an Android Oreo One PLus5.

This is the error I am getting.

04-01 01:30:26.680 26997-26997/com.google.android.gms.fit.samples.basicsensorsapi D/AppTracker: App Event: stop
04-01 01:30:26.717 26997-27076/com.google.android.gms.fit.samples.basicsensorsapi I/Adreno: QUALCOMM build : d52c199, I26dffed9a4
Build Date : 01/09/18
OpenGL ES Shader Compiler Version: EV031.22.00.01
Local Branch :
Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.UM.6.4.R1.08.00.00.309.052
Remote Branch : NONE
Reconstruct Branch : NOTHING
04-01 01:30:26.717 26997-27076/com.google.android.gms.fit.samples.basicsensorsapi I/vndksupport: sphal namespace is not configured for this process. Loading /vendor/lib64/hw/gralloc.msm8998.so from the current namespace instead.

StepCounterKotlin stuck on empty white popup after selecting Google Account

Hello,

I try to run StepCounterKotlin sample.
After selecting a Google Account, an empty white popup is shown, just with a loader at the top. And it stuck in this place.
No errors are visible in logcat . I tested in the emulator and on Redmi Note 8 phone.

Package name match credentials for my Cloud project, package name matches the applicationId in the app/build.gradle file, and Signing-certificate fingerprint from debug.keystore is entered correctly.
Should I make some additional setup on Google API Console?

Best

Find Data Source Using Sensor API

I am using the below code to find data sources because I am interested in reading data specifically from the sensor on a wearable device but not from the same type of sensor on the phone.

private fun findDataSource(){
Fitness.getSensorsClient(this, getGoogleAccount()).findDataSources(
DataSourcesRequest.Builder()
.setDataTypes(DataType.TYPE_LOCATION_SAMPLE)
.setDataSourceTypes(DataSource.TYPE_RAW)
.build())
.addOnSuccessListener { dataSources ->
/**
* Only my mobile phone was found as a data source
* Missing android watch
*/
for (dataSource in dataSources) {
Log.i(TAG,"Data source found: $dataSource")
Log.i(TAG,"Data Source type: ${dataSource.dataType.name}")

                if (dataSource.dataType == DataType.TYPE_HEART_RATE_BPM && dataPointListener == null) {
                    Log.i(TAG,"Data source for TYPE_HEART_RATE_BPM found!")
                    registerFitnessDataListener(dataSource, dataSource.dataType)
                }
            }
            if (dataSources != null && dataSources.size == 0){
                Log.i(TAG,"No data source found")
            }
        }
        .addOnFailureListener { e -> Log.e(TAG,"failed",e) }
}

But from the above code
* Only my mobile phone was found as a data source
* Missing android watch

NOTE: Using Polar Unite Fitness Watch

Missing sample of BroadcastReceiver for Session Start/End

Issue by rubinbasha
Monday Jan 22, 2018 at 12:21 GMT
Originally opened as googlearchive/android-fit#30


"Google Fit broadcasts intents when any app starts or stops recording a session on behalf of the user. Fitness apps can register a listener to receive these intents."

Can we please have a sample of that? I am trying to implement one myself but not being able to receive intents right now and having a sample would be very helpful.

Kind regards,
Rubin

GoogleSignIn.getLastSignedInAccount for google fit api ALWAYS prompt account selection

Issue by ykorshev
Monday Jan 07, 2019 at 04:41 GMT
Originally opened as googlearchive/android-fit#44


I have an app which uses Google Fit. The integration code has been copied from google documentation:
if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) { GoogleSignIn.requestPermissions( this, // your activity GOOGLE_FIT_PERMISSIONS_REQUEST_CODE, GoogleSignIn.getLastSignedInAccount(this), fitnessOptions); } else { accessGoogleFit(); }
In the debug mode, everything works fine, but when my app downloaded from Google Play, it ALWAYS display a prompt for selecting the google account to use:
image
The problem appears only when app downloaded from google play. When app installed with adb, everything works fine.

It seems like, Google Play Services does not cache last selected account.

Please help me, where is the issue here?

OnDataPointListener Stops getting updates randomly?

Issue by RyanNewsom
Friday Jul 22, 2016 at 22:52 GMT
Originally opened as googlearchive/android-fit#17


All,

My team noticed this problem in our application which uses your Sensors API to show users their distance traveled. Every time we start a walk, eventually, the OnDataPointListener just stops giving updates that there's a new DataPoint available(even though user is moving). I've seen it take anywhere from 5 mins to 1.5 hours to stop working. We have log statements tracking when theres an update, when the client gets disconnected(if it ever does), when a client gets built, etc. There is no callback when this happens. I forked your sample app to try and see if this was an API issue, and it looks like it is.
https://github.com/RyanNewsom/android-fit/tree/master/BasicSensorsApi

Steps to reproduce:

  1. Download my sample app, launch, press start.
  2. Confirm updates are coming in
  3. Background the app, hit the hold button to turn off the screen
  4. Put phone in pocket/on a table for 10-30 mins
  5. Foreground app and walk around of shake the phone to see if you are getting updates
  6. repeat 3-5 until you see you are not getting updates

๐Ÿ™

Failing to recreate GoogleApiClient after upgrading play services 9.0.2

Issue by vitovalov
Thursday Jul 28, 2016 at 11:22 GMT
Originally opened as googlearchive/android-fit#18


I made a fork from android-fit google's github project and added a couple of commits.

The problem comes with play-services-fitness version upgrade. It works as expected in 8.4.0 but if you upgrade to 9.0.2 appears the issue of recreating googleApiClient.

I'm trying to solve the case when the googleApiClient has to be recreated because stopAutoManage has been automatically called due to some error (either user canceled the sign-in dialog, or other client was alive but was manually stopAutomanage called). See the gifs.

So to sum up, the question is how to properly recreate the GoogleApiClient with play services 9+?

There's also an issue in android bug tracker.

How to read steps session wise.

Issue by krunal93
Monday Jul 02, 2018 at 13:53 GMT
Originally opened as googlearchive/android-fit#37


I am in need to show steps time line wise like below.

Time 10 am - 56 steps
Time 11 am - 156 steps
Time 4.30 pm - 236 steps

I don't want to aggregate by hour or anything , i just want the actual data that is currently google fit app is showing in timeline using steps filter.

However i am able to retrieve steps using bucketBySession that entered manually into google fit app but not able to retrieve those steps history which is generated automatically.

Please let me know how to overcome this.

Below is my sample code.

       // Build a session read request
       SessionReadRequest readRequest = new SessionReadRequest.Builder()
               .setTimeInterval(times[0], times[1], TimeUnit.MILLISECONDS)
               .readSessionsFromAllApps()
               .read(DataType.TYPE_STEP_COUNT_DELTA)
               .enableServerQueries()
               .build();

       Fitness.getSessionsClient(mContext, GoogleSignIn.getLastSignedInAccount(mContext))
               .readSession(readRequest)
               .addOnSuccessListener(new OnSuccessListener<SessionReadResponse>() {
                   @Override
                   public void onSuccess(SessionReadResponse sessionReadResponse) {
                       // Get a list of the sessions that match the criteria to check the result.
                       List<Session> sessions = sessionReadResponse.getSessions();
                       Log.i(TAG, "Session read was successful. Number of returned sessions is: "
                               + sessions.size());

                       for (Session session : sessions) {
                           // Process the session
                           dumpSession(session);

                           // Process the data sets for this session
                           List<DataSet> dataSets = sessionReadResponse.getDataSet(session);
                           for (DataSet dataSet : dataSets) {
                               dumpDataSet(dataSet);
                           }
                       }
                   }
               })
               .addOnFailureListener(new OnFailureListener() {
                   @Override
                   public void onFailure(@NonNull Exception e) {
                       Log.i(TAG, "Failed to read session");
                   }
               });

    final DataReadRequest req = new DataReadRequest.Builder()
               .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
               .aggregate(DataType.TYPE_ACTIVITY_SEGMENT, DataType.AGGREGATE_ACTIVITY_SUMMARY)
               .enableServerQueries()
               .bucketBySession(1, TimeUnit.MINUTES)
               .setTimeRange(times[0], times[1], TimeUnit.MILLISECONDS)
               .build();

   Fitness.getHistoryClient(mContext, GoogleSignIn.getLastSignedInAccount(mContext))
               .readData(req)
               .addOnSuccessListener(
                       dataReadResponse -> readData(dataReadResponse, MESSAGE_HEALTH_DATA_LIST_KEY))
               .addOnFailureListener(
                       e -> {
                       });

I am trying with the both client , session as well as history but didn't get any suceess.
thanks,
Krunal

Do we need Google Fit App for Google Fit API?

Issue by hienttVFJ
Wednesday Aug 21, 2019 at 08:40 GMT
Originally opened as googlearchive/android-fit#53


I made small test app which shows daily steps using Google Fit API. During testing, I was not getting any steps count. But later I realised that my Samsung device doesn't come's with Google Fit app so I downloaded it and after feeding some data then I tested my app again and Now I can see my steps count on my test app.

So Does this means that in order to use Google Fit API all my app users must have installed Google Fit App?

BMR and Calories Expended

Hi I want to know if theres any method to differenctiate BMR calories with Calories Expended in the API. If I change any personal data (in google Fit) I can get It using TYPE_BASAL_METABOLIC_RATE. But If i don't do any thing this doesnt work

Is there a limit on SessionReadRequest with dataSets?

Issue by casman51
Tuesday May 21, 2019 at 10:04 GMT
Originally opened as googlearchive/android-fit#51


When I try to use SessionReadRequest to parse data from 1 month it does not return anything. In the beginning this worked, but as newer sessions now include TYPE_HEART_RATE_BPM dataType it doesn't work anymore. When I don't read this dataType or lower the time to only 3 days back in time it works.. Could anyone help me with this issue. Is there some sort on limit on a SessionReadRequest? Below is my code for reading the sessions. Once a session is read is goes to the populateList where they are added to a list and when completed notify a RecyclerView.

private SessionReadRequest readFitnessSession() {
        // [START build_read_session_request]
        // Set a start and end time for query, using a start time of 1 month before this moment.
        Calendar cal = Calendar.getInstance();
        Date now = new Date();
        cal.setTime(now);
        long endTime = cal.getTimeInMillis();
        cal.add(Calendar.MONTH, -1);
        long startTime = cal.getTimeInMillis();

        // Build a session read request
        SessionReadRequest readRequest = new SessionReadRequest.Builder()
                .setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
                .read(DataType.TYPE_HEART_RATE_BPM)
                .read(DataType.AGGREGATE_DISTANCE_DELTA)
                .readSessionsFromAllApps()
                //.enableServerQueries()
                .build();
        // [END build_read_session_request]

        return readRequest;
    }
private Task<SessionReadResponse> readSession() {
        // Begin by creating the query.
        SessionReadRequest readRequest = readFitnessSession();

        // [START read_session]
        // Invoke the Sessions API to fetch the session with the query and wait for the result
        // of the read request. Note: Fitness.SessionsApi.readSession() requires the
        // ACCESS_FINE_LOCATION permission.
        return Fitness.getSessionsClient(this, GoogleSignIn.getLastSignedInAccount(this))
                .readSession(readRequest)
                .addOnSuccessListener(new OnSuccessListener<SessionReadResponse>() {
                    @Override
                    public void onSuccess(SessionReadResponse sessionReadResponse) {
                        // Get a list of the sessions that match the criteria to check the result.
                        Log.i(TAG, "Session read was successful");
                        populateList(sessionReadResponse);
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.i(TAG, "Failed to read session");
                    }
                });
        // [END read_session]
    }

Read Google Fit automatically generated activities

I'm struggling getting this to work as expected. I need to enumerate all the activities I see in Google Fit app (e.g auto "morning walk" or manual added running). I've used the following query:

DataReadRequest readRequest = new DataReadRequest.Builder()
.aggregate(DataType.TYPE_ACTIVITY_SEGMENT, DataType.AGGREGATE_ACTIVITY_SUMMARY)
.enableServerQueries()
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.bucketByTime(1, TimeUnit.DAYS)
.build();
Note: this kind of aggregation is deprecated, but I cannot find the "right" way to receive the same result with the non-deprecated method.

Now: in my example day on Fit, I've two activities. The first is auto-generated "afternoon walk" of 2.32km and 32 min, the second is a manual added running activity of 1h. The query above returns two rows with fields activity/duration/num_segments:

Running / 3600000 (1h) / 1
Walking / 2674044 (~44mins) / 10
As you can see I get 12 minutes added for walking, why? How can I get the exact thing I see in the app? Moreover the total sum of steps for that day is not the sum of the two activities I see on Fit. What a mess...

EDIT: about timezone I'm getting it this way:

Calendar calendar = Calendar.getInstance(Locale.getDefault());
long endTime = calendar.getTimeInMillis();
calendar.add(Calendar.MONTH, -1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
long startTime = calendar.getTimeInMillis();
And these are the results for the specific day:

DATA TYPE: DataType{com.google.activity.summary[activity(i), duration(i), num_segments(i)]}

AS ACTIVITY: running FIELD: activity(i) START TIME: Fri Oct 16 12:10:00 GMT+02:00 2020 END TIME: Fri Oct 16 13:10:00 GMT+02:00 2020

DURATION: 3600000 FIELD: duration(i) START TIME: Fri Oct 16 12:10:00 GMT+02:00 2020 END TIME: Fri Oct 16 13:10:00 GMT+02:00 2020

N. SEGMENTS: 1 FIELD: num_segments(i) START TIME: Fri Oct 16 12:10:00 GMT+02:00 2020 END TIME: Fri Oct 16 13:10:00 GMT+02:00 2020

AS ACTIVITY: walking FIELD: activity(i) START TIME: Fri Oct 16 09:20:30 GMT+02:00 2020 END TIME: Fri Oct 16 23:15:17 GMT+02:00 2020

DURATION: 2674044 FIELD: duration(i) START TIME: Fri Oct 16 09:20:30 GMT+02:00 2020 END TIME: Fri Oct 16 23:15:17 GMT+02:00 2020

N. SEGMENTS: 10 2FIELD: num_segments(i) START TIME: Fri Oct 16 09:20:30 GMT+02:00 2020 END TIME: Fri Oct 16 23:15:17 GMT+02:00 2020

Error: I cannot use sensor client with TYPE_ACTIVITY_SEGMENT and TYPE_CALORIES_EXPENDED dataType

Hi there, I got some problems with real-time display data in my application. I use SensorClient to listen to calorie data change. When my calories data change on Google Fit, the onDataPoint function was not invoked. When I use sensor client for listening to the Step Count data change, it works properly. Please explains to me why I cannot use SensorClient for listening to TYPE_CALORIES_EXPENDED data type.
Here is my code:
Fitness.getSensorsClient(context, account)
.add(SensorRequest.Builder().setDataType(dataType)
.build(), dataPointListener)
.addOnSuccessListener {
Log.e("registerDataPointUpdateListener: ", "Success for $dataType")
}.addOnFailureListener {
Log.e("registerDataPointUpdateListener: ", "Fail ${it.message}")
}
I saw this one in my logcat:
W/Fitness: No live data sources available for SensorRegistrationRequest{type DataType{com.google.activity.segment[activity(i)]} source null interval -1 fastest 0 latency 0}. Returning success. Will start recording once data source is live [CONTEXT service_id=17 ]

Google Fit API: ApiException 17 (Fitness.CLIENT is not available on this device)

Issue by hrsalehi
Friday May 04, 2018 at 03:07 GMT
Originally opened as googlearchive/android-fit#34


I configured Google fit api and followed "Getting Started" section of google docs. But when I trying to read "Steps" data I face "Google Fit API: ApiException 17 (Fitness.CLIENT is not available on this device)" exception in Task object callback from getRecordingClient

        Fitness.getRecordingClient(context, GoogleSignIn.getLastSignedInAccount(context))
                .subscribe(DataType.TYPE_STEP_COUNT_CUMULATIVE)
                .addOnCompleteListener(
                        new OnCompleteListener<Void>() {
                            @Override
                            public void onComplete(@NonNull Task<Void> task) {
                                if (task.isSuccessful()) {
                                    Log.i(LOG_TAG, "Successfully subscribed!");
                                } else {
                                    Log.w(LOG_TAG, "There was a problem subscribing.", task.getException());
                                }
                            }
                        });

Always my history api returns empty Buckets

Issue by puvi008
Monday Oct 01, 2018 at 11:33 GMT
Originally opened as googlearchive/android-fit#41


public class MainActivity extends AppCompatActivity {

public static final String TAG = "StepCounter";
private static final int REQUEST_OAUTH_REQUEST_CODE = 0x1001;
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
private GoogleApiClient mClient = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // This method sets up our custom logger, which will print all log messages to the device
    // screen, as well as to adb logcat.
    initializeLogging();
    if (!checkPermissions()) {
        requestPermissions();
    } else {
        callGoogleClient();
    }

}

private void callGoogleClient() {
    FitnessOptions fitnessOptions =
            FitnessOptions.builder()
                    .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
                    .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
                    .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
                    .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_WRITE)
                    .addDataType(DataType.TYPE_ACTIVITY_SEGMENT, FitnessOptions.ACCESS_READ)
                    .addDataType(DataType.TYPE_ACTIVITY_SEGMENT, FitnessOptions.ACCESS_WRITE)
                    .build();
    if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) {
        GoogleSignIn.requestPermissions(
                this,
                REQUEST_OAUTH_REQUEST_CODE,
                GoogleSignIn.getLastSignedInAccount(this),
                fitnessOptions);
    } else {
        getFitData();
    }

}

private boolean checkPermissions() {
    int permissionState = ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION);
    int permissionState1 = ActivityCompat.checkSelfPermission(this,
            Manifest.permission.BODY_SENSORS);
    return permissionState == PackageManager.PERMISSION_GRANTED && permissionState1 == PackageManager.PERMISSION_GRANTED;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == REQUEST_OAUTH_REQUEST_CODE) {
            getFitData();
          }
    }
}

private void getFitData() {
    if (mClient == null && checkPermissions()) {
        mClient = new GoogleApiClient.Builder(this)
                .addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
                .addScope(new Scope(Scopes.FITNESS_BODY_READ))
                .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ))
                .addApi(Fitness.HISTORY_API)
                .addConnectionCallbacks(
                        new GoogleApiClient.ConnectionCallbacks() {
                            @Override
                            public void onConnected(Bundle bundle) {
                                android.util.Log.i(TAG, "Connected!!!");
                                subscribeToFetching();
                            }

                            @Override
                            public void onConnectionSuspended(int i) {
                                if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
                                } else if (i
                                        == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
                                }
                            }
                        }
                )
                .enableAutoManage(this, 4, new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult result) {
                        android.util.Log.i("onConnectionFailed", result.getErrorMessage());
                    }
                })
                .build();
    }
}

private void
subscribeToFetching() {
    new BackgroundFetching().execute();
     }

private void getData() {
    try {
        Calendar cal = Calendar.getInstance();
        Date now = new Date();
        cal.setTime(now);
        long endTime = cal.getTimeInMillis();
        cal.add(Calendar.HOUR, -cal.getInstance().get(Calendar.HOUR_OF_DAY));
        cal.add(Calendar.MINUTE, -cal.getInstance().get(Calendar.MINUTE));
        cal.add(Calendar.SECOND, -cal.getInstance().get(Calendar.SECOND));
        long startTime = cal.getTimeInMillis();
        //long startTime = Long.parseLong("1535602500000");


        android.util.Log.i(TAG, "Start Time: " + android.text.format.DateFormat.format("yyyy-MM-dd hh:mm:ss a", startTime));
        android.util.Log.i(TAG, "End Time: " + android.text.format.DateFormat.format("yyyy-MM-dd hh:mm:ss a", endTime));


        DataReadRequest readRequest = new DataReadRequest.Builder()
                .aggregate(DataType.AGGREGATE_STEP_COUNT_DELTA, DataType.TYPE_STEP_COUNT_DELTA)
                // .aggregate(DataType.TYPE_HEART_RATE_BPM, DataType.AGGREGATE_HEART_RATE_SUMMARY)
                /// .aggregate(DataType.TYPE_CALORIES_EXPENDED, DataType.AGGREGATE_CALORIES_EXPENDED)
                .enableServerQueries()
                .bucketByTime(24, TimeUnit.HOURS)
                .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                .build();
        PendingResult<DataReadResult> result = Fitness.HistoryApi.readData(mClient, readRequest);

        result.setResultCallback(new ResultCallback<DataReadResult>() {
            @Override
            public void onResult(@NonNull DataReadResult dataReadResult) {
                int totalSteps = 0;
                if (dataReadResult.getBuckets().size() > 0) {
                    for (Bucket bucket : dataReadResult.getBuckets()) {
                        for (DataSet set : bucket.getDataSets()) {
                            for (DataPoint dp : set.getDataPoints()) {
                                for (Field field : dp.getDataType().getFields()) {
                                    int steps = dp.getValue(field).asInt();
                                    totalSteps += steps;
                                    Toast.makeText(MainActivity.this, totalSteps, Toast.LENGTH_LONG).show();

                                }

                            }
                        }

                    }
                }
            }
        });

    } catch (Exception e) {
        android.util.Log.i(TAG, "Error msg: " + e.getMessage());
    }
}

private class BackgroundFetching extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... params) {
        getData();
        return null;
    }
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the main; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.action_read_data) {
        readData();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

/**
 * Initializes a custom log class that outputs both to in-app targets and logcat.
 */
private void initializeLogging() {
    // Wraps Android's native log framework.
    LogWrapper logWrapper = new LogWrapper();
    // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
    Log.setLogNode(logWrapper);
    // Filter strips out everything except the message text.
    MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
    logWrapper.setNext(msgFilter);
    // On screen logging via a customized TextView.
    LogView logView = (LogView) findViewById(R.id.sample_logview);

    // Fixing this lint error adds logic without benefit.
    // noinspection AndroidLintDeprecation
    logView.setTextAppearance(R.style.Log);

    logView.setBackgroundColor(Color.WHITE);
    msgFilter.setNext(logView);
    Log.i(TAG, "Ready");
}

private void requestPermissions() {
    boolean shouldProvideRationale =
            ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_FINE_LOCATION);
    if (shouldProvideRationale) {
        Snackbar.make(
                findViewById(R.id.main_activity_view),
                "RequestPremission",
                Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.intro_text, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        // Request permission
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.BODY_SENSORS},
                                REQUEST_PERMISSIONS_REQUEST_CODE);
                    }
                })
                .show();
    } else {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BODY_SENSORS},
                REQUEST_PERMISSIONS_REQUEST_CODE);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    android.util.Log.i(TAG, "onRequestPermissionResult");
    if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
        if (grantResults.length <= 0) {
            android.util.Log.i(TAG, "User interaction was cancelled.");
        } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            callGoogleClient();
        } else {
            Snackbar.make(
                    findViewById(R.id.main_activity_view),
                    "Premission not Granted",
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.intro_text, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            // Build intent that displays the App settings screen.
                            Intent intent = new Intent();
                            intent.setAction(
                                    Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package",
                                    BuildConfig.APPLICATION_ID, null);
                            intent.setData(uri);
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    })
                    .show();
        }
    }
}

}

Google Fit History API returns empty dataset [ ]

Hi,

I ran the the sample to get steps using history Api as mentioned in the link: https://developers.google.com/fit/android/get-started

But I am getting empty [ ] response from the Api regardless of the interval time.

Here is my code:

private fun accessGoogleFit() {
val cal = Calendar.getInstance()
cal.setTime(Date())
val endTime = cal.getTimeInMillis()
cal.add(Calendar.MONTH, -1)
val startTime = cal.getTimeInMillis()

val readRequest = DataReadRequest.Builder()
  .aggregate(TYPE_STEP_COUNT_DELTA, AGGREGATE_STEP_COUNT_DELTA)
  .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
  .enableServerQueries()
  .bucketByTime(1, TimeUnit.DAYS)
  .build()

Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this)!!)
  .readData(readRequest)
  .addOnSuccessListener(OnSuccessListener<DataReadResponse> {

    Log.i("DATASET",it.dataSets.toString())
    textView35.text = it.dataSets.toString()
    Log.d(
      "SUCCESS_TAG",
      "onSuccess()"
    )
  })
  .addOnFailureListener(OnFailureListener { e -> Log.e("FAILED_TAG", "onFailure()", e) })
  .addOnCompleteListener(OnCompleteListener<DataReadResponse> {
    Log.d(

      "COMPLETE TAG",
      "onComplete()"
    )
  })

}

Any help would be appreciated.

Always returns empty dataset

Issue by ilyasdirin
Tuesday May 14, 2019 at 08:11 GMT
Originally opened as googlearchive/android-fit#50


I'm developing a step counter with Google Fit.
I tried to implement as it is defined in Google Fit docs. But the problem is that when I query step count it always returns empty dataset but when I query with readDailyTotal function it returns a dataset.
I am not able to find what is the cause.

  1. I get the required permission for required step count permission
val fitnessOptions = FitnessOptions.builder()
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)  
.addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE, FitnessOptions.ACCESS_READ)  
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)  
.build()

if (! GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(activity),  
fitnessOptions)) {
    GoogleSignIn.requestPermissions(
        activity, // your activity
        REQUEST_CODE_GOOGLE_FIT_PERMISSIONS,
        GoogleSignIn.getLastSignedInAccount(activity),
        fitnessOptions
    )
} else {
    onSuccess.invoke()
}
  1. I subscribe to the application for recording step counts.
Fitness.getRecordingClient(context, client!!)
.subscribe(DataType.TYPE_STEP_COUNT_DELTA)
.addOnSuccessListener {
    onSuccess.invoke()
}
.addOnFailureListener { e ->
    onFail.invoke(e)
}
  1. I query 1 week period with history API but it always returns an empty dataset.
// Setting a start and end date using a range of 1 week before this moment.  
val cal = Calendar.getInstance()  
val now = Date()  
cal.time = now  
val endTime = cal.timeInMillis  
cal.add(Calendar.WEEK_OF_YEAR, -1)  
val startTime = cal.timeInMillis  

val dateFormat = DateFormat.getDateInstance()
Log.i(TAG, "Range Start: " + dateFormat.format(startTime))
Log.i(TAG, "Range End: " + dateFormat.format(endTime))

val readRequest = DataReadRequest.Builder()
// The data request can specify multiple data types to return, effectively
// combining multiple data queries into one call.
// In this example, it's very unlikely that the request is for several hundred
// datapoints each consisting of a few steps and a timestamp.  The more likely
// scenario is wanting to see how many steps were walked per day, for 7 days.
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
// Analogous to a "Group By" in SQL, defines how data should be aggregated.
// bucketByTime allows for a time span, whereas bucketBySession would allow
// bucketing by "sessions", which would need to be defined in code.
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.enableServerQueries()
.build()
Fitness.getHistoryClient(context, client)
    .readData(readRequest)
    .addOnSuccessListener { dataReadResponse ->
        dumpDataSets(dataReadResponse.dataSets)
        onSuccess.invoke(dataReadResponse)
    }
    .addOnFailureListener { e ->
        onFail.invoke(e)
    }
    .addOnCompleteListener { task ->
        dumpDataSets(task.result!!.dataSets)
        onComplete.invoke(task)
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.