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 ativado é 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 Ambiente, 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 nº 1: estado interativo para ambiente:após um período de inatividade do usuário, o dispositivo entra no estado Ambiente.
- Tempo limite 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.
Logo após a primeira transição do sistema para o estado Ambiente, o comportamento padrão depende da versão do Wear OS e da configuração do seu 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 em versões mais recentes, se um app for destinado ao 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") // ... }
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 app
e se ele observa transições de estado ambiente (usando
LocalAmbientModeManager ou AmbientLifecycleCallback).
Controlar a duração da tela ativada
As seções a seguir descrevem como gerenciar o tempo que seu app fica na tela.
Impedir o retorno 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é o fim da tarefa. Se um usuário voltar manualmente para o mostrador do relógio, o indicador de atividade em andamento vai oferecer uma maneira de retornar ao 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 ligada e evitar o estado ambiente
Em casos raros, pode ser 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 extrema cautela, já que isso afeta muito 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 energia 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 (uma proporção de pixels ativos de 15% ou menos).
- 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, ajustando o contraste do contorno para que os elementos permaneçam legíveis sem risco de trepidação ou burn-in da tela.
- Evite grandes blocos de cores sólidas e imagens de marca ou de fundo não funcionais.
- Processar dados dinâmicos e animações 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 incorretas e enganosas, substitua esses valores dinâmicos por conteúdo de marcador de posição estático, como--. - Remova indicadores de progresso que exigem atualizações frequentes para serem úteis no contexto ou situação atual do usuário, como círculos de progresso para sessões de mídia curtas. Você pode manter indicadores de progresso em situações em que atualizações a cada minuto ainda são úteis, como em cronômetros longos.
- Pause ou remova todas as animações no modo ambiente, incluindo indicadores de progresso animados e texto de marcação rolando.
- O callback
- Mantenha um layout consistente
- Mantenha os elementos na mesma posição nos modos Interativo e Ambiente para criar uma transição suave. Elementos interativos da interface, como botões, podem permanecer visíveis porque os dispositivos modernos do Wear OS oferecem suporte a entrada por toque durante sessões ambientais.
- Sempre mostrar a hora atual. No Jetpack Compose para Wear OS,
o
TimeText(incluído por padrão emScreenScaffold) é sensível ao ambiente e é atualizado automaticamente uma vez por minuto no modo ambiente.
- Tenha consciência 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
- Quando
currentAmbientModeretornaAmbientMode.Ambient:- Se
isLowBitAmbientSupportedfortrue, a tela vai aceitar menos bits por cor no modo ambiente. Desative o anti-aliasing (por exemplo, em operações de desenho personalizadas deCanvasouPaint) e evite gradientes de cor sempre que possível. - Se
isBurnInProtectionRequiredfortrue, o sistema vai mudar periodicamente o conteúdo da tela para evitar o efeito burn-in. Não mova manualmente elementos da interface no app. Em vez disso, evite áreas brancas sólidas e posicione elementos essenciais da interface a pelo menos 10 pixels da borda da tela para que não sejam cortados quando o sistema mover a tela. Os layouts padrão do Wear Compose, comoScreenScaffold, já oferecem padding de borda suficiente.
- Se
- Quando
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
Considere um app de treino que precisa mostrar métricas ao usuário durante toda a duração da 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 Ambiente 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 todo o treino para evitar 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.