i want to get my daily step count from google fit - android

I'm writing an android application which works with Google Fit APIs to collect daily user's step count.
I want to get my daily step count. this code return me a whole years step count.
How can I get the Google daily step Count value?
override fun onConnected(bundle: Bundle?) {
val dataSourceRequest = DataSourcesRequest.Builder()
.setDataTypes(DataType.TYPE_STEP_COUNT_CUMULATIVE)
.setDataSourceTypes(DataSource.TYPE_RAW)
.build()
val dataSourcesResultCallback =
ResultCallback<DataSourcesResult> { dataSourcesResult ->
for (dataSource in dataSourcesResult.dataSources) {
if (DataType.TYPE_STEP_COUNT_CUMULATIVE == dataSource.dataType) {
registerFitnessDataListener(
dataSource,
DataType.TYPE_STEP_COUNT_CUMULATIVE
)
}
}
}
Fitness.SensorsApi.findDataSources(
mApiClient,
dataSourceRequest
)
.setResultCallback(dataSourcesResultCallback)
}
private fun registerFitnessDataListener(dataSource: DataSource, dataType: DataType) {
val request = SensorRequest.Builder()
.setDataSource(dataSource)
.setDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
.setSamplingRate(1, TimeUnit.SECONDS)
.build()
Fitness.SensorsApi.add(mApiClient, request, this)
.setResultCallback { status ->
if (status.isSuccess) {
Log.d("GoogleFit", "SensorApi successfully added")
}
}
}
override fun onDataPoint(dataPoint: DataPoint) {
for (field in dataPoint.dataType.fields) {
val value = dataPoint.getValue(field)
runOnUiThread(Runnable {
stepCounterTextView.setText("Field1: " + field.name + " Value1: " + value)
})
}
}
I replaced DataType.TYPE_STEP_COUNT_CUMULATIVE with a DataType.TYPE_STEP_COUNT_DELTA but it doesnoot work.

Visit https://developers.google.com/android/reference/com/google/android/gms/fitness/request/SessionReadRequest
for get daily step count read

Related

I want weekly Sleep data from google fit

I am not getting weekly data from google fit (Yes, There is data in google fit which I have track using watch), but Yes I am getting today's date data.
I am attaching code snippet.
Start date = "2022-09-13T00:00:00Z"
End date = "2022-09-20T23:59:59Z"
private fun readSleepSessions(startTime : Long , endTime : Long) {
val client = Fitness.getSessionsClient(requireContext(), getGoogleAccount())
val sessionReadRequest = SessionReadRequest.Builder()
.read(DataType.TYPE_SLEEP_SEGMENT)
.includeSleepSessions()
.readSessionsFromAllApps()
.enableServerQueries()
.setTimeInterval(1663027200000, 1663718399000, TimeUnit.MILLISECONDS)
.build()
client.readSession(sessionReadRequest)
.addOnSuccessListener {
Log.d(TAG, "readSleepSessions: $sessionReadRequest")
dumpSleepSessions(it)
}
.addOnFailureListener {
Log.e("MainScreen", "Unable to read sleep sessions", it)
}
}
private fun dumpSleepSessions(response: SessionReadResponse) {
if (response.sessions.isNotEmpty()){
for (session in response.sessions) {
dumpSleepSession(session, response.getDataSet(session))
Log.d(TAG, "dumpSleepSessions: ${response.sessions}")
}
}else{
Log.d(TAG, "dumpSleepSessionsResponse: ${response.status}")
}
}
private fun dumpSleepSession(session: Session, dataSets: List<DataSet>) {
dumpSleepSessionMetadata(session)
dumpSleepDataSets(dataSets)
}
private fun dumpSleepDataSets(dataSets: List<DataSet>) {
for (dataSet in dataSets) {
for (dataPoint in dataSet.dataPoints) {
val sleepStageOrdinal = dataPoint.getValue(Field.FIELD_SLEEP_SEGMENT_TYPE).asInt()
val sleepStage = sleepTargetName[sleepStageOrdinal]
val durationMillis =
dataPoint.getEndTime(TimeUnit.MILLISECONDS) - dataPoint.getStartTime(TimeUnit.MILLISECONDS)
val duration = TimeUnit.MILLISECONDS.toMinutes(durationMillis)
Log.d(TAG, "\t$sleepStage: $duration (minutes)")
}
}

How to update timeInterval for PeriodicWorkRequest after doWork() call

I'm new to Work manager in android and I want to update the timeInterval of PeriodicWorkRequest once I got the response from server. Here is my sample code where I'm trying to update the timeInterval. But it is going to an infinite loop of calling the doWork() function. Please suggest to me where it is wrong.
class RandomNumberGenerator(context: Context, workerParams: WorkerParameters) : Worker(
context,
workerParams) {
private val min = 0
private val max = 100
var randomNumber = 0
var context: Context
init {
Log.d(TAG, "Constructor invoked")
this.context = context
Log.d(TAG, "" + workerParams.id.toString())
}
private fun startRandomNumberGenerator() {
Log.d(TAG, "startRandomNumberGenerator: isStopped: $isStopped")
var i = 0
while (i < 5) {
try {
Thread.sleep(1000)
randomNumber = Random().nextInt(max) + min
Log.d(
TAG,
"Thread Id: " + Thread.currentThread().id + " Random Number: " + randomNumber
)
i++
} catch (e: Exception) {
}
if (i == 5) {
callUpdateSyncTime()
}
}
}
private fun callUpdateSyncTime() {
Log.d(TAG, "callUpdateSyncTime() called")
val periodicWork =
PeriodicWorkRequest.Builder(RandomNumberGenerator::class.java, 20, TimeUnit.MINUTES)
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"work_manager_random",
ExistingPeriodicWorkPolicy.REPLACE,
periodicWork
)
}
companion object {
const val TAG = "WorkManager"
}
override fun doWork(): Result {
startRandomNumberGenerator()
return Result.success()
}
override fun onStopped() {
Log.d(TAG, "onStopped() called")
super.onStopped()
}
}
Here is the code how I'm enqueuing from my MainActivity
val workRequestRandomNumber: PeriodicWorkRequest =
PeriodicWorkRequestBuilder<RandomNumberGenerator>(
15,
TimeUnit.MINUTES
).build()
workManager.enqueueUniquePeriodicWork(
"work_manager_random",
ExistingPeriodicWorkPolicy.KEEP,
workRequestRandomNumber
)
When you enqueue a PeriodicWorkRequest, it will be executed immeditially if you don't add an initial delay using setInitialDelay().
Given that you are rescheduling your worker each time it's completed, I would suggest to use a OneTimeWorkRequest, instead of a repeating one, with an initial delay:
val workRequestRandomNumber =
OneTimeWorkRequestBuilder<RandomNumberGenerator>()
.setInitialDelay(
15,
TimeUnit.MINUTES)
.addTag("work_manager_random")
.build()
workManager.enqueue(workRequestRandomNumber)
As it is right now, WorkManager is sending a cancellation to your worker that you are ignoring.

