I have previously worked on getting the heart rate data using Google fit. Initially, I have faced the same issue. If you go through the documentation in the following link
https://developers.google.com/android/reference/com/google/android/gms/fitness/data/DataType.html#TYPE_HEART_RATE_BPM
It is clearly mentioned that you need to get BODY_SENSORS permission
"Registering to, or subscribing to data of this type requires BODY_SENSORS"
If the user doesn't grant the permission for BODY_SENSORS, then we will be getting the error as we won't be able to access or insert Heart rate data.
You may use the below code to request the user for granting permission
ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.BODY_SENSORS},
BODY_SENSOR_PERMISSION_REQUEST_CODE);
You can check if the user has granted permission in the 'onRequestPermissionsResult' callback and then request for Heart rate data.
Adding sample code as requested.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{android.Manifest.permission.BODY_SENSORS},
BODY_SENSOR_PERMISSION_REQUEST_CODE);
}
private class InsertAndVerifyDataTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
// Create a new dataset and insertion request.
DataSet dataSet = insertHeartData();
// [START insert_dataset]
// Then, invoke the History API to insert the data and await the result, which is
// possible here because of the {@link AsyncTask}. Always include a timeout when calling
// await() to prevent hanging that can occur from the service being shutdown because
// of low memory or other conditions.
com.google.android.gms.common.api.Status insertStatus =
Fitness.HistoryApi.insertData(connectFit.returnClient(), dataSet)
.await(1, TimeUnit.MINUTES);
// Before querying the data, check to see if the insertion succeeded.
if (!insertStatus.isSuccess()) {
return null;
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(MainActivity.this, "Added", Toast.LENGTH_SHORT).show();
}
}
private DataSet insertHeartData() {
// [START build_insert_data_request]
try {
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_HEART_RATE_BPM)
.setStreamName(" - heart count")
.setType(DataSource.TYPE_DERIVED)
.build();
// Create a data set
float hearRate = Float.parseFloat(((EditText) (findViewById(R.id.heartRate))).getText().toString().trim());
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, MILLISECONDS);
dataPoint.getValue(Field.FIELD_BPM).setFloat(hearRate);
dataSet.add(dataPoint);
// [END build_insert_data_request]
return dataSet;
} catch (Exception e) {
return null;
}
}
This worked for me.