Google fit empty dataset - android

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.
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()
}
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)
}
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)
}

Datasets can be found in buckets:
dataReadResponse.buckets.forEach { bucket ->
bucket.dataSet.forEach { dataSet ->
dataSet.dataPoints.forEach { dataPoint ->
// USE DataPoint
}
}
}

Related

Google Fit returns exception when trying to read data: "Error: 4: The user must be signed in to make this API call."

The issue started happening after I disabled google fit. Link
Checking permissions with
GoogleSignIn.hasPermissions(googleAccount, fitnessOptions) returns true.
Also the method for requesting permissions asks to select an account, but after selecting an account I get the same exception trying to read data.
GoogleSignIn.requestPermissions(
activity,
GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
googleAccount,
fitnessOptions
)
Here is the code that I'm using to try to read data from GoogleFit.
var end = DateHelper.getEndOfDay(endDate)
if (DateHelper.isToday(endDate)) {
/* make sure current day query time is until current time, not end of the day */
end = Calendar.getInstance().time
}
val start = DateHelper.getStartOfDay(startDate)
val datasource = DataSource.Builder()
.setAppPackageName("com.google.android.gms")
.setDataType(DataType.TYPE_STEP_COUNT_DELTA)
.setType(DataSource.TYPE_DERIVED)
.setStreamName("estimated_steps")
.build()
val request = DataReadRequest.Builder()
.aggregate(datasource)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(start.time, end.time, TimeUnit.SECONDS)
.build()
val fitnessOptions: GoogleSignInOptionsExtension = FitnessOptions.builder()
.addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ)
.build()
val googleSignInAccount: GoogleSignInAccount =
GoogleSignIn.getAccountForExtension(this.reactContext, fitnessOptions)
Fitness.getHistoryClient(this.reactContext, googleSignInAccount)
.readData(request)
.addOnSuccessListener { response ->
val totalSteps = response.buckets
.flatMap { it.dataSets }
.flatMap { it.dataPoints }
.sumBy { it.getValue(Field.FIELD_STEPS).asInt() }
Log.i(TAG, "Total steps: $totalSteps")
promise.resolve(totalSteps)
}
.addOnFailureListener { e: Exception ->
Log.i(TAG, "onFailure()");
Log.i(TAG, "Error $e");
promise.reject(e);
}
Is there any way to force account authorization to sign in the user? Or what is the reason I get this error, because the method to check if account has permission returns true.

Google Fit Api Android getting daily steps by hour and total time of exercise

I am currently working on an android project, which has to collect daily info from google fit api. I have searched a lot, but I have not found answers for 2 questions:
How to get steps bu hours with array. For example from 1pm to 2pm I have walked 100 steps, from 2pm to 3pm 200 steps.
How to get the total amount of time that the user exercised that day.
Thank you very much in advance)
For your first part of point.
If you form a data read request with proper segmented start and end time alongside bucket and aggregation functionality you can retrieve data buckets of each hour.
Below is the code that I am using to retrieve hourly data for any given start and end date.
fun getReadDataRequestBuilderAggregated(startDate: Date, endDate: Date): DataReadRequest? {
val cal = Calendar.getInstance()
cal.time = startDate.setDayStartTime()
var startTime = cal.timeInMillis
cal.time = endDate.setDayEndTime()
var endTime = cal.timeInMillis
return if (startTime>endTime) {
null
} else {
return DataReadRequest.Builder()
.aggregate(DataType.TYPE_CALORIES_EXPENDED, DataType.AGGREGATE_CALORIES_EXPENDED)
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
.bucketByTime(1, TimeUnit.HOURS)
.enableServerQueries()
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS).build()
}
}
private fun Date.setDayEndTime(): Date {
val currentTime = Calendar.getInstance().apply {
time = this#setDayEndTime
}
currentTime.set(Calendar.HOUR_OF_DAY, 23)
currentTime.set(Calendar.MINUTE, 59)
currentTime.set(Calendar.SECOND, 59)
return currentTime.time
}
private fun Date.setDayStartTime(): Date {
val currentTime = Calendar.getInstance().apply {
time = this#setDayStartTime
}
currentTime.set(Calendar.HOUR_OF_DAY, 0)
currentTime.set(Calendar.MINUTE, 0)
currentTime.set(Calendar.SECOND, 0)
currentTime.set(Calendar.MILLISECOND,0)
return currentTime.time
}

Why value of CALORIES_EXPENDED of API not equal value of Google Fit App?