Android Unit Test: How do I test if retryWhen from RxJava is called certain numbers?

What I have
I have a static class APIHelper and there's a single public function
/**
* Calls APIs that return Observable<Response<*>>.
* #param observable an Observable<Response<SomeModel>> you can get from NetworkServiceGenerator.getApi()
* #param maxRetryCount retry count to try up to. Default is 3 (see DEFAULT_RETRY_COUNT)
* #param customErrorToCatch if included, you can throw any Exception with custom logic
* #param haltIfThrownType if included, you can halt the operation even before try count didn't reach retry count
*/
fun <T : Response<*>> call(
observable: Observable<T>,
maxRetryCount: Int = DEFAULT_MAX_RETRY_COUNT,
retryIntervalInSec: Long = DEFAULT_RETRY_INTERVAL_SEC,
customErrorToCatch: ((response: T) -> Unit)? = null,
haltIfThrownType: ((throwable: Throwable?) -> Boolean)? = null): Observable<T> {
return observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext {
if (!it.isSuccessful) {
if (customErrorToCatch != null) {
customErrorToCatch(it)
}
throwNetworkException(it)
}
}
.retryWhen { errors ->
errors.zipWith(
Observable.range(1, maxRetryCount),
BiFunction { throwable: Throwable, count: Int -> Pair(throwable, count) })
.flatMap { pair: Pair<Throwable, Int> ->
val throwable = pair.first
val currentCount = pair.second
val isNetworkException = pair.first is NetworkException
if (shouldStopRetrying(haltIfThrownType, throwable, currentCount, maxRetryCount)) {
Observable.error(throwable)
} else {
Observable.timer(retryIntervalInSec, TimeUnit.SECONDS)
}
}
}
}
I was able to verify success case and failed case by doing this
#Test
fun testSuccessful() {
val response = ResponseModel("success", "0", "")
Mockito.`when`(api.requestLogout()).thenReturn(Observable.just(Response.success(response)))
val result = APIHelper.call(api.requestLogout())
val testObserver = TestObserver<Response<ResponseModel>>()
result.subscribe(testObserver)
testObserver.assertComplete()
testObserver.assertNoErrors()
testObserver.assertValueCount(1)
val isSuccessful = testObserver.values()[0].isSuccessful
assert(isSuccessful)
}
#Test
fun testError() {
val response = Response.error<ResponseModel>(
400,
ResponseBody.create(
MediaType.parse("application/json"),
"{\"result\":\"fail\",\"errorCode\":\"0\",\"errorMessage\":\"some error\"}")
)
Mockito.`when`(api.requestLogout()).thenReturn(Observable.just(response))
val result = APIHelper.call(api.requestLogout())
val testObserver = TestObserver<Response<ResponseModel>>()
result.subscribe(testObserver)
testObserver.assertNotComplete()
testObserver.assertError(NetworkException(400, ""))
testObserver.assertValueCount(0)
}
Setup
Kotlin
Mockito 3.x.x
mockk 1.9.x
Question
I want to test two things
retryWhen was entered maxRetryCount times and failed.
try n numbers and pass mock response at n+1 attempt to test success case.
What I tried
I tried to make a function inside retryWhen block (see shouldStopRetrying(...)), but I don't really know how to count that specific function invocation from a static class.
Thank you in advance!
EDIT
So I edited the function to be an extension function of Observable
fun <T: Response<*>> Observable<T>.call(
subscribeOn: Scheduler = Schedulers.io(),
observeOn: Scheduler = AndroidSchedulers.mainThread(),
maxRetryCount: Int = DEFAULT_MAX_RETRY_COUNT,
retryIntervalInSec: Long = DEFAULT_RETRY_INTERVAL_SEC,
customErrorToCatch: ((response: T) -> Unit)? = null,
haltIfThrownType: ((throwable: Throwable?) -> Boolean)? = null): Observable<T> {
return this.subscribeOn(subscribeOn)
.observeOn(observeOn)
.doOnNext {
if (!it.isSuccessful) {
if (customErrorToCatch != null) {
customErrorToCatch(it)
}
throwNetworkException(it)
}
}
.retryWhen { errors ->
errors.zipWith(
Observable.range(1, maxRetryCount),
BiFunction { throwable: Throwable, count: Int -> Pair(throwable, count) })
.flatMap { pair: Pair<Throwable, Int> ->
val throwable = pair.first
val currentCount = pair.second
if (shouldStopRetrying(haltIfThrownType, throwable, currentCount, maxRetryCount)) {
Observable.error(throwable)
} else {
Observable.timer(retryIntervalInSec, TimeUnit.SECONDS)
}
}
}
}
and my test is
#Test
fun testRetriableError() {
val response = Response.error<ResponseModel>(
500,
ResponseBody.create(
MediaType.parse("application/json"),
"{\"result\":\"fail\",\"errorCode\":\"4\",\"errorMessage\":\"\"}")
)
Mockito.`when`(api.requestLogout()).thenReturn(Observable.just(response))
val testScheduler = TestScheduler(0, TimeUnit.SECONDS)
val result = api.requestLogout().call(
observeOn = testScheduler
)
val testObserver = TestObserver<Response<ResponseModel>>()
result.subscribe(testObserver)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
testObserver.assertNotTerminated()
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
testObserver.assertNotTerminated()
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
testObserver.assertNotTerminated()
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
testObserver.assertTerminated() // <--- fails
testObserver.assertNotComplete()
testObserver.assertError(NetworkException(500, "Internal Server Error"))
testObserver.assertValueCount(0)
}
This fails at testObserver.assertTerminated() with the following error
java.lang.AssertionError: Subscriber still running! (latch = 1, values = 0, errors = 0, completions = 0)
However, when I debug this test and run them line by line (taking enough time), the test passes.
I almost feel like testScheduler.advanceTimeBy(1, TimeUnit.SECONDS) is doing nothing.
What am I doing wrong?

