interface AmbientModeManager


Summary

Public functions

suspend Unit
withAmbientTick(block: () -> Unit)

Suspends the calling coroutine and waits for the next delivered "ambient tick".

Public properties

AmbientMode

The current state of the display, which is either AmbientMode.Interactive or AmbientMode.Ambient.

Extension functions

Unit

A convenience extension that performs recurrent, battery-efficient UI updates when the device is in AmbientMode.Ambient.

Public functions

withAmbientTick

Added in 1.6.0-alpha08
suspend fun withAmbientTick(block: () -> Unit): Unit

Suspends the calling coroutine and waits for the next delivered "ambient tick".

When the device is in AmbientMode.Ambient, the system only provides updates at infrequent intervals (typically once per minute) to preserve battery life. This function allows a coroutine to pause and resume execution specifically when that tick is received.

The provided block will be executed synchronously when the tick occurs, and any state updates performed within it will be reflected on the ambient screen.

This function should typically be used within a looping LaunchedEffect that runs only when currentAmbientMode is AmbientMode.Ambient.

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.wear.compose.foundation.AmbientMode
import androidx.wear.compose.foundation.AmbientTickEffect
import androidx.wear.compose.foundation.LocalAmbientModeManager
import androidx.wear.compose.foundation.rememberAmbientModeManager
import androidx.wear.compose.material.Text

// **Best Practice Note:** In a production application, the AmbientModeManager should be
// instantiated and provided at the highest level of the Compose hierarchy (typically in
// the host Activity's setContent block) using a CompositionLocalProvider. This ensures
// proper lifecycle management and broad accessibility.

// For this self-contained demo, AmbientModeManager is created and provided locally:
val activityAmbientModeManager =
    rememberAmbientModeManager(LocalContext.current.findActivityOrNull()!!)
CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) {
    var counter by remember { mutableIntStateOf(0) }

    val ambientModeManager = LocalAmbientModeManager.current
    ambientModeManager?.AmbientTickEffect {
        // While device is in ambient mode, update counter in onAmbientTick approx. every minute
        counter++
    }

    val ambientMode = ambientModeManager?.currentAmbientMode
    if (ambientMode is AmbientMode.Interactive) {
        // While device is not in ambient mode, update counter approx. every second
        LaunchedEffect(Unit) {
            while (true) {
                delay(1000L)
                counter++
            }
        }
    }

    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize(),
    ) {
        val ambientModeName =
            ambientMode?.let {
                when (it) {
                    is AmbientMode.Interactive -> "Interactive"
                    is AmbientMode.Ambient -> "Ambient"
                }
            } ?: "Unknown"

        val updateInterval = if (ambientMode is AmbientMode.Ambient) "minute" else "second"
        val color = if (ambientMode is AmbientMode.Ambient) Color.Gray else Color.Yellow

        Text(text = "$ambientModeName Mode", color = color)
        Text(text = "Updates every $updateInterval")
        Text(text = "$counter")
    }
}
Parameters
block: () -> Unit

The state update logic to execute immediately upon receiving the ambient tick.

Public properties

currentAmbientMode

Added in 1.6.0-alpha08
val currentAmbientModeAmbientMode

The current state of the display, which is either AmbientMode.Interactive or AmbientMode.Ambient.

This property should be backed by Compose's Snapshot State system. Reading this value inside a composable function should automatically subscribe the composable to state changes and trigger a recomposition when the ambient mode changes.

Extension functions

@Composable
fun AmbientModeManager.AmbientTickEffect(block: () -> Unit): Unit

A convenience extension that performs recurrent, battery-efficient UI updates when the device is in AmbientMode.Ambient.

This extension handles the boilerplate for ambient tick synchronization: it automatically launches and manages a LaunchedEffect that repeatedly suspends using withAmbientTick to align state updates with the system's infrequent ambient tick schedule.

The internal loop automatically terminates when the device returns to AmbientMode.Interactive.

Efficiency Note: The block lambda should only update the minimal androidx.compose.runtime.State required to prevent excessive recomposition and maximize battery life.

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.wear.compose.foundation.AmbientMode
import androidx.wear.compose.foundation.AmbientTickEffect
import androidx.wear.compose.foundation.LocalAmbientModeManager
import androidx.wear.compose.foundation.rememberAmbientModeManager
import androidx.wear.compose.material.Text

// **Best Practice Note:** In a production application, the AmbientModeManager should be
// instantiated and provided at the highest level of the Compose hierarchy (typically in
// the host Activity's setContent block) using a CompositionLocalProvider. This ensures
// proper lifecycle management and broad accessibility.

// For this self-contained demo, AmbientModeManager is created and provided locally:
val activityAmbientModeManager =
    rememberAmbientModeManager(LocalContext.current.findActivityOrNull()!!)
CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) {
    var counter by remember { mutableIntStateOf(0) }

    val ambientModeManager = LocalAmbientModeManager.current
    ambientModeManager?.AmbientTickEffect {
        // While device is in ambient mode, update counter in onAmbientTick approx. every minute
        counter++
    }

    val ambientMode = ambientModeManager?.currentAmbientMode
    if (ambientMode is AmbientMode.Interactive) {
        // While device is not in ambient mode, update counter approx. every second
        LaunchedEffect(Unit) {
            while (true) {
                delay(1000L)
                counter++
            }
        }
    }

    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize(),
    ) {
        val ambientModeName =
            ambientMode?.let {
                when (it) {
                    is AmbientMode.Interactive -> "Interactive"
                    is AmbientMode.Ambient -> "Ambient"
                }
            } ?: "Unknown"

        val updateInterval = if (ambientMode is AmbientMode.Ambient) "minute" else "second"
        val color = if (ambientMode is AmbientMode.Ambient) Color.Gray else Color.Yellow

        Text(text = "$ambientModeName Mode", color = color)
        Text(text = "Updates every $updateInterval")
        Text(text = "$counter")
    }
}
Parameters
block: () -> Unit

The state update logic to execute once per ambient tick.