Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.android.example.wear.ongoingactivity

import android.Manifest
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
Expand All @@ -27,6 +28,7 @@ import android.content.res.Configuration
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresPermission
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
Expand Down Expand Up @@ -65,6 +67,8 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
}

private lateinit var notificationManager: NotificationManager
private lateinit var notification: Notification
private lateinit var ongoingActivity: OngoingActivity

/*
* Checks whether the bound activity has really gone away (in which case a foreground service
Expand Down Expand Up @@ -144,8 +148,9 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
// we do nothing.
if (!configurationChange && walkingWorkoutActive) {
Log.d(TAG, "Start foreground service")
val notification =
notification =
generateNotification(getString(R.string.walking_workout_notification_started_text))
updateOngoingActivity(getString(R.string.walking_workout_notification_started_text))
// startForeground takes care of notificationManager.notify(...).
startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
serviceRunningInForeground = true
Expand All @@ -166,6 +171,7 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
configurationChange = false
}

@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
fun startWalkingWorkout() {
Log.d(TAG, "startWalkingWorkout()")

Expand Down Expand Up @@ -212,13 +218,12 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
// Normally, you would listen to the location and sensor data and calculate your points with
// an algorithm, but we are mocking the data to simply this so we can focus on learning about
// the Ongoing Activity API.
@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
private suspend fun mockSensorAndLocationForWalkingWorkout() {
for (walkingPoints in 0 until 100) {
if (serviceRunningInForeground) {
val notification = generateNotification(
getString(R.string.walking_points_text, walkingPoints),
)
notificationManager.notify(NOTIFICATION_ID, notification)
val updatedStatus = getString(R.string.walking_points_text, walkingPoints)
updateOngoingActivity(updatedStatus)
}
Log.d(TAG, "mockSensorAndLocationForWalkingWorkout(): $walkingPoints")
walkingWorkoutsRepository.setWalkingPoints(walkingPoints)
Expand Down Expand Up @@ -313,7 +318,7 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
.addTemplate(mainText)
.build()

val ongoingActivity =
ongoingActivity =
OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
// Sets icon that will appear on the watch face in active mode. If it isn't set,
// the watch face will use the static icon in active mode.
Expand All @@ -340,6 +345,15 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
return notificationBuilder.build()
}

@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
private fun updateOngoingActivity(statusText: String) {
val status = Status.Builder()
.addTemplate(statusText)
.build()

ongoingActivity.update(this, status)
}

/**
* Class used for the client Binder. Since this service runs in the same process as its
* clients, we don't need to deal with IPC.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.android.example.wear.ongoingactivity

import android.Manifest
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
Expand All @@ -27,9 +28,11 @@ import android.content.res.Configuration
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresPermission
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import androidx.wear.ongoing.OngoingActivity
import com.android.example.wear.ongoingactivity.data.WalkingWorkoutsRepository
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
Expand Down Expand Up @@ -63,6 +66,8 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
}

private lateinit var notificationManager: NotificationManager
private lateinit var notification: Notification
private lateinit var ongoingActivity: OngoingActivity

/*
* Checks whether the bound activity has really gone away (in which case a foreground service
Expand Down Expand Up @@ -141,9 +146,9 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
// NOTE: If this method is called due to a configuration change in MainActivity,
// we do nothing.
if (!configurationChange && walkingWorkoutActive) {
Log.d(TAG, "Start foreground service")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This log statement, which is useful for debugging, was removed. However, it's kept in the finished version of the file. This seems like an accidental deletion and introduces an inconsistency between the start and finished states of the codelab. Please consider keeping it.

val notification =
notification =
generateNotification(getString(R.string.walking_workout_notification_started_text))
updateOngoingActivity(getString(R.string.walking_workout_notification_started_text))
// startForeground takes care of notificationManager.notify(...).
startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC)
serviceRunningInForeground = true
Expand All @@ -164,6 +169,7 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
configurationChange = false
}

@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
fun startWalkingWorkout() {
Log.d(TAG, "startWalkingWorkout()")

Expand Down Expand Up @@ -210,13 +216,12 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
// Normally, you would listen to the location and sensor data and calculate your points with
// an algorithm, but we are mocking the data to simply this so we can focus on learning about
// the Ongoing Activity API.
@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
private suspend fun mockSensorAndLocationForWalkingWorkout() {
for (walkingPoints in 0 until 100) {
if (serviceRunningInForeground) {
val notification = generateNotification(
getString(R.string.walking_points_text, walkingPoints),
)
notificationManager.notify(NOTIFICATION_ID, notification)
val updatedStatus = getString(R.string.walking_points_text, walkingPoints)
updateOngoingActivity(updatedStatus)
Comment on lines +223 to +224
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This change replaces the notification update logic with a call to updateOngoingActivity, which is currently an empty method with a TODO. This results in a functional regression where the walking points are no longer updated in the notification for the start version of the codelab. While this might be to set up an exercise for the user, it leaves the app in a non-working state. Consider preserving the old notification update logic within the new updateOngoingActivity method to ensure the app remains functional at the beginning of this codelab step.

}
Log.d(TAG, "mockSensorAndLocationForWalkingWorkout(): $walkingPoints")
walkingWorkoutsRepository.setWalkingPoints(walkingPoints)
Expand Down Expand Up @@ -311,6 +316,11 @@ class ForegroundOnlyWalkingWorkoutService : LifecycleService() {
return notificationBuilder.build()
}

@RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
private fun updateOngoingActivity(statusText: String) {
// TODO: Update the Ongoing Activity.
}

/**
* Class used for the client Binder. Since this service runs in the same process as its
* clients, we don't need to deal with IPC.
Expand Down
Loading