Este guia explica como deixar seu app sempre ativo, como reagir a transições de estado de energia e como gerenciar o comportamento do aplicativo para oferecer uma boa experiência do usuário enquanto economiza bateria.
Tornar um app constantemente visível afeta significativamente a duração da bateria. Por isso, considere o impacto no consumo de energia ao adicionar esse recurso.
Principais conceitos
Quando um app para Wear OS é mostrado em tela cheia, ele está em um de dois estados de energia:
- Interativo: um estado de alta potência em que a tela está com brilho máximo, permitindo a interação total do usuário.
- Ambiente: um estado de baixo consumo de energia em que a tela escurece para economizar energia. Nesse estado, a interface do app ainda ocupa a tela inteira, mas o sistema pode alterar a aparência dela desfocando ou mostrando conteúdo de sobreposição, como a hora. Isso também é chamado de Modo ambiente.
O sistema operacional controla a transição entre esses estados.
Um app sempre ativo é um aplicativo que mostra conteúdo nos estados Interativo e Ambiente.
Quando um app sempre ativo continua mostrando a própria interface enquanto o dispositivo está no estado de baixo consumo de energia Ambient, ele é descrito como estando no modo ambiactivo.
Transições do sistema e comportamento padrão
Quando um app está em primeiro plano, o sistema gerencia as transições de estado de energia com base em dois tempos limite acionados pela inatividade do usuário.
- Tempo limite 1: estado interativo para ambiente:após um período de inatividade do usuário, o dispositivo entra no estado Ambiente.
- Timeout nº 2: voltar ao mostrador do relógio:após um período adicional de inatividade, o sistema pode ocultar o app atual e mostrar o mostrador do relógio.
Imediatamente após a primeira transição do sistema para o estado Ambient, o comportamento padrão depende da versão do Wear OS e da configuração do app:
- No Wear OS 5 e versões anteriores, o sistema mostra uma captura de tela desfocada do aplicativo pausado, com o tempo sobreposto na parte de cima. Esse estado é representado pelo nó "AOD Lite" no fluxograma a seguir.
- No Wear OS 6 e versões mais recentes, se um app segmentar o SDK 36 ou mais recente, ele será considerado sempre ativo. A tela fica esmaecida, mas o aplicativo continua em execução e visível. As atualizações podem ser tão raras quanto uma vez por minuto. Esse estado é representado pelo nó "Global AOD" no fluxograma a seguir.
Personalizar o comportamento do estado ambiente
Independente do comportamento padrão do sistema, em todas as versões do Wear OS, é possível
personalizar a aparência ou o comportamento do app no estado Ambient usando
LocalAmbientModeManager para observar as transições de estado no
Jetpack Compose no Wear OS. Esse estado é representado pelo nó "Modo Ambiactive" no fluxograma a seguir.
Observar o estado ambiente
Para reagir a eventos do modo ambiente no Jetpack Compose no Wear OS:
Use
LocalAmbientModeManagerpara observar mudanças no status do modo ambiente do sistema e ajustar seus elementos combináveis de acordo. Configure o componente para se ajustar a um modo de baixo consumo de energia no estadoAmbientMode.Ambiente restaure-o para uma tela interativa completa no 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 desenvolvedores que usam o Jetpack Compose, use LocalAmbientModeManager, que
simplifica a implementação desse padrão.
Fluxograma de comportamento ambiente
O fluxograma a seguir ilustra como o sistema determina o comportamento
ambiente com base na versão do Wear OS do dispositivo, no targetSdkVersion do seu app
e se ele implementa AmbientLifecycleCallback.
Controlar a duração da tela ativada
As seções a seguir descrevem como gerenciar o tempo que o app fica na tela.
Evitar voltar ao mostrador do relógio com uma atividade em andamento ou uma atualização em tempo real
Depois de um período no estado Ambiente (tempo limite nº 2), o sistema normalmente volta ao mostrador do relógio. O usuário pode configurar a duração do tempo limite nas configurações do sistema. Em alguns casos de uso, como um usuário monitorando um treino, um app pode precisar ficar visível por mais tempo.
No Wear OS 5 e em versões mais recentes, é possível evitar isso implementando uma Atividade em andamento. Se o app estiver mostrando informações sobre uma tarefa em andamento do usuário, como uma sessão de treino, use a API Ongoing Activity para manter o app visível até que a tarefa termine. Se um usuário voltar manualmente ao mostrador do relógio, o indicador de atividade em andamento vai oferecer uma maneira de retornar ao seu app com um toque.
Como alternativa, no Wear OS 7 e em versões mais recentes, use uma Atualização dinâmica em vez de uma atividade em andamento. Para compatibilidade com versões anteriores, continue oferecendo suporte à Atividade em andamento em dispositivos com o Wear OS 6 ou versões anteriores.
Para implementar isso, a intent de toque da notificação em andamento precisa apontar para sua atividade sempre ativa, conforme mostrado no snippet de código a seguir:
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()
Manter a tela ativada e evitar o estado ambiente
Em casos raros, talvez seja necessário impedir completamente que o dispositivo entre no estado
Ambiente. Ou seja, para evitar o tempo limite nº 1. Para isso, use o
modificador keepScreenOn. Isso funciona como um wake lock, mantendo
o dispositivo no estado Interativo. Use com muito cuidado, já que isso afeta bastante a duração da bateria.
Recomendações para o Modo ambiente
Para oferecer a melhor experiência do usuário e economizar energia no modo Ambiente, siga estas diretrizes de design. Essas recomendações priorizam uma experiência do usuário clara, evitando informações enganosas e reduzindo a poluição visual, ao mesmo tempo em que otimizam o poder de exibição.
- Reduza a poluição visual e a potência da tela. Uma interface limpa e minimalista indica ao usuário que o app está em um estado de baixo consumo de energia e economiza bateria significativamente ao limitar pixels brilhantes.
- Mantenha pelo menos 85% da tela preta.
- Mostre apenas as informações mais importantes, movendo os detalhes secundários para a tela interativa.
- Use contornos em vez de preenchimentos sólidos para ícones ou botões grandes.
- Evite grandes blocos de cores sólidas e branding ou imagens de fundo não funcionais.
- Processar dados dinâmicos desatualizados
- O callback
AmbientTickEffecté invocado apenas periodicamente, geralmente uma vez por minuto, para economizar energia. Devido a essa limitação, os dados que mudam com frequência, como um cronômetro, a frequência cardíaca ou a distância do treino, ficam desatualizados entre as atualizações. Para evitar mostrar informações enganosas e incorretas, substitua esses valores dinâmicos por conteúdo de marcador de posição estático, como--.
- O callback
- Mantenha um layout consistente
- Mantenha os elementos na mesma posição nos modos Interativo e Ambiente para criar uma transição suave.
- Sempre mostrar a hora.
- Esteja ciente do contexto
- Se o usuário estiver em uma tela de configurações ou configuração quando o dispositivo entrar no modo ambiente, considere mostrar uma tela mais relevante do seu app em vez da visualização de configurações.
- Processar requisitos específicos do dispositivo
- No objeto
AmbientModeretornado decurrentAmbientMode:- Se
isLowBitAmbientSupportedfortrue, desative a suavização sempre que possível. - Se
isBurnInProtectionRequiredfortrue, mude os elementos da interface ligeramente de forma periódica e evite áreas brancas sólidas para evitar a queima da tela.
- Se
- No objeto
Depuração e testes
Estes comandos adb podem ser úteis ao desenvolver ou testar o comportamento do app
quando o dispositivo está no 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
Exemplo: app de treino
Imagine um app de treino que precisa mostrar métricas ao usuário durante toda a sessão de exercícios. O app precisa permanecer visível durante as transições de estado do Ambient e não ser substituído pelo mostrador do relógio.
Para isso, o desenvolvedor precisa fazer o seguinte:
- Use
LocalAmbientModeManagerpara processar mudanças na interface entre os estados Interativo e Ambiente, como escurecer a tela e remover dados não essenciais. - Crie um novo layout de baixo consumo de energia para o estado Ambient que siga as práticas recomendadas.
- Use a API Ongoing Activity (ou Atualizações dinâmicas no Wear OS 7 e versões mais recentes) durante o treino para impedir que o sistema volte ao mostrador do relógio.
Para uma implementação completa, consulte o Exemplo de exercício (link em inglês) baseado no Compose no
GitHub. Este exemplo também demonstra o uso do
elemento combinável LocalAmbientModeManager para simplificar o processamento do modo ambiente
no Compose.