This code get calo in day:
val cal = Calendar.getInstance()
cal.time = Date()
val endTime = cal.timeInMillis
cal.add(Calendar.DAY_OF_YEAR, -1)
val startTime = cal.timeInMillis
val readRequest = DataReadRequest.Builder()
.aggregate(DataType.TYPE_CALORIES_EXPENDED, DataType.AGGREGATE_CALORIES_EXPENDED)
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
.bucketByTime(1, TimeUnit.DAYS)
.build()
Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
.readData(readRequest)
.addOnSuccessListener { 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 { e -> Log.e(TAG, "onFailure()", e) }
.addOnCompleteListener(OnCompleteListener {
Log.d(TAG, "onComplete()")
})
Value return:Field Calories Value= 11332.985.
But in Google Fit App display value = 6.164 Cal.
Why value of CALORIES_EXPENDED of API not equal value of Google Fit App?

Why deleteData of google fit history api not working?

This code delete history in today:
val cal = Calendar.getInstance()
cal.time = Date()
val endTime = cal.timeInMillis
cal.add(Calendar.DAY_OF_YEAR, -1)
val startTime = cal.timeInMillis
val request = DataDeleteRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
// .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
.deleteAllData ()
.deleteAllSessions ()
.build()
Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
.deleteData(request)
.addOnSuccessListener {
Log.i(TAG, "Successfully deleted today's sessions") }
.addOnFailureListener {
// The deletion will fail if the requesting app tries to delete data
// that it did not insert.
Log.i(TAG, "Failed to delete today's sessions")
}
Result : logcat show message successfully:
03-02 18:12:54.949 15978-15978/vnit.com.testrealm I/StepCounter: Successfully deleted today's sessions
But i use function read data, it still exist:
private fun readData() {
Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
.readDailyTotal(DataType.TYPE_STEP_COUNT_DELTA)
.addOnSuccessListener { dataSet ->
val total = (if (dataSet.isEmpty)
0
else
dataSet.dataPoints[0].getValue(Field.FIELD_STEPS).asInt()).toLong()
Log.i(TAG, "Total steps: " + total)
txtStep.setText(total.toString())
}
.addOnFailureListener(
object : OnFailureListener {
override fun onFailure(e: Exception) {
Log.w(TAG, "There was a problem getting the step count.", e)
}
})
}
I am trying to open Google fit app, it still display's old value.
Why can't delete old history?
Thanks all.

Google Fit Data

Hi guys I have a problem using the Google Fit Api. I only receive activity data in specific situations.
I'm using the RxFit library (but I had the same behaviour using the default implementation). When I try this on my own phone (Nexus 5X) with my own account it works perfectly fine. If I try a different account on my phone I receive a success response, but no actual activity data. Same goes for other device and other account. And with my own account on the other device it does not work either. The same behaviour occurs when using the emulator.
My implementation:
fun requestActivities(): Single<DataReadResult> {
val fit = RxFit(context, arrayOf(Fitness.HISTORY_API), arrayOf(Scope(Scopes.FITNESS_ACTIVITY_READ)))
val dataReadRequest = buildRequest(getStartEndTime())
return fit.history().read(dataReadRequest).doOnSuccess { storeDatapoints(it) }
}
private fun storeDatapoints(data: DataReadResult) {
val idlist = activityRepository.all().map { it.activityId }
val activities = data.buckets
.flatMap { it.dataSets }
.flatMap { it.dataPoints }
.filter { point ->
//https://developers.google.com/fit/rest/v1/reference/activity-types
val activity = point.getValue(Field.FIELD_ACTIVITY).asInt()
return#filter activity != 0 && activity != 3 //&& !(109..112).contains(activity)
}
.map { point ->
PersistentExerciseActivity(
activityId = point.timestampNanos.toString(),
date = Instant(point.getTimestamp(TimeUnit.MILLISECONDS)).toDateTime().toLocalDateTime(),
duration = point.getValue(Field.FIELD_DURATION).asInt() / 1000 / 60,
activity = point.getValue(Field.FIELD_ACTIVITY).asActivity(),
apiId = null
)
}
.filter { !idlist.contains(it.activityId) }
activityRepository.store(activities)
}
private fun getStartEndTime(): Pair<Long, Long> {
val cal = Calendar.getInstance()
val now = Date()
cal.time = now
cal.set(Calendar.HOUR_OF_DAY, 0)
cal.set(Calendar.MINUTE, 0)
cal.set(Calendar.MILLISECOND, 0)
cal.set(Calendar.SECOND, 0)
val endTime = cal.timeInMillis
cal.add(Calendar.WEEK_OF_YEAR, -1)
val startTime = cal.timeInMillis
return Pair(startTime, endTime)
}
private fun buildRequest(startEndTime: Pair<Long, Long>): DataReadRequest {
return DataReadRequest.Builder()
.aggregate(DataType.TYPE_ACTIVITY_SEGMENT, DataType.AGGREGATE_ACTIVITY_SUMMARY)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startEndTime.first, startEndTime.second, TimeUnit.MILLISECONDS)
.enableServerQueries()
.build()
}
Does anyone have some ideas what would be causing this?
Kind regards,
Bryan

Categories

Resources