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 superponiendo contenido, 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 ambiente activo.
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 interactivo a ambiente: Después de un período de inactividad del usuario, el dispositivo ingresa al 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 se representa con 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 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 se representa con 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
AmbientLifecycleObserver para escuchar devoluciones de llamada en las transiciones de estado. Este estado se representa con el nodo "Modo ambiente activo" en el
siguiente diagrama de flujo.
Usa AmbientLifecycleObserver
Para reaccionar a los eventos del modo ambiente, usa la AmbientLifecycleObserver clase:
Implementa la
AmbientLifecycleObserver.AmbientLifecycleCallbackinterfaz. Usa el métodoonEnterAmbient()para ajustar la IU para el estado de baja potencia yonExitAmbient()para restablecerla a la pantalla interactiva completa.val ambientCallback = object : AmbientLifecycleObserver.AmbientLifecycleCallback { override fun onEnterAmbient(ambientDetails: AmbientLifecycleObserver.AmbientDetails) { // ... Called when moving from interactive mode into ambient mode. // Adjust UI for low-power state: dim colors, hide non-essential elements. } override fun onExitAmbient() { // ... Called when leaving ambient mode, back into interactive mode. // Restore full UI. } override fun onUpdateAmbient() { // ... Called by the system periodically (typically once per minute) // to allow the app to update its display while in ambient mode. } }
Crea un
AmbientLifecycleObservery regístralo con el ciclo de vida de tu actividad o elemento componible.private val ambientObserver = AmbientLifecycleObserver(activity, ambientCallback) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(ambientObserver) // ... }
Llama a
removeObserver()para quitar el observador enonDestroy().override fun onDestroy() { super.onDestroy() lifecycle.removeObserver(ambientObserver) // ... }
Para los desarrolladores que usan Jetpack Compose, la biblioteca de Horologist proporciona una utilidad útil, el elemento componible AmbientAware, que simplifica la implementación
de este patrón.
TimeText compatible con el ambiente
Como excepción a la necesidad de un observador personalizado, en Wear OS 6, el TimeText
widget es compatible con el ambiente. Se actualiza automáticamente una vez por minuto cuando el dispositivo está en el estado Ambiente sin ningún código adicional.
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, el 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 un usuario que 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 ingrese al estado Ambiente. Es decir, para evitar el tiempo de espera n.° 1. Para ello, puedes usar la
FLAG_KEEP_SCREEN_ON marca de ventana. Esto funciona como un bloqueo de activación, lo que mantiene el dispositivo en el estado Interactiva. Úsala 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, ya que limita 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
onUpdateAmbient()se 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, escucha la devolución de llamadaonEnterAmbienty 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 ingresa al 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
AmbientDetailsque se pasa aonEnterAmbient(), haz lo siguiente:- Si
deviceHasLowBitAmbientestrue, inhabilita el suavizado de contorno siempre que sea posible. - Si
burnInProtectionRequiredestrue, 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 lograrlo, el desarrollador debe hacer lo siguiente:
- Implementa un
AmbientLifecycleObserverpara 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 elemento AmbientAware
componible de la biblioteca de Horologist para simplificar el control del modo ambiente
en Compose.