Alguns apps para Wear OS ficam constantemente visíveis para o usuário.
Os dispositivos Wear OS com Android 5.1 ou posterior permitem que apps permaneçam em primeiro plano e economizem bateria ao mesmo tempo. Os apps Wear OS podem controlar o que é exibido no smartwatch enquanto ele está no modo de baixa energia (ambiente). Apps Wear que são executados no modo ambiente e no modo interativo são chamados de apps sempre ativos.
Esses apps permitem, por exemplo, que usuários olhem o smartwatch e vejam a distância e o tempo percorridos enquanto correm. Alguns usuários registram listas de compras e podem ver rapidamente os itens, caso necessário.
Tornar um app constantemente visível tem um impacto na duração da bateria, portanto, considere com cuidado esse impacto ao adicionar esse recurso ao app.
Importante: a versão 27.1.0 da Biblioteca de Suporte do Android permite uma nova maneira de oferecer compatibilidade com o modo ambiente, que usa a classe AmbientModeSupport
em vez da classe WearableActivity
.
Você pode decidir se quer usar a nova maneira preferencial para oferecer compatibilidade com o modo ambiente ou se quer estender a classe WearableActivity.
Observação: a classe AmbientMode
se tornou obsoleta e foi substituída pela classe AmbientModeSupport
.
Confira os seguintes recursos relacionados:
Configurar seu projeto
Para oferecer compatibilidade com o modo ambiente, você precisa atualizar o SDK do Android e configurar o projeto de desenvolvimento. Siga estas etapas para fazer as alterações necessárias:
- Crie ou atualize seu projeto com base nas configurações da página Criar e executar um app para wearables.
- Adicione a permissão
WAKE_LOCK
ao arquivo de manifesto do Android:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Modo ambiente usando a classe AmbientModeSupport
Usar a classe AmbientModeSupport
para oferecer compatibilidade com o modo ambiente permite que você se beneficie de:
-
subclasses de
Activity
na Biblioteca de Suporte do Android, comoFragmentActivity
, em que a funcionalidade para fragmentos está disponível; - componentes de arquitetura, que reconhecem o ciclo de vida;
- suporte aprimorado para o Login do Google.
Para usar a classe AmbientModeSupport
, estenda uma das subclasses FragmentActivity
ou a própria FragmentActivity e implementar uma interface de provedor, que por sua vez, pode ser usada para ouvir atualizações do modo ambiente.
Observação: o método AmbientModeSupport.attach(FragmentActivity)
anexa um fragmento headless à classe ou subclasse FragmentActivity
fornecida, chamando subsequentemente FragmentManager.getFragments()
para retornar uma referência a esse fragmento, que não precisa ser usado.
As etapas a seguir descrevem o uso geral da classe AmbientModeSupport
:
-
Crie uma subclasse de uma das classes
FragmentActivity
. -
Implemente a interface
AmbientCallbackProvider
, como no exemplo abaixo. Substitua o métodogetAmbientCallback()
para fornecer os callbacks necessários para reagir a eventos de ambiente do sistema Android. Na Etapa 4, criaremos a classe de callback personalizada.Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { … override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = MyAmbientCallback() … }
Java
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { … @Override public AmbientModeSupport.AmbientCallback getAmbientCallback() { return new MyAmbientCallback(); } … }
-
No método
onCreate()
, ative o modo ambiente chamandoAmbientModeSupport.attach(FragmentActivity)
. Esse método retorna umAmbientModeSupport.AmbientController
. O controlador permite verificar o estado do ambiente fora dos callbacks. É recomendável manter uma referência ao objetoAmbientModeSupport.AmbientController
:Kotlin
class MainActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private lateinit var ambientController: AmbientModeSupport.AmbientController ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ... ambientController = AmbientModeSupport.attach(this) } ... }
Java
public class MainActivity extends AppCompatActivity implements AmbientModeSupport.AmbientCallbackProvider { ... /* * Declare an ambient mode controller, which will be used by * the activity to determine if the current mode is ambient. */ private AmbientModeSupport.AmbientController ambientController; ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ... ambientController = AmbientModeSupport.attach(this); } ... }
-
Crie uma classe interna que estenda a classe
AmbientCallback
para agir em eventos de ambiente. Essa classe se torna o objeto retornado do método criado na Etapa 2:Kotlin
private class MyAmbientCallback : AmbientModeSupport.AmbientCallback() { override fun onEnterAmbient(ambientDetails: Bundle?) { // Handle entering ambient mode } override fun onExitAmbient() { // Handle exiting ambient mode } override fun onUpdateAmbient() { // Update the content } }
Java
private class MyAmbientCallback extends AmbientModeSupport.AmbientCallback { @Override public void onEnterAmbient(Bundle ambientDetails) { // Handle entering ambient mode } @Override public void onExitAmbient() { // Handle exiting ambient mode } @Override public void onUpdateAmbient() { // Update the content } }
Leia as seções da amostra de AlwaysOn para mais informações e práticas recomendadas.
Modo ambiente usando a classe WearableActivity
Para projetos novos e existentes, você pode adicionar compatibilidade com o modo ambiente ao app Wear ao atualizar a configuração do seu projeto.
Criar uma atividade compatível com o modo ambiente
Você pode ativar o modo ambiente na sua atividade usando a classe
WearableActivity
:
-
Crie uma atividade que
WearableActivity
. -
No método
onCreate()
da sua atividade, chame o métodosetAmbientEnabled()
.
Ative o modo ambiente na sua atividade da seguinte maneira:
Kotlin
class MainActivity : WearableActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ... } }
Java
public class MainActivity extends WearableActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ... }
Processar transições entre modos
Se o usuário não interagir com seu app por um período enquanto ele estiver sendo exibido ou se o usuário cobrir a tela com a palma da mão, o sistema alternará a atividade para o modo ambiente. Depois que o app for alternado para o modo ambiente, atualize a IU da atividade para um layout mais básico a fim de reduzir o consumo de energia. Use um plano de fundo preto com o mínimo de elementos gráficos e textos brancos. Para facilitar a transição do modo interativo para o ambiente, tente manter um posicionamento de itens semelhante na tela. Para mais informações sobre apresentação de conteúdo no modo ambiente, consulte o guia de design Mostradores de relógio para Wear OS.
Quando seu app é executado em um dispositivo sem um botão físico, colocar a mão sobre a tela não alterna o app para o modo ambiente. Em vez disso, essa ação faz com que o app seja fechado e a tela inicial apareça. Assim, usuários podem sair dos apps facilmente. No entanto, esses dispositivos ainda entram no modo ambiente quando a tela fica ociosa por muito tempo.
Observação: no modo ambiente, desative todos os elementos interativos na tela, como botões. Para mais informações sobre como criar interações do usuário em um app sempre ativo, consulte o guia de design Estrutura do app para o Wear OS (em inglês).
Quando a atividade muda para o modo ambiente, o sistema chama o método onEnterAmbient()
na atividade do wearable. O snippet de código a seguir mostra como alterar a cor do texto para branco e desativar o anti-aliasing quando o sistema alternar para o modo ambiente:
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) stateTextView.setTextColor(Color.WHITE) stateTextView.paint.isAntiAlias = false }
Java
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); stateTextView.setTextColor(Color.WHITE); stateTextView.getPaint().setAntiAlias(false); }
Quando o usuário toca na tela ou levanta o pulso, a atividade alterna do modo ambiente para o modo interativo. O sistema chama o método onExitAmbient()
. Modifique esse método para atualizar o layout da IU para que seu app seja exibido em um estado interativo colorido.
O snippet de código a seguir mostra como alterar a cor do texto para verde e ativar o anti-aliasing quando o sistema alternar para o modo interativo:
Kotlin
override fun onExitAmbient() { super.onExitAmbient() stateTextView.setTextColor(Color.GREEN) stateTextView.paint.isAntiAlias = true }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); stateTextView.setTextColor(Color.GREEN); stateTextView.getPaint().setAntiAlias(true); }
Atualizar conteúdo no modo ambiente
O modo ambiente permite que você atualize a tela com novas informações para o usuário, mas você precisa equilibrar cuidadosamente as atualizações de tela com a duração da bateria. Considere modificar apenas o método
onUpdateAmbient()
para atualizar a tela uma vez por minuto no modo ambiente. Caso seu app precise de atualizações mais frequentes, leve em conta que existe uma troca entre a duração da bateria e a frequência de atualizações. Para economizar bateria, as atualizações não precisam acontecer mais do que uma vez a cada 10 segundos. Na prática, no entanto, atualize seu app com menos frequência.
Atualizar uma vez por minuto
Para economizar bateria, a maioria dos apps para Wear não precisa atualizar a tela com frequência no modo ambiente. Recomendamos projetar o app para atualizar a tela uma vez por minuto quando estiver nesse modo. O sistema disponibiliza um método de callback, onUpdateAmbient()
, que permite atualizar a tela com essa frequência recomendada.
Para atualizar o conteúdo do seu app, modifique o método onUpdateAmbient()
da atividade do wearable:
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
Java
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
Atualizar com mais frequência
É possível, embora não seja recomendado, atualizar um app para Wear mais de uma vez por minuto no modo ambiente. Em apps que exijam atualizações mais frequentes, você pode usar um objeto AlarmManager
para ativar o processador e atualizar a tela com mais frequência.
Para implementar um alarme que atualiza o conteúdo com mais frequência no modo ambiente, siga estas etapas:
- Prepare o gerenciador de alarmes.
- Defina a frequência das atualizações.
- Programe a próxima atualização quando a atividade for alternada para o modo ambiente ou estiver no modo ambiente.
- Cancele o alarme quando a atividade alternar para o modo interativo ou a atividade for interrompida.
Observação: o gerenciador de alarmes pode criar novas instâncias para sua atividade à medida que são acionadas. Para evitar essa situação, certifique-se de que sua atividade seja declarada com o parâmetro android:launchMode="singleInstance"
no manifesto.
As seções a seguir descrevem essas etapas em detalhes.
Preparar o gerenciador de alarmes
O gerenciador de alarmes abre um intent pendente que atualiza a tela e programa o próximo alarme. O exemplo a seguir mostra como declarar o gerenciador de alarmes e o intent pendente no método onCreate()
da sua atividade:
Kotlin
// Action for updating the display in ambient mode, per our custom refresh cycle. private const val AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE" ... private lateinit var ambientUpdateAlarmManager: AlarmManager private lateinit var ambientUpdatePendingIntent: PendingIntent private lateinit var ambientUpdateBroadcastReceiver: BroadcastReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setAmbientEnabled() ambientUpdateAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager ambientUpdatePendingIntent = Intent(AMBIENT_UPDATE_ACTION).let { ambientUpdateIntent -> PendingIntent.getBroadcast(this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT) } ambientUpdateBroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { refreshDisplayAndSetNextUpdate() } } ... }
Java
// Action for updating the display in ambient mode, per our custom refresh cycle. private static final String AMBIENT_UPDATE_ACTION = "com.your.package.action.AMBIENT_UPDATE"; private AlarmManager ambientUpdateAlarmManager; private PendingIntent ambientUpdatePendingIntent; private BroadcastReceiver ambientUpdateBroadcastReceiver; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAmbientEnabled(); ambientUpdateAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent ambientUpdateIntent = new Intent(AMBIENT_UPDATE_ACTION); ambientUpdatePendingIntent = PendingIntent.getBroadcast( this, 0, ambientUpdateIntent, PendingIntent.FLAG_UPDATE_CURRENT); ambientUpdateBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { refreshDisplayAndSetNextUpdate(); } }; ... }
Agora, precisamos registrar e cancelar o broadcast receiver em onResume()
e onPause()
:
Kotlin
override fun onResume() { super.onResume() IntentFilter(AMBIENT_UPDATE_ACTION).also { filter -> registerReceiver(ambientUpdateBroadcastReceiver, filter) } } override fun onPause() { super.onPause() unregisterReceiver(ambientUpdateBroadcastReceiver) ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(AMBIENT_UPDATE_ACTION); registerReceiver(ambientUpdateBroadcastReceiver, filter); ... } @Override public void onPause() { super.onPause(); unregisterReceiver(ambientUpdateBroadcastReceiver); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); ... }
Atualizar tela e agendar atualizações de dados
Nesta atividade de exemplo, o gerenciador de alarmes é acionado a cada 20 segundos no modo ambiente. Quando o timer é iniciado, o alarme aciona o intent para atualizar a tela e define em quanto tempo ocorrerá a próxima atualização.
O exemplo a seguir mostra como atualizar as informações na tela e definir o alarme para a próxima atualização:
Kotlin
// Milliseconds between waking processor/screen for updates private val AMBIENT_INTERVAL_MS: Long = TimeUnit.SECONDS.toMillis(20) ... private fun refreshDisplayAndSetNextUpdate() { if (isAmbient) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } val timeMs: Long = System.currentTimeMillis() // Schedule a new alarm if (isAmbient) { // Calculate the next trigger time val delayMs: Long = AMBIENT_INTERVAL_MS - timeMs % AMBIENT_INTERVAL_MS val triggerTimeMs: Long = timeMs + delayMs ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent) } else { // Calculate the next trigger time for interactive mode } }
Java
// Milliseconds between waking processor/screen for updates private static final long AMBIENT_INTERVAL_MS = TimeUnit.SECONDS.toMillis(20); private void refreshDisplayAndSetNextUpdate() { if (isAmbient()) { // Implement data retrieval and update the screen for ambient mode } else { // Implement data retrieval and update the screen for interactive mode } long timeMs = System.currentTimeMillis(); // Schedule a new alarm if (isAmbient()) { // Calculate the next trigger time long delayMs = AMBIENT_INTERVAL_MS - (timeMs % AMBIENT_INTERVAL_MS); long triggerTimeMs = timeMs + delayMs; ambientUpdateAlarmManager.setExact( AlarmManager.RTC_WAKEUP, triggerTimeMs, ambientUpdatePendingIntent); } else { // Calculate the next trigger time for interactive mode } }
Programar o próximo alarme
Programe o alarme para atualizar a tela quando a atividade estiver entrando no modo ambiente ou quando a atividade já estiver nele. Para isso, modifique os métodos onEnterAmbient()
e onUpdateAmbient()
:
Kotlin
override fun onEnterAmbient(ambientDetails: Bundle?) { super.onEnterAmbient(ambientDetails) refreshDisplayAndSetNextUpdate() } override fun onUpdateAmbient() { super.onUpdateAmbient() refreshDisplayAndSetNextUpdate() }
Java
@Override public void onEnterAmbient(Bundle ambientDetails) { super.onEnterAmbient(ambientDetails); refreshDisplayAndSetNextUpdate(); } @Override public void onUpdateAmbient() { super.onUpdateAmbient(); refreshDisplayAndSetNextUpdate(); }
Observação: nesse exemplo, o método refreshDisplayAndSetNextUpdate()
é chamado sempre que a tela precisa ser atualizada. Para mais exemplos de quando chamar esse método, veja a amostra de AlwaysOn.
Cancelar o alarme
Quando o dispositivo alternar para o modo interativo, cancele o alarme no método onExitAmbient()
:
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
Quando o usuário sair ou interromper a atividade, cancele o alarme no método onDestroy()
da atividade:
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
Java
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }
Manter compatibilidade com versões anteriores
As atividades compatíveis com o modo ambiente retornam automaticamente às atividades normais em dispositivos Wear com versões do Android anteriores à 5.1 (API de nível 22). Nenhum código de app especial é necessário para oferecer compatibilidade com dispositivos dessas versões do Android. Quando o dispositivo alternar para o modo ambiente, retornará para a tela inicial e sairá da atividade.
Caso seu app não precise ser instalado ou atualizado em dispositivos com versões do Android anteriores à 5.1, atualize o manifesto com o seguinte:
<uses-library android:name="com.google.android.wearable" android:required="true" />