Search code examples
javaandroidgoogle-fit-sdk

How to use Google Fit API's RecordingClient for background collection of DataType.TYPE_LOCATION_SAMPLE?


I proceeded as per Google Fit examples and subscribed to the RecordingClient for DataType.TYPE_LOCATION_SAMPLE with the following code (after requesting all needed permissions):

Fitness.getRecordingClient(this, GoogleSignIn.getLastSignedInAccount(this))
    .subscribe(DataType.TYPE_LOCATION_SAMPLE)
    .addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Log.d(LOG_TAG, "Successfully subscribed!");
        }
    })
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Log.d(LOG_TAG, "There was a problem subscribing.");
        }
    });

On the Logcat, I receive the messagge Successfully subscribed!, so everything seems to be OK. In addition, if I run the following code, to double check:

Fitness.getRecordingClient(MainActivity.this, GoogleSignIn.getLastSignedInAccount(MainActivity.this))
    .listSubscriptions()
    .addOnSuccessListener(new OnSuccessListener<List<Subscription>>() {
        @Override
        public void onSuccess(List<Subscription> subscriptions) {
            for (Subscription sc : subscriptions) {
                Log.d(LOG_TAG, "Active subscription for data type: " + sc.getDataType().getName());
            }
        }
    });

I receive the output:

D/mygpsapp.log: Active subscription for data type: com.google.location.sample

confirming that the subscription is indeed active. However, if (after moving around for one hour, for testing) I try to read data back from the HistoryClient, with the following code:

DataReadRequest readRequest = new DataReadRequest.Builder()
    .read(DataType.TYPE_LOCATION_SAMPLE)
    .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
    .build();

Fitness.getHistoryClient(MainActivity.this, GoogleSignIn.getLastSignedInAccount(MainActivity.this))
    .readData(readRequest)
    .addOnSuccessListener(new OnSuccessListener<DataReadResponse>() {
        @Override
        public void onSuccess(DataReadResponse dataReadResponse) {
        Log.d(LOG_TAG, "HistoryClient.readData: onSuccess()");
        DataSet dataSet;

        List<DataSet> dataSets = dataReadResponse.getDataSets();
        Log.d(LOG_TAG, "# of DataSets: " + dataSets.size());
        dataSet = dataReadResponse.getDataSet(DataType.TYPE_LOCATION_SAMPLE);
            Log.d(LOG_TAG, "DataSet: " + dataSet);
            Log.d(LOG_TAG, "DataSource: " + dataSet.getDataSource());
            Log.d(LOG_TAG, "DataType: " + dataSet.getDataType());

        int count = 0;
        for (DataPoint dp : dataSet.getDataPoints()) {
            Log.d(LOG_TAG, "Data point #" + count++);
            Log.d(LOG_TAG, "\tType: " + dp.getDataType().getName());
            Log.d(LOG_TAG, "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
            Log.d(LOG_TAG, "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)));
            for (Field field : dp.getDataType().getFields()) {
                Log.d(LOG_TAG, "\tField: " + field.getName() + ", Value: " + dp.getValue(field));
            }
            Log.d(LOG_TAG, "\tSource: " + dp.getOriginalDataSource().getAppPackageName());
        }
        }
    })
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
        Log.e(LOG_TAG, "HistoryClient.readData: onFailure()", e);
        }
    });

I do get a relevant DataSet, but it is always empty:

D/mygpsapp.log: # of DataSets: 1
D/mygpsapp.log: DataSet: DataSet{d:location.sample:gms:default_location_samples []}
D/mygpsapp.log: DataSource: DataSource{derived:Application{com.google.android.gms}:default_location_samples:DataType{com.google.location.sample[latitude(f), longitude(f), accuracy(f), altitude(f)]}}
D/mygpsapp.log: DataType: DataType{com.google.location.sample[latitude(f), longitude(f), accuracy(f), altitude(f)]}

I acknowledge that the Google Fit API documentation reports the following:

Exceptions: Whilst any application can write data to a public data type, there are certain data types which can only be read by the application that wrote the data:

com.google.location.sample, The user's current location.

but I do try to read back the data with the same application. What makes me suspicious is that the previous Logcat seems to indicate that the application that wrote the data is com.google.android.gms (is it the RecordingClient?) not mine, possibly explaining why the DataSet returns empty. But if this is the case, how is my application supposed to read back the data that itself asked (succesfully!) to record?


Solution

  • Google Fit does not support reading location data which has been gathered via the Recording API via the History API.

    We'll clarify this in the documentation.