Skip to content

Commit df8094b

Browse files
committed
Activity Recognition: Use activity updates instead of transitions
1 parent 3888bd6 commit df8094b

File tree

17 files changed

+388
-68
lines changed

17 files changed

+388
-68
lines changed

activity_recognition/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ android {
3939
buildFeatures {
4040
dataBinding = true
4141
viewBinding = true
42+
buildConfig = true
4243
}
4344
}
4445

activity_recognition/src/main/AndroidManifest.xml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools">
44

5+
<!-- TODO Add required permissions-->
6+
<!-- Required for 28 and below. -->
57
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
68
<!-- Required for 29+. -->
79
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
10+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH" />
11+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
12+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
813

914
<application
1015
android:name=".ActivityRecognitionApp"
@@ -20,6 +25,7 @@
2025
<activity
2126
android:name=".ui.MainActivity"
2227
android:exported="true"
28+
android:launchMode="singleInstance"
2329
android:label="@string/app_name"
2430
android:screenOrientation="portrait">
2531
<intent-filter>
@@ -31,13 +37,16 @@
3137

3238
<receiver
3339
android:name=".services.TransitionsReceiver"
40+
android:enabled="false"
41+
android:exported="false"/>
42+
<receiver
43+
android:name=".services.ActivityUpdatesReceiver"
3444
android:enabled="true"
45+
android:exported="false"/>
46+
<service
47+
android:name=".services.ActivityTrackingService"
3548
android:exported="false"
36-
android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
37-
<intent-filter>
38-
<action android:name="TRANSITIONS_RECEIVER_ACTION" />
39-
</intent-filter>
40-
</receiver>
49+
android:foregroundServiceType="health" />
4150
</application>
4251

