Skip to content

Commit 4f05d5f

Browse files
committed
Activity Recognition: Calculate steps using confidence
1 parent df8094b commit 4f05d5f

12 files changed

Lines changed: 158 additions & 133 deletions

File tree

activity_recognition/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,7 @@ dependencies {
6969

7070
// TODO Add Google Play Services Location library
7171
implementation(libs.play.services.location)
72+
73+
implementation(libs.datastore)
74+
7275
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/ActivityRecognitionApp.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,4 @@ import dagger.hilt.android.HiltAndroidApp
99
@HiltAndroidApp
1010
class ActivityRecognitionApp : Application() {
1111

12-
val detectingMode = MutableLiveData<DetectingMode>()
13-
val activityType = MutableLiveData(ActivityType.STILL)
14-
val currentPoints = MutableLiveData(0)
15-
16-
1712
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/services/ActivityUpdatesReceiver.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@ import android.content.Context
55
import android.content.Intent
66
import android.util.Log
77
import android.widget.Toast
8-
import com.asemlab.samples.activity_recognition.ActivityRecognitionApp
98
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility.toActivityType
9+
import com.asemlab.samples.activity_recognition.utilties.ActivityType.DRIVING
10+
import com.asemlab.samples.activity_recognition.utilties.ActivityType.RUNNING
11+
import com.asemlab.samples.activity_recognition.utilties.ActivityType.STILL
12+
import com.asemlab.samples.activity_recognition.utilties.ActivityType.UNKNOWN
13+
import com.asemlab.samples.activity_recognition.utilties.ActivityType.WALKING
14+
import com.asemlab.samples.activity_recognition.utilties.DataStoreUtils
1015
import com.google.android.gms.location.ActivityRecognitionResult
16+
import kotlinx.coroutines.CoroutineScope
17+
import kotlinx.coroutines.Dispatchers
18+
import kotlinx.coroutines.launch
1119

1220

1321
class ActivityUpdatesReceiver : BroadcastReceiver() {
@@ -26,10 +34,17 @@ class ActivityUpdatesReceiver : BroadcastReceiver() {
2634
val type = toActivityType(activity.type)
2735
val confidence = activity.confidence
2836

29-
with(context.applicationContext as ActivityRecognitionApp) {
30-
activityType.value = type
37+
val steps = when (type) {
38+
STILL, DRIVING, UNKNOWN -> 0
39+
WALKING -> confidence / 10
40+
RUNNING -> confidence / 10
3141
}
3242

43+
CoroutineScope(Dispatchers.IO).launch {
44+
DataStoreUtils.updateCurrentPoints(context, confidence / 10)
45+
}
46+
47+
3348
Toast.makeText(context, "$type : $confidence%", Toast.LENGTH_SHORT).show()
3449
}
3550
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/services/TransitionsReceiver.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,21 @@ class TransitionsReceiver : BroadcastReceiver() {
3434

3535
Toast.makeText(context, info, Toast.LENGTH_SHORT).show()
3636

37-
when (event.transitionType) {
38-
ActivityTransition.ACTIVITY_TRANSITION_ENTER -> {
39-
with(context.applicationContext as ActivityRecognitionApp) {
40-
activityType.value = toActivityType(event.activityType)
41-
detectingMode.value = DetectingMode.ENTER
42-
}
43-
}
44-
45-
ActivityTransition.ACTIVITY_TRANSITION_EXIT -> {
46-
with(context.applicationContext as ActivityRecognitionApp) {
47-
activityType.value = toActivityType(event.activityType)
48-
detectingMode.value = DetectingMode.EXIT
49-
}
50-
}
51-
}
37+
// when (event.transitionType) {
38+
// ActivityTransition.ACTIVITY_TRANSITION_ENTER -> {
39+
// with(context.applicationContext as ActivityRecognitionApp) {
40+
// activityType.value = toActivityType(event.activityType)
41+
// detectingMode.value = DetectingMode.ENTER
42+
// }
43+
// }
44+
//
45+
// ActivityTransition.ACTIVITY_TRANSITION_EXIT -> {
46+
// with(context.applicationContext as ActivityRecognitionApp) {
47+
// activityType.value = toActivityType(event.activityType)
48+
// detectingMode.value = DetectingMode.EXIT
49+
// }
50+
// }
51+
// }
5252
}
5353
}
5454
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/ui/MainViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ open class MainViewModel @Inject constructor(private val activitiesRepository: A
1919

2020
val entries = MediatorLiveData<List<ActivityEntry>>(emptyList())
2121
var lastEntry: LiveData<ActivityEntry> = MutableLiveData()
22-
var totalPoints: LiveData<Long> = MutableLiveData()
22+
var totalSteps: LiveData<Long> = MutableLiveData()
2323

2424
fun addActivity(activityEntry: ActivityEntry) {
2525
viewModelScope.launch {
@@ -56,7 +56,7 @@ open class MainViewModel @Inject constructor(private val activitiesRepository: A
5656
fun getTotalPoints() {
5757
viewModelScope.launch {
5858
withContext(Dispatchers.IO) {
59-
totalPoints = activitiesRepository.getTotalPoints()
59+
totalSteps = activitiesRepository.getTotalPoints()
6060
}
6161
}
6262
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/ui/dashboard/DashboardFragment.kt

Lines changed: 27 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ import android.os.Bundle
1010
import android.view.LayoutInflater
1111
import android.view.View
1212
import android.view.ViewGroup
13-
import android.widget.Toast
1413
import androidx.activity.result.contract.ActivityResultContracts
1514
import androidx.core.app.ActivityCompat
1615
import androidx.fragment.app.Fragment
16+
import androidx.lifecycle.Lifecycle
1717
import androidx.lifecycle.ViewModelProvider
18-
import com.asemlab.samples.activity_recognition.ActivityRecognitionApp
19-
import com.asemlab.samples.activity_recognition.services.ActivityTrackingService
18+
import androidx.lifecycle.lifecycleScope
19+
import androidx.lifecycle.repeatOnLifecycle
2020
import com.asemlab.samples.activity_recognition.R
2121
import com.asemlab.samples.activity_recognition.databinding.FragmentDashboardBinding
2222
import com.asemlab.samples.activity_recognition.model.ActivityEntry
23+
import com.asemlab.samples.activity_recognition.services.ActivityTrackingService
2324
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility
2425
import com.asemlab.samples.activity_recognition.utilties.ActivityType
25-
import com.asemlab.samples.activity_recognition.utilties.Constants
26-
import com.asemlab.samples.activity_recognition.utilties.DetectingMode
27-
import com.asemlab.samples.activity_recognition.utilties.TimerUtility
26+
import com.asemlab.samples.activity_recognition.utilties.DataStoreUtils
2827
import dagger.hilt.android.AndroidEntryPoint
28+
import kotlinx.coroutines.launch
2929

3030

3131
@AndroidEntryPoint
@@ -39,13 +39,6 @@ class DashboardFragment : Fragment() {
3939
requireActivity().recreate()
4040
}
4141
}
42-
private var points = 0
43-
private var pointsFactor = Constants.WALKING_POINTS_FACTOR
44-
private val timer = TimerUtility(Constants.TIMER_INTERVAL) {
45-
points += pointsFactor
46-
(requireContext().applicationContext.applicationContext as ActivityRecognitionApp).currentPoints
47-
.value = (points)
48-
}
4942

5043
override fun onCreateView(
5144
inflater: LayoutInflater,
@@ -59,11 +52,11 @@ class DashboardFragment : Fragment() {
5952
with(dashboardViewModel) {
6053

6154
lastEntry.observe(this@DashboardFragment.viewLifecycleOwner) {
62-
binding.lastPoints.text = "${it?.points ?: 0}"
55+
binding.lastSteps.text = "${it?.points ?: 0}"
6356
}
6457

65-
totalPoints.observe(this@DashboardFragment.viewLifecycleOwner) {
66-
binding.totalPoints.text = "${it ?: 0}"
58+
totalSteps.observe(this@DashboardFragment.viewLifecycleOwner) {
59+
binding.totalSteps.text = "${it ?: 0}"
6760
}
6861

6962
isServiceRunning.observe(this@DashboardFragment.viewLifecycleOwner) {
@@ -78,8 +71,6 @@ class DashboardFragment : Fragment() {
7871
val isRunning = dashboardViewModel.isServiceRunning.value!!
7972

8073
dashboardViewModel.isServiceRunning.postValue(!isRunning)
81-
(requireContext().applicationContext as ActivityRecognitionApp)
82-
.detectingMode.postValue(if (!isRunning) DetectingMode.ON else DetectingMode.OFF)
8374

8475
// TODO Start detecting
8576
val intent = Intent(context, ActivityTrackingService::class.java)
@@ -92,6 +83,17 @@ class DashboardFragment : Fragment() {
9283
}
9384
} else {
9485
requireContext().stopService(intent)
86+
87+
dashboardViewModel.addActivity(
88+
ActivityEntry(
89+
ActivityType.WALKING.name,
90+
currentSteps.text.toString().toLong(),
91+
System.currentTimeMillis()
92+
)
93+
)
94+
lifecycleScope.launch {
95+
DataStoreUtils.setCurrentPoints(requireContext(), 0)
96+
}
9597
}
9698
}
9799

@@ -107,6 +109,13 @@ class DashboardFragment : Fragment() {
107109
ActivityDetectionUtility.testDrivingToWalking(requireContext())
108110
}
109111

112+
viewLifecycleOwner.lifecycleScope.launch {
113+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
114+
DataStoreUtils.getCurrentPoints(requireContext()).collect {
115+
binding.currentSteps.text = "$it"
116+
}
117+
}
118+
}
110119
}
111120

112121

@@ -123,68 +132,6 @@ class DashboardFragment : Fragment() {
123132
binding.startButton.isEnabled = false
124133
}
125134

126-
with(requireContext().applicationContext as ActivityRecognitionApp) {
127-
detectingMode.observe(this@DashboardFragment.viewLifecycleOwner) {
128-
it?.let {
129-
when (it) {
130-
DetectingMode.ON -> {
131-
timer.start()
132-
}
133-
134-
DetectingMode.OFF -> {
135-
timer.cancel()
136-
dashboardViewModel.addActivity(
137-
ActivityEntry(
138-
activityType.value.toString(),
139-
currentPoints.value!!.toLong(),
140-
System.currentTimeMillis()
141-
)
142-
)
143-
detectingMode.value = null
144-
}
145-
146-
DetectingMode.ENTER -> {
147-
Toast.makeText(
148-
requireContext(),
149-
"Entered to ${activityType.value}",
150-
Toast.LENGTH_SHORT
151-
).show()
152-
timer.start()
153-
154-
currentPoints.value = 0
155-
points = 0
156-
}
157-
158-
// Save to database
159-
DetectingMode.EXIT -> {
160-
dashboardViewModel.addActivity(
161-
ActivityEntry(
162-
activityType.value.toString(),
163-
currentPoints.value!!.toLong(),
164-
System.currentTimeMillis()
165-
)
166-
)
167-
currentPoints.value = 0
168-
points = 0
169-
detectingMode.postValue(null)
170-
timer.cancel()
171-
}
172-
}
173-
}
174-
}
175-
176-
activityType.observe(this@DashboardFragment.viewLifecycleOwner) {
177-
pointsFactor = when (it!!) {
178-
ActivityType.DRIVING -> Constants.DRIVING_POINTS_FACTOR
179-
ActivityType.STILL, ActivityType.UNKNOWN -> Constants.STILL_POINTS_FACTOR
180-
ActivityType.WALKING, ActivityType.RUNNING -> Constants.WALKING_POINTS_FACTOR
181-
}
182-
}
183-
184-
currentPoints.observe(this@DashboardFragment.viewLifecycleOwner) {
185-
binding.currentPoints.text = "${it ?: 0}"
186-
}
187-
}
188135

189136
return binding.root
190137
}

activity_recognition/src/main/java/com/asemlab/samples/activity_recognition/utilties/ActivityDetectionUtility.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ object ActivityDetectionUtility {
9494
@SuppressLint("MissingPermission")
9595
fun enableActivityUpdates(context: Context){
9696
val task = ActivityRecognition.getClient(context)
97-
.requestActivityUpdates(10000L, getPendingIntent(context))
97+
.requestActivityUpdates(3000L, getPendingIntent(context))
9898

9999
task.addOnSuccessListener {
100100
activityTrackingEnabled = true
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.asemlab.samples.activity_recognition.utilties
2+
3+
import android.content.Context
4+
import androidx.datastore.core.DataStore
5+
import androidx.datastore.preferences.core.Preferences
6+
import androidx.datastore.preferences.core.edit
7+
import androidx.datastore.preferences.core.intPreferencesKey
8+
import androidx.datastore.preferences.preferencesDataStore
9+
import kotlinx.coroutines.flow.Flow
10+
import kotlinx.coroutines.flow.map
11+
12+
13+
object DataStoreUtils {
14+
15+
// TODO Init DataStore object
16+
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_details")
17+
18+
val CURRENT_POINTS = intPreferencesKey("current_points")
19+
20+
suspend fun setCurrentPoints(context: Context, points: Int) {
21+
context.dataStore.edit { data ->
22+
data[CURRENT_POINTS] = points
23+
}
24+
}
25+
26+
suspend fun updateCurrentPoints(context: Context, points: Int) {
27+
context.dataStore.edit { data ->
28+
data[CURRENT_POINTS] = data[CURRENT_POINTS]?.plus(points) ?: 0
29+
}
30+
}
31+
32+
fun getCurrentPoints(context: Context): Flow<Int> {
33+
return context.dataStore.data.map {
34+
it[CURRENT_POINTS] ?: 0
35+
}
36+
}
37+
38+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="960"
5+
android:viewportHeight="960">
6+
<path
7+
android:pathData="M260,120q-45,0 -72.5,50T160,280q0,63 17.5,111.5T210,464l110,-22q13,-32 26.5,-73t13.5,-89q0,-60 -27.5,-110T260,120ZM315,640q19,0 32,-14t13,-39q0,-17 -8,-35t-16,-32l-96,20q0,40 17.5,70t57.5,30ZM700,320q-45,0 -72.5,50T600,480q0,48 13.5,88.5T640,642l110,22q15,-24 32.5,-72T800,480q0,-60 -27.5,-110T700,320ZM645,840q40,0 57.5,-30t17.5,-70l-96,-20q-8,14 -16,32t-8,35q0,20 12.5,36.5T645,840ZM315,720q-77,0 -117,-57t-38,-128l-18,-27q-11,-17 -36.5,-77T80,280q0,-103 51,-171.5T260,40q85,0 132.5,75.5T440,280q0,58 -16,107t-28,79l8,13q8,14 22,44.5t14,63.5q0,57 -35.5,95T315,720ZM645,920q-54,0 -89.5,-38T520,787q0,-33 14,-63.5t22,-44.5l8,-13q-12,-30 -28,-79t-16,-107q0,-89 47.5,-164.5T700,240q78,0 129,68.5T880,480q0,91 -25.5,150.5T818,707l-18,28q1,71 -38.5,128T645,920Z"
8+
android:fillColor="#000000"/>
9+
</vector>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
2+
3+
<path android:fillColor="#000000" android:pathData="M480,840q-138,0 -240.5,-91.5T122,520h82q14,104 92.5,172T480,760q117,0 198.5,-81.5T760,480q0,-117 -81.5,-198.5T480,200q-69,0 -129,32t-101,88h110v80L120,400v-240h80v94q51,-64 124.5,-99T480,120q75,0 140.5,28.5t114,77q48.5,48.5 77,114T840,480q0,75 -28.5,140.5t-77,114q-48.5,48.5 -114,77T480,840ZM592,648L440,496v-216h80v184l128,128 -56,56Z"/>
4+
5+
</vector>

0 commit comments

Comments
 (0)