From 63782ce2e6afcc111869d67a0dc07bbdf736bc10 Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Thu, 2 Oct 2025 17:03:59 +0100 Subject: [PATCH 1/7] Create android_wear_ongoing_activity_create_notification --- gradle/libs.versions.toml | 2 +- .../wear/snippets/alwayson/AlwaysOnService.kt | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e4701a474..d02cdf75e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -76,7 +76,7 @@ wear = "1.3.0" wearComposeFoundation = "1.5.0-rc02" wearComposeMaterial = "1.5.0-rc02" wearComposeMaterial3 = "1.5.0-rc02" -wearOngoing = "1.0.0" +wearOngoing = "1.1.0" wearToolingPreview = "1.0.0" webkit = "1.14.0" diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index 59ed0f8af..379d693ff 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -22,6 +22,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.os.SystemClock import android.util.Log import androidx.core.app.NotificationCompat import androidx.core.content.getSystemService @@ -29,6 +30,7 @@ import androidx.lifecycle.LifecycleService import androidx.wear.ongoing.OngoingActivity import androidx.wear.ongoing.Status import com.example.wear.R +import java.util.concurrent.TimeUnit class AlwaysOnService : LifecycleService() { @@ -122,8 +124,7 @@ class AlwaysOnService : LifecycleService() { .setOngoing(true) // [START_EXCLUDE] - // Create an Ongoing Activity - val ongoingActivityStatus = Status.Builder().addTemplate("Stopwatch running").build() + val ongoingActivityStatus = createOngoingStatus() // [END_EXCLUDE] val ongoingActivity = @@ -142,4 +143,22 @@ class AlwaysOnService : LifecycleService() { return notificationBuilder.build() } // [END android_wear_ongoing_activity_create_notification] + + private fun createOngoingStatus(): Status { + // [START android_wear_ongoing_activity_create_status] + val statusTemplate = "#type# for #time#" + + // Creates a 5 minute timer. + // Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis(). + val runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5) + + val ongoingActivityStatus = Status.Builder() + .addTemplate(statusTemplate) + .addPart("type", Status.TextPart("Run")) + .addPart("time", Status.StopwatchPart(runStartTime)) + .build() + // [END android_wear_ongoing_activity_create_status] + + return ongoingActivityStatus + } } From f2d56bcd514154980769f6a15c523ca6e2ccccb4 Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 11:38:27 +0100 Subject: [PATCH 2/7] Ongoing activity improvements --- .../wear/snippets/alwayson/AlwaysOnService.kt | 118 ++++++++++++++++-- 1 file changed, 105 insertions(+), 13 deletions(-) diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index 379d693ff..4778ebf67 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -68,9 +68,7 @@ class AlwaysOnService : LifecycleService() { super.onStartCommand(intent, flags, startId) Log.d(TAG, "onStartCommand: Service started with startId: $startId") - // Create and start foreground notification - val notification = createNotification() - startForeground(NOTIFICATION_ID, notification) + createNotification1() Log.d(TAG, "onStartCommand: Service is now running as foreground service") @@ -95,8 +93,9 @@ class AlwaysOnService : LifecycleService() { Log.d(TAG, "createNotificationChannel: Notification channel created") } - // [START android_wear_ongoing_activity_create_notification] - private fun createNotification(): Notification { + // Creates an ongoing activity that demonstrates how to link the touch intent to the always-on activity. + private fun createNotification1(): Unit { + // [START android_wear_ongoing_activity_create_notification] val activityIntent = Intent(this, AlwaysOnActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP @@ -124,7 +123,7 @@ class AlwaysOnService : LifecycleService() { .setOngoing(true) // [START_EXCLUDE] - val ongoingActivityStatus = createOngoingStatus() + val ongoingActivityStatus = Status.Builder().addTemplate("Stopwatch running").build() // [END_EXCLUDE] val ongoingActivity = @@ -140,25 +139,118 @@ class AlwaysOnService : LifecycleService() { ongoingActivity.apply(applicationContext) - return notificationBuilder.build() + val notification = notificationBuilder.build() + // [END android_wear_ongoing_activity_create_notification] // where's the equivalent START? should this even be here? check the docs jjjjjjj + + startForeground(NOTIFICATION_ID, notification) } - // [END android_wear_ongoing_activity_create_notification] - private fun createOngoingStatus(): Status { + // Creates an ongoing activity with a static status text + private fun createNotification2(): Unit { + + // [START android_wear_ongoing_activity_notification_builder] + // Create a PendingIntent to pass to the notification builder + val pendingIntent = + PendingIntent.getActivity( + this, + 0, + Intent(this, AlwaysOnActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_SINGLE_TOP + }, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Always On Service") + .setContentText("Service is running in background") + .setSmallIcon(R.drawable.animated_walk) + // Category helps the system prioritize the ongoing activity + .setCategory(NotificationCompat.CATEGORY_WORKOUT) + .setContentIntent(pendingIntent) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setOngoing(true) // Important! + // [END android_wear_ongoing_activity_notification_builder] + + // [START android_wear_ongoing_activity_builder] + val ongoingActivity = + OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder) + // Sets the icon that appears on the watch face in active mode. + .setAnimatedIcon(R.drawable.animated_walk) + // Sets the icon that appears on the watch face in ambient mode. + .setStaticIcon(R.drawable.ic_walk) + // Sets the tap target to bring the user back to the app. + .setTouchIntent(pendingIntent) + .build() + // [END android_wear_ongoing_activity_builder] + + // [START android_wear_ongoing_activity_post_notification] + // This call modifies notificationBuilder to include the ongoing activity data. + ongoingActivity.apply(applicationContext) + + // Post the notification. + startForeground(NOTIFICATION_ID, notificationBuilder.build()) + // [END android_wear_ongoing_activity_post_notification] + } + + // Creates an ongoing activity that demonstrates dynamic status text (a timer) + private fun createNotification3(): Unit { + val activityIntent = + Intent(this, AlwaysOnActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_SINGLE_TOP + } + + val pendingIntent = + PendingIntent.getActivity( + this, + 0, + activityIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + + val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Always On Service") + .setContentText("Service is running in background") + .setSmallIcon(R.drawable.animated_walk) + // Category helps the system prioritize the ongoing activity + .setCategory(NotificationCompat.CATEGORY_WORKOUT) + .setContentIntent(pendingIntent) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setOngoing(true) // Important! + // [START android_wear_ongoing_activity_create_status] + // Define a template with placeholders for the activity type and the timer. val statusTemplate = "#type# for #time#" - // Creates a 5 minute timer. - // Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis(). - val runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5) + // Set the start time for a stopwatch. + // Use SystemClock.elapsedRealtime() for time-based parts. + val runStartTime = SystemClock.elapsedRealtime() val ongoingActivityStatus = Status.Builder() + // Sets the template string. .addTemplate(statusTemplate) + // Fills the #type# placeholder with a static text part. .addPart("type", Status.TextPart("Run")) + // Fills the #time# placeholder with a stopwatch part. .addPart("time", Status.StopwatchPart(runStartTime)) .build() // [END android_wear_ongoing_activity_create_status] - return ongoingActivityStatus + // [START android_wear_ongoing_activity_set_status] + val ongoingActivity = + OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder) + // [START_EXCLUDE] + .setAnimatedIcon(R.drawable.animated_walk) + .setStaticIcon(R.drawable.ic_walk) + .setTouchIntent(pendingIntent) + // [END_EXCLUDE] + // Add the status to the OngoingActivity. + .setStatus(ongoingActivityStatus) + .build() + // [END android_wear_ongoing_activity_set_status] + + ongoingActivity.apply(applicationContext) + startForeground(NOTIFICATION_ID, notificationBuilder.build()) + } + } From a2d9b4c8a1008d66a0931f56f23677f1c91171a4 Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 11:38:47 +0100 Subject: [PATCH 3/7] Spotless updates --- .../example/wear/snippets/alwayson/AlwaysOnService.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index 4778ebf67..4fce91952 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -16,7 +16,6 @@ package com.example.wear.snippets.alwayson -import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent @@ -30,7 +29,6 @@ import androidx.lifecycle.LifecycleService import androidx.wear.ongoing.OngoingActivity import androidx.wear.ongoing.Status import com.example.wear.R -import java.util.concurrent.TimeUnit class AlwaysOnService : LifecycleService() { @@ -94,7 +92,7 @@ class AlwaysOnService : LifecycleService() { } // Creates an ongoing activity that demonstrates how to link the touch intent to the always-on activity. - private fun createNotification1(): Unit { + private fun createNotification1() { // [START android_wear_ongoing_activity_create_notification] val activityIntent = Intent(this, AlwaysOnActivity::class.java).apply { @@ -146,7 +144,7 @@ class AlwaysOnService : LifecycleService() { } // Creates an ongoing activity with a static status text - private fun createNotification2(): Unit { + private fun createNotification2() { // [START android_wear_ongoing_activity_notification_builder] // Create a PendingIntent to pass to the notification builder @@ -193,7 +191,7 @@ class AlwaysOnService : LifecycleService() { } // Creates an ongoing activity that demonstrates dynamic status text (a timer) - private fun createNotification3(): Unit { + private fun createNotification3() { val activityIntent = Intent(this, AlwaysOnActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP @@ -250,7 +248,5 @@ class AlwaysOnService : LifecycleService() { ongoingActivity.apply(applicationContext) startForeground(NOTIFICATION_ID, notificationBuilder.build()) - } - } From ad51e8c88326f00545414e869cca3ab62fed4fef Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 11:53:53 +0100 Subject: [PATCH 4/7] Explain how to exercise different codepaths --- .../java/com/example/wear/snippets/alwayson/AlwaysOnService.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index 4fce91952..7270db2d8 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -66,7 +66,10 @@ class AlwaysOnService : LifecycleService() { super.onStartCommand(intent, flags, startId) Log.d(TAG, "onStartCommand: Service started with startId: $startId") + // Switch between different types of ongoing notification createNotification1() + // createNotification2() + // createNotification3() Log.d(TAG, "onStartCommand: Service is now running as foreground service") From 7a3976468f74b1bb29f15116f3d1b63eadc58bbc Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 12:33:36 +0100 Subject: [PATCH 5/7] Generalize AlwaysOnService with multiple versions --- wear/src/main/AndroidManifest.xml | 16 ++++- .../snippets/alwayson/AlwaysOnActivity.kt | 64 +++++++++++-------- .../wear/snippets/alwayson/AlwaysOnService.kt | 48 +++++++------- 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml index c2a0bb52f..a70ca62db 100644 --- a/wear/src/main/AndroidManifest.xml +++ b/wear/src/main/AndroidManifest.xml @@ -224,7 +224,21 @@ + + + + + + ?>(null) } + MaterialTheme( colorScheme = dynamicColorScheme(LocalContext.current) ?: MaterialTheme.colorScheme ) { - // [START android_wear_ongoing_activity_ambientaware] AmbientAware { ambientState -> - // [START_EXCLUDE] Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text(text = "Elapsed Time", style = MaterialTheme.typography.titleLarge) Spacer(modifier = Modifier.height(8.dp)) - // [END_EXCLUDE] ElapsedTime(ambientState = ambientState) - // [START_EXCLUDE] Spacer(modifier = Modifier.height(8.dp)) - SwitchButton( - checked = isOngoingActivity, - onCheckedChange = { newState -> - Log.d(TAG, "Switch button changed: $newState") - isOngoingActivity = newState - - if (newState) { - Log.d(TAG, "Starting AlwaysOnService") - AlwaysOnService.startService(context) - } else { - Log.d(TAG, "Stopping AlwaysOnService") - AlwaysOnService.stopService(context) - } - }, - contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), - ) { - Text( - text = "Ongoing Activity", - style = MaterialTheme.typography.bodyExtraSmall, - ) + + val services = listOf( + AlwaysOnService1::class.java, + AlwaysOnService2::class.java, + AlwaysOnService3::class.java + ) + + services.forEachIndexed { index, serviceClass -> + val isRunning = runningService == serviceClass + SwitchButton( + checked = isRunning, + onCheckedChange = { newState -> + if (newState) { + if (runningService != null) { + Log.d(TAG, "Stopping ${runningService?.simpleName}") + context.stopService(Intent(context, runningService)) + } + Log.d(TAG, "Starting ${serviceClass.simpleName}") + val intent = Intent(context, serviceClass) + context.startForegroundService(intent) + runningService = serviceClass + } else { + Log.d(TAG, "Stopping ${serviceClass.simpleName}") + context.stopService(Intent(context, serviceClass)) + runningService = null + } + }, + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + text = "Ongoing Activity ${index + 1}", + style = MaterialTheme.typography.bodyExtraSmall, + ) + } } } } - // [END_EXCLUDE] } - // [END android_wear_ongoing_activity_ambientaware] } } diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index 7270db2d8..fc4df7cc5 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -19,7 +19,6 @@ package com.example.wear.snippets.alwayson import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent -import android.content.Context import android.content.Intent import android.os.SystemClock import android.util.Log @@ -30,29 +29,19 @@ import androidx.wear.ongoing.OngoingActivity import androidx.wear.ongoing.Status import com.example.wear.R -class AlwaysOnService : LifecycleService() { +abstract class AlwaysOnServiceBase : LifecycleService() { private val notificationManager by lazy { getSystemService() } companion object { private const val TAG = "AlwaysOnService" - private const val NOTIFICATION_ID = 1001 - private const val CHANNEL_ID = "always_on_service_channel" + const val NOTIFICATION_ID = 1001 + const val CHANNEL_ID = "always_on_service_channel" private const val CHANNEL_NAME = "Always On Service" + @Volatile var isRunning = false private set - - fun startService(context: Context) { - Log.d(TAG, "Starting AlwaysOnService") - val intent = Intent(context, AlwaysOnService::class.java) - context.startForegroundService(intent) - } - - fun stopService(context: Context) { - Log.d(TAG, "Stopping AlwaysOnService") - context.stopService(Intent(context, AlwaysOnService::class.java)) - } } override fun onCreate() { @@ -66,16 +55,15 @@ class AlwaysOnService : LifecycleService() { super.onStartCommand(intent, flags, startId) Log.d(TAG, "onStartCommand: Service started with startId: $startId") - // Switch between different types of ongoing notification - createNotification1() - // createNotification2() - // createNotification3() + createNotification() Log.d(TAG, "onStartCommand: Service is now running as foreground service") return START_STICKY } + + override fun onDestroy() { Log.d(TAG, "onDestroy: Service destroyed") isRunning = false @@ -94,8 +82,12 @@ class AlwaysOnService : LifecycleService() { Log.d(TAG, "createNotificationChannel: Notification channel created") } - // Creates an ongoing activity that demonstrates how to link the touch intent to the always-on activity. - private fun createNotification1() { + abstract fun createNotification() +} + +class AlwaysOnService1 : AlwaysOnServiceBase() { + override fun createNotification() { + // Creates an ongoing activity that demonstrates how to link the touch intent to the always-on activity. // [START android_wear_ongoing_activity_create_notification] val activityIntent = Intent(this, AlwaysOnActivity::class.java).apply { @@ -145,9 +137,11 @@ class AlwaysOnService : LifecycleService() { startForeground(NOTIFICATION_ID, notification) } +} - // Creates an ongoing activity with a static status text - private fun createNotification2() { +class AlwaysOnService2 : AlwaysOnServiceBase() { + override fun createNotification() { + // Creates an ongoing activity with a static status text // [START android_wear_ongoing_activity_notification_builder] // Create a PendingIntent to pass to the notification builder @@ -192,9 +186,11 @@ class AlwaysOnService : LifecycleService() { startForeground(NOTIFICATION_ID, notificationBuilder.build()) // [END android_wear_ongoing_activity_post_notification] } +} - // Creates an ongoing activity that demonstrates dynamic status text (a timer) - private fun createNotification3() { +class AlwaysOnService3 : AlwaysOnServiceBase() { + override fun createNotification() { + // Creates an ongoing activity that demonstrates dynamic status text (a timer) val activityIntent = Intent(this, AlwaysOnActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP @@ -252,4 +248,4 @@ class AlwaysOnService : LifecycleService() { ongoingActivity.apply(applicationContext) startForeground(NOTIFICATION_ID, notificationBuilder.build()) } -} +} \ No newline at end of file From 95a6ddc153b233e13a50308d37c067b70874d5b7 Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 12:45:35 +0100 Subject: [PATCH 6/7] Update UI --- .../snippets/alwayson/AlwaysOnActivity.kt | 89 +++++++++++-------- .../wear/snippets/alwayson/AlwaysOnService.kt | 4 +- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnActivity.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnActivity.kt index 20e4609f6..0f936b5cb 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnActivity.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnActivity.kt @@ -26,12 +26,14 @@ import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height +import androidx.wear.compose.foundation.lazy.AutoCenteringParams +import androidx.wear.compose.foundation.lazy.ScalingLazyColumn +import androidx.wear.compose.foundation.lazy.items +import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -143,51 +145,64 @@ fun ElapsedTime(ambientState: AmbientState) { fun WearApp() { val context = LocalContext.current var runningService by rememberSaveable { mutableStateOf?>(null) } + val listState = rememberScalingLazyListState() MaterialTheme( colorScheme = dynamicColorScheme(LocalContext.current) ?: MaterialTheme.colorScheme ) { AmbientAware { ambientState -> - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { + ScalingLazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState, + horizontalAlignment = Alignment.CenterHorizontally, + autoCentering = AutoCenteringParams(itemIndex = 0) + ) { + item { Text(text = "Elapsed Time", style = MaterialTheme.typography.titleLarge) + } + item { Spacer(modifier = Modifier.height(8.dp)) + } + item { ElapsedTime(ambientState = ambientState) + } + item { Spacer(modifier = Modifier.height(8.dp)) + } - val services = listOf( - AlwaysOnService1::class.java, - AlwaysOnService2::class.java, - AlwaysOnService3::class.java - ) - - services.forEachIndexed { index, serviceClass -> - val isRunning = runningService == serviceClass - SwitchButton( - checked = isRunning, - onCheckedChange = { newState -> - if (newState) { - if (runningService != null) { - Log.d(TAG, "Stopping ${runningService?.simpleName}") - context.stopService(Intent(context, runningService)) - } - Log.d(TAG, "Starting ${serviceClass.simpleName}") - val intent = Intent(context, serviceClass) - context.startForegroundService(intent) - runningService = serviceClass - } else { - Log.d(TAG, "Stopping ${serviceClass.simpleName}") - context.stopService(Intent(context, serviceClass)) - runningService = null - } - }, - contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), - ) { - Text( - text = "Ongoing Activity ${index + 1}", - style = MaterialTheme.typography.bodyExtraSmall, - ) - } + val services = listOf( + AlwaysOnService1::class.java, + AlwaysOnService2::class.java, + AlwaysOnService3::class.java + ) + + items(services.size) { index -> + val serviceClass = services[index] + val isRunning = runningService == serviceClass + SwitchButton( + checked = isRunning, + onCheckedChange = { newState -> + if (newState) { + if (runningService != null) { + Log.d(TAG, "Stopping ${runningService?.simpleName}") + context.stopService(Intent(context, runningService)) + } + Log.d(TAG, "Starting ${serviceClass.simpleName}") + val intent = Intent(context, serviceClass) + context.startForegroundService(intent) + runningService = serviceClass + } else { + Log.d(TAG, "Stopping ${serviceClass.simpleName}") + context.stopService(Intent(context, serviceClass)) + runningService = null + } + }, + contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp), + ) { + Text( + text = "Ongoing Activity ${index + 1}", + style = MaterialTheme.typography.bodySmall, + ) } } } diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index fc4df7cc5..e21b3bd89 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -62,8 +62,6 @@ abstract class AlwaysOnServiceBase : LifecycleService() { return START_STICKY } - - override fun onDestroy() { Log.d(TAG, "onDestroy: Service destroyed") isRunning = false @@ -248,4 +246,4 @@ class AlwaysOnService3 : AlwaysOnServiceBase() { ongoingActivity.apply(applicationContext) startForeground(NOTIFICATION_ID, notificationBuilder.build()) } -} \ No newline at end of file +} From 3d13a91c5b0a22cff30484e33dfd85096413546a Mon Sep 17 00:00:00 2001 From: Michael Stillwell Date: Tue, 7 Oct 2025 13:11:14 +0100 Subject: [PATCH 7/7] Remove comment --- .../java/com/example/wear/snippets/alwayson/AlwaysOnService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt index e21b3bd89..d52db8fd8 100644 --- a/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt +++ b/wear/src/main/java/com/example/wear/snippets/alwayson/AlwaysOnService.kt @@ -131,7 +131,7 @@ class AlwaysOnService1 : AlwaysOnServiceBase() { ongoingActivity.apply(applicationContext) val notification = notificationBuilder.build() - // [END android_wear_ongoing_activity_create_notification] // where's the equivalent START? should this even be here? check the docs jjjjjjj + // [END android_wear_ongoing_activity_create_notification] startForeground(NOTIFICATION_ID, notification) }