4352
</manifest>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import dagger.hilt.android.HiltAndroidApp
1010
class ActivityRecognitionApp : Application() {
1111

1212
val detectingMode = MutableLiveData<DetectingMode>()
13-
val activityType = MutableLiveData(ActivityType.WALKING)
13+
val activityType = MutableLiveData(ActivityType.STILL)
1414
val currentPoints = MutableLiveData(0)
1515

1616

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.asemlab.samples.activity_recognition.services
2+
3+
import android.app.Notification
4+
import android.app.NotificationChannel
5+
import android.app.NotificationManager
6+
import android.app.PendingIntent
7+
import android.app.Service
8+
import android.content.Context
9+
import android.content.Intent
10+
import android.content.pm.ServiceInfo
11+
import android.os.Build
12+
import android.os.IBinder
13+
import androidx.core.app.NotificationCompat
14+
import com.asemlab.samples.activity_recognition.R
15+
import com.asemlab.samples.activity_recognition.ui.MainActivity
16+
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility
17+
import com.asemlab.samples.activity_recognition.utilties.Constants
18+
19+
class ActivityTrackingService : Service() {
20+
21+
22+
override fun onStartCommand(
23+
intent: Intent?,
24+
flags: Int,
25+
startId: Int
26+
): Int {
27+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
28+
startForeground(
29+
Constants.SERVICE_NOTIFICATION_ID,
30+
createNotification(),
31+
ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH
32+
)
33+
} else
34+
startForeground(Constants.SERVICE_NOTIFICATION_ID, createNotification())
35+
36+
ActivityDetectionUtility.switchUpdatesDetecting(this)
37+
// ActivityDetectionUtility.switchTransitionsDetecting(this)
38+
return START_STICKY
39+
}
40+
41+
override fun onDestroy() {
42+
ActivityDetectionUtility.switchUpdatesDetecting(this)
43+
// ActivityDetectionUtility.switchTransitionsDetecting(this)
44+
super.onDestroy()
45+
}
46+
47+
private fun createNotificationChannel(context: Context) {
48+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
49+
val channel = NotificationChannel(
50+
Constants.NOTIFICATION_CHANNEL_ID,
51+
Constants.NOTIFICATION_CHANNEL_NAME,
52+
NotificationManager.IMPORTANCE_LOW
53+
)
54+
val manager =
55+
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
56+
manager.createNotificationChannel(channel)
57+
}
58+
}
59+
60+
private fun createNotification(): Notification {
61+
createNotificationChannel(this)
62+
63+
val mainIntent = Intent(this, MainActivity::class.java)
64+
val mainPendingIntent = PendingIntent.getActivity(
65+
this, Constants.SERVICE_NOTIFICATION_INTENT_ID,
66+
mainIntent,
67+
PendingIntent.FLAG_IMMUTABLE
68+
)
69+
70+
return NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_ID)
71+
.setContentTitle("Activity tracking enabled")
72+
.setContentText("Detecting your activity")
73+
.setSmallIcon(R.drawable.ic_steps)
74+
.setContentIntent(mainPendingIntent)
75+
.setShowWhen(false)
76+
.setOngoing(true)
77+
.build()
78+
}
79+
80+
override fun onBind(intent: Intent?): IBinder? = null
81+
}
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.services
2+
3+
import android.content.BroadcastReceiver
4+
import android.content.Context
5+
import android.content.Intent
6+
import android.util.Log
7+
import android.widget.Toast
8+
import com.asemlab.samples.activity_recognition.ActivityRecognitionApp
9+
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility.toActivityType
10+
import com.google.android.gms.location.ActivityRecognitionResult
11+
12+
13+
class ActivityUpdatesReceiver : BroadcastReceiver() {
14+
15+
override fun onReceive(context: Context, intent: Intent) {
16+
17+
Log.d("ActivityUpdatesReceiver", "Start detecting")
18+
19+
if (ActivityRecognitionResult.hasResult(intent)) {
20+
21+
// TODO Receive updates and process them
22+
val result = ActivityRecognitionResult.extractResult(intent)
23+
val probableActivities = result?.probableActivities ?: return
24+
25+
probableActivities.forEach { activity ->
26+
val type = toActivityType(activity.type)
27+
val confidence = activity.confidence
28+
29+
with(context.applicationContext as ActivityRecognitionApp) {
30+
activityType.value = type
31+
}
32+
33+
Toast.makeText(context, "$type : $confidence%", Toast.LENGTH_SHORT).show()
34+
}
35+
}
36+
}
37+
38+
}

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

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import android.content.Intent
66
import android.util.Log
77
import android.widget.Toast
88
import com.asemlab.samples.activity_recognition.ActivityRecognitionApp
9-
import com.asemlab.samples.activity_recognition.utilties.ActivityType
9+
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility.toActivityType
10+
import com.asemlab.samples.activity_recognition.utilties.ActivityDetectionUtility.toTransitionType
1011
import com.asemlab.samples.activity_recognition.utilties.DetectingMode
1112
import com.google.android.gms.location.ActivityTransition
1213
import com.google.android.gms.location.ActivityTransitionResult
13-
import com.google.android.gms.location.DetectedActivity
1414
import java.text.SimpleDateFormat
1515
import java.util.Date
1616
import java.util.Locale
@@ -27,26 +27,24 @@ class TransitionsReceiver : BroadcastReceiver() {
2727
val result = ActivityTransitionResult.extractResult(intent)
2828

2929
// TODO Receive transitions and process them
30-
for (event in result!!.transitionEvents) {
30+
result?.transitionEvents?.forEach { event ->
3131
val time = SimpleDateFormat("HH:mm:ss", Locale.US).format(Date())
3232
val info =
33-
"${toTransitionType(event.transitionType)} ${toActivityString(event.activityType)} at $time"
33+
"${toTransitionType(event.transitionType)} ${toActivityType(event.activityType)} at $time"
3434

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

3737
when (event.transitionType) {
3838
ActivityTransition.ACTIVITY_TRANSITION_ENTER -> {
3939
with(context.applicationContext as ActivityRecognitionApp) {
40-
activityType.value =
41-
ActivityType.getType(toActivityString(event.activityType))
40+
activityType.value = toActivityType(event.activityType)
4241
detectingMode.value = DetectingMode.ENTER
4342
}
4443
}
4544

4645
ActivityTransition.ACTIVITY_TRANSITION_EXIT -> {
4746
with(context.applicationContext as ActivityRecognitionApp) {
48-
activityType.value =
49-
ActivityType.getType(toActivityString(event.activityType))
47+
activityType.value = toActivityType(event.activityType)
5048
detectingMode.value = DetectingMode.EXIT
5149
}
5250
}
@@ -55,20 +53,5 @@ class TransitionsReceiver : BroadcastReceiver() {
5553
}
5654
}
5755

58-
private fun toActivityString(activity: Int): String {
59-
return when (activity) {
60-
// DetectedActivity.STILL -> "STILL"
61-
DetectedActivity.WALKING -> "WALKING"
62-
DetectedActivity.IN_VEHICLE -> "DRIVING"
63-
else -> "WALKING"
64-
}
65-
}
6656

67-
private fun toTransitionType(transitionType: Int): String {
68-
return when (transitionType) {
69-
ActivityTransition.ACTIVITY_TRANSITION_ENTER -> "ENTER"
70-
ActivityTransition.ACTIVITY_TRANSITION_EXIT -> "EXIT"
71-
else -> "UNKNOWN"
72-
}
73-
}
7457
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import androidx.navigation.fragment.NavHostFragment
1313
import androidx.navigation.ui.setupWithNavController
1414
import com.asemlab.samples.activity_recognition.R
1515
import com.asemlab.samples.activity_recognition.databinding.ActivityMainBinding
16+
import com.asemlab.samples.activity_recognition.services.ActivityUpdatesReceiver
1617
import com.asemlab.samples.activity_recognition.services.TransitionsReceiver
1718
import com.asemlab.samples.activity_recognition.utilties.Constants
1819
import com.google.android.material.bottomnavigation.BottomNavigationView
@@ -22,7 +23,9 @@ import dagger.hilt.android.AndroidEntryPoint
2223
class MainActivity : AppCompatActivity() {
2324

2425
private lateinit var binding: ActivityMainBinding
25-
private lateinit var receiver: TransitionsReceiver
26+
// TODO Create an instance from the custom receiver and un/register it
27+
private var receiver = ActivityUpdatesReceiver()
28+
// private var receiver: TransitionsReceiver = TransitionsReceiver()
2629

2730

2831
override fun onCreate(savedInstanceState: Bundle?) {
@@ -44,14 +47,11 @@ class MainActivity : AppCompatActivity() {
4447

4548
navView.setupWithNavController(navController)
4649

47-
// TODO Create an instance from the custom receiver and un/register it
48-
receiver = TransitionsReceiver()
49-
5050
}
5151

52-
53-
override fun onDestroy() {
54-
super.onDestroy()
52+
// TODO Register and unregister with suitable filter
53+
override fun onStop() {
54+
super.onStop()
5555
unregisterReceiver(receiver)
5656
}
5757

@@ -60,7 +60,7 @@ class MainActivity : AppCompatActivity() {
6060
ContextCompat.registerReceiver(
6161
this,
6262
receiver,
63-
IntentFilter(Constants.TRANSITIONS_RECEIVER_ACTION),
63+
IntentFilter(Constants.ACTIVITY_UPDATES_RECEIVER_ACTION), // OR TRANSITIONS_RECEIVER_ACTION
6464
ContextCompat.RECEIVER_EXPORTED
6565
)
6666
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ open class MainViewModel @Inject constructor(private val activitiesRepository: A
2424
fun addActivity(activityEntry: ActivityEntry) {
2525
viewModelScope.launch {
2626
withContext(Dispatchers.IO) {
27-
activitiesRepository.addActivity(activityEntry)
27+
if(activityEntry.points > 0)
28+
activitiesRepository.addActivity(activityEntry)
2829
}
2930
}
3031
}

0 commit comments

Comments
 (0)