En esta guía, se explica cómo hacer que tu app esté siempre activa, cómo reaccionar a las transiciones de estado de energía y cómo administrar el comportamiento de la aplicación para brindar una buena experiencia del usuario y, al mismo tiempo, conservar la batería.
Hacer que una app sea visible constantemente afecta significativamente la duración de la batería, por lo que debes tener en cuenta el impacto en la energía cuando agregues esta función.
Conceptos clave
Cuando una app para Wear OS se muestra en pantalla completa, se encuentra en uno de los dos estados de energía:
- Interactiva: Es un estado de alta potencia en el que la pantalla tiene el brillo máximo, lo que permite la interacción completa del usuario.
- Ambiente: Es un estado de baja potencia en el que la pantalla se atenúa para conservar energía. En este estado, la IU de tu app aún ocupa la pantalla completa, pero el sistema puede alterar su apariencia desenfocándola o mostrando contenido superpuesto, como la hora. Esto también se conoce como Modo ambiente.
El sistema operativo controla la transición entre estos estados.
Una app siempre activa es una aplicación que muestra contenido en los estados Interactiva y Ambiente.
Cuando una app siempre activa continúa mostrando su propia IU mientras el dispositivo está en el estado Ambiente de baja potencia, se describe como que está en modo ambiactivo.
Transiciones del sistema y comportamiento predeterminado
Cuando una app está en primer plano, el sistema administra las transiciones de estado de energía en función de dos tiempos de espera que se activan por la inactividad del usuario.
- Tiempo de espera n.° 1: Estado de interactivo a ambiente: Después de un período de inactividad del usuario, el dispositivo entra en el estado Ambiente.
- Tiempo de espera n.° 2: Regresar a la cara de reloj: Después de un período de inactividad adicional, el sistema puede ocultar la app actual y mostrar la cara de reloj.
Inmediatamente después de que el sistema pasa por la primera transición al estado Ambiente, el comportamiento predeterminado depende de la versión de Wear OS y de la configuración de tu app:
- En Wear OS 5 y versiones anteriores, el sistema muestra una captura de pantalla desenfocada de la aplicación en pausa, con la hora superpuesta en la parte superior. Este estado está representado por el nodo "AOD Lite" en el siguiente diagrama de flujo.
- En Wear OS 6 y versiones posteriores, si una app se orienta al SDK 36 o versiones posteriores, se considera que está siempre activa. La pantalla se atenúa, pero la aplicación continúa ejecutándose y permanece visible (las actualizaciones pueden ser tan poco frecuentes como una vez por minuto). Este estado está representado por el nodo "Global AOD" en el siguiente diagrama de flujo.
Personaliza el comportamiento para el estado Ambiente
Independientemente del comportamiento predeterminado del sistema, en todas las versiones de Wear OS, puedes
personalizar la apariencia o el comportamiento de tu app mientras está en el estado Ambiente usando
LocalAmbientModeManager para observar las transiciones de estado en
Jetpack Compose en Wear OS. Este estado está representado por el nodo "Modo ambiactivo"
en el siguiente diagrama de flujo.
Observa el estado ambiente
Para reaccionar a los eventos del modo ambiente en Jetpack Compose en Wear OS, haz lo siguiente:
Usa
LocalAmbientModeManagerpara observar los cambios en el estado del modo ambiente del sistema y ajustar los elementos componibles en consecuencia. Configura tu componente para que se ajuste a un modo de menor potencia en el estadoAmbientMode.Ambienty restablécelo a una pantalla interactiva completa en el estadoAmbientMode.Interactive.// 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() CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) { val ambientModeManager = LocalAmbientModeManager.current val ambientMode = ambientModeManager?.currentAmbientMode if (ambientModeManager != null) { ambientModeManager.AmbientTickEffect { // While device is in ambient mode, update properties every minute or so // ... } } // ... val ambientModeName = when (ambientMode) { is AmbientMode.Interactive -> "Interactive" is AmbientMode.Ambient -> "Ambient" else -> "Unknown" } Text(text = "$ambientModeName Mode") // ... }
Para los desarrolladores que usan Jetpack Compose, usa LocalAmbientModeManager, que
simplifica la implementación de este patrón.
Diagrama de flujo del comportamiento ambiente
En el siguiente diagrama de flujo, se ilustra cómo el sistema determina el comportamiento ambiente en función de la versión de Wear OS del dispositivo, la targetSdkVersion de tu app y si implementa AmbientLifecycleCallback.
Controla la duración de la pantalla encendida
En las siguientes secciones, se describe cómo administrar el tiempo que tu app permanece en la pantalla.
Evita regresar a la cara de reloj con una actividad en curso o una actualización en vivo
Después de un período en el estado Ambiente (tiempo de espera n.° 2), el sistema suele regresar a la cara de reloj. El usuario puede configurar la duración del tiempo de espera en la configuración del sistema. En ciertos casos de uso, como cuando un usuario hace un seguimiento de un entrenamiento, es posible que una app deba permanecer visible durante más tiempo.
En Wear OS 5 y versiones posteriores, puedes evitar esto implementando una actividad en curso. Si tu app muestra información sobre una tarea en curso del usuario, como una sesión de entrenamiento, puedes usar la API de Ongoing Activity para mantener tu app visible hasta que finalice la tarea. Si un usuario regresa manualmente a la cara de reloj, el indicador de actividad en curso le proporciona una forma de presionar una vez para volver a tu app.
Como alternativa, en Wear OS 7 y versiones posteriores, puedes usar una actualización en vivo en lugar de una actividad en curso. Para garantizar la retrocompatibilidad, sigue admitiendo la actividad en curso en dispositivos que ejecutan Wear OS 6 o versiones anteriores.
Para implementar esto, el intent táctil de la notificación en curso debe apuntar a tu actividad siempre activa, como se muestra en el siguiente fragmento de código:
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) // ... // ... .setOngoing(true) // ... val ongoingActivity = OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder) // ... // ... .setTouchIntent(pendingIntent) .build() ongoingActivity.apply(applicationContext) val notification = notificationBuilder.build()
Mantén la pantalla encendida y evita el estado Ambiente
En casos excepcionales, es posible que debas evitar por completo que el dispositivo entre en el estado Ambiente. Es decir, para evitar el tiempo de espera n.° 1. Para ello, puedes usar el
keepScreenOn modificador. Esto funciona como un bloqueo de activación, lo que mantiene el dispositivo en el estado Interactiva. Usa esto con extrema precaución, ya que afecta gravemente la duración de la batería.
Recomendaciones para el modo ambiente
Para brindar la mejor experiencia del usuario y conservar energía en el modo Ambiente, sigue estos lineamientos de diseño. Estas recomendaciones priorizan una experiencia del usuario clara, ya que evitan la información engañosa y reducen el desorden visual, a la vez que optimizan la energía de la pantalla.
- Reduce el desorden visual y la energía de la pantalla. Una IU limpia y minimalista le indica al usuario que la app está en un estado de baja potencia y ahorra una cantidad significativa de batería al limitar los píxeles brillantes.
- Mantén al menos el 85% de la pantalla en negro.
- Muestra solo la información más importante y mueve los detalles secundarios a la pantalla interactiva.
- Usa contornos para íconos o botones grandes en lugar de rellenos sólidos.
- Evita los bloques grandes de color sólido y las imágenes de marca o de fondo no funcionales.
- Controla los datos dinámicos obsoletos
- La devolución de llamada
AmbientTickEffectse invoca solo de forma periódica (por lo general, una vez por minuto) para conservar energía. Debido a esta limitación, cualquier dato que cambie con frecuencia, como un cronómetro, la frecuencia cardíaca o la distancia de entrenamiento, se vuelve obsoleto entre las actualizaciones. Para evitar mostrar información engañosa e incorrecta, reemplaza estos valores en vivo por contenido de marcador de posición estático, como--.
- La devolución de llamada
- Mantén un diseño coherente
- Mantén los elementos en la misma posición en los modos Interactiva y Ambiente para crear una transición fluida.
- Muestra siempre la hora.
- Ten en cuenta el contexto
- Si el usuario estaba en una pantalla de configuración cuando el dispositivo entra en el modo ambiente, considera mostrar una pantalla más relevante de tu app en lugar de la vista de configuración.
- Controla los requisitos específicos del dispositivo
- En el objeto
AmbientModeque se muestra desdecurrentAmbientMode:- Si
isLowBitAmbientSupportedestrue, inhabilita el suavizado de contorno siempre que sea posible. - Si
isBurnInProtectionRequiredestrue, cambia periódicamente los elementos de la IU ligeramente y evita las áreas blancas sólidas para evitar la protección de pantalla.
- Si
- En el objeto
Depuración y pruebas
Estos adb comandos pueden ser útiles cuando desarrollas o pruebas el comportamiento de tu app
cuando el dispositivo está en modo ambiente:
# put device in ambient mode if the always on display is enabled in settings
# (and not disabled by other settings, such as theatre mode)
$ adb shell input keyevent KEYCODE_SLEEP
# put device in interactive mode
$ adb shell input keyevent KEYCODE_WAKEUP
Ejemplo: App de entrenamiento
Considera una app de entrenamiento que necesita mostrar métricas al usuario durante toda la sesión de ejercicio. La app debe permanecer visible durante las transiciones de estado Ambiente y evitar que se reemplace por la cara de reloj.
Para lograr esto, el desarrollador debe hacer lo siguiente:
- Usa
LocalAmbientModeManagerpara controlar los cambios en la IU entre los estados Interactiva y Ambiente, como atenuar la pantalla y quitar datos no esenciales. - Crea un nuevo diseño de baja potencia para el estado Ambiente que siga las prácticas recomendadas.
- Usa la API de Ongoing Activity (o las actualizaciones en vivo en Wear OS 7 y versiones posteriores) durante el entrenamiento para evitar que el sistema regrese a la cara de reloj.
Para ver una implementación completa, consulta el ejemplo de Exercise basado en Compose en
GitHub. En este ejemplo, también se muestra el uso del
LocalAmbientModeManager elemento componible para simplificar el control del modo ambiente
en Compose.