How to call a method multiple times using RXJava - which operator do I use?

I have a function which does a network call to retrieve data, and I need to call it 5 times. My method:
#Throws(IOException::class)
private fun getWeather(future : Int): String {
var twitterURL = Constants.API_URL
if (future > 0) {
twitterURL += "future$future.json"
}
val urlBuilder = HttpUrl.parse(Constants.API_URL).newBuilder()
val url = urlBuilder.build().toString()
val request = Request.Builder()
.url(url)
.build()
val client = OkHttpClient()
val response = client.newCall(request).execute()
val body = response.body()
return if (response.code() == HttpURLConnection.HTTP_OK) {
body.string()
} else {
throw IOException("Bad Request: Server Response" + response.code().toString() + " " + response.message())
}
}
I'd like to use the observable model doing something like:
private val array = DoubleArray(5)
Observable.fromArray(listOf(1, 2, 3, 4, 5))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread()))
//observation on the main thread
.subscribe(object:Subscriber<Int>(){
override fun onCompleted() {
calculateStandardDeviation(array)
}
override fun onError(e: Throwable?) {
//TODO : Handle error here
}
override fun onNext(t: Int?) {
val string = getWeather(t)
val gson = Gson()
val weather = gson.fromJson(string,TwitterWeather::class.java)
array[t-1] = weather.temperature
}
})
But really, onNext() runs on the main thread. I want to run it all on the Schedulers.io() thread.
.observeOn(AndroidSchedulers.mainThread()) tells on which scheduler will the subscribe callbacks, including onNext run. So just use .observeOn(Schedulers.io())
Check this article for more details:
https://medium.com/upday-devs/rxjava-subscribeon-vs-observeon-9af518ded53a
Conceptually, you need to move your network call from the subscription logic and make it Observable, something like this:
Observable.fromIterable(listOf(1, 2, 3, 4, 5))
.flatMap { t ->
Observable.fromCallable {
val string = getWeather(t)
val gson = Gson()
val weather = gson.fromJson(string, TwitterWeather::class.java)
weather.temperature
}.subscribeOn(Schedulers.io())
}.toList()
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ temperatures ->
calculateStandardDeviation(temperatures)
}, {
//TODO : Handle error here
})

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.

Categories

Resources