Algunas apps para Wear OS están visibles de manera constante para el usuario.
Los dispositivos con Wear OS que ejecutan Android 5.1 o versiones posteriores permiten que las apps permanezcan en primer plano y, al mismo tiempo, ahorran batería. Las apps para Wear OS pueden controlar lo que se muestra en el reloj mientras que este está en el modo de bajo consumo (ambiente). Las apps para Wear que se ejecutan tanto en el modo ambiente como en el interactivo se llaman apps siempre activas.
Estas permiten que los usuarios que están trotando vean en el reloj la distancia recorrida y el tiempo transcurrido. Algunos usuarios guardan listas de compras y pueden ver rápidamente los artículos incluidos mientras compran.
Habilitar una app para que esté visible constantemente afecta la duración de la batería, por lo que debes considerar especialmente ese impacto cuando agregues esta función a la tuya.
Importante: La versión 27.1.0 de la biblioteca de compatibilidad de Android habilita una nueva forma de admitir el modo ambiente que usa la clase AmbientModeSupport
en lugar de la clase WearableActivity
.
Puedes elegir la nueva forma preferida para admitir el modo ambiente o, en su lugar, extender la clase WearableActivity.
Nota: La clase AmbientMode
dejó de estar disponible y se reemplazó por la clase AmbientModeSupport
.
Consulta los siguientes recursos relacionados:
Cómo configurar tu proyecto
Para admitir el modo ambiente, debes actualizar tu SDK de Android y configurar tu proyecto de desarrollo. Para realizar los cambios necesarios, sigue estos pasos:
- Crea o actualiza tu proyecto de acuerdo con la configuración de la página Cómo crear y ejecutar una app para wearables.
- Agrega el permiso
WAKE_LOCK
al archivo de manifiesto de Android:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Modo ambiente con la clase AmbientModeSupport
El uso de la clase AmbientModeSupport
para admitir el modo ambiente te permite beneficiarte de lo siguiente:
- Las subclases
Activity
de la biblioteca de compatibilidad de Android, comoFragmentActivity
(la funcionalidad para fragmentos está disponible) - Componentes de arquitectura que tienen en cuenta el ciclo de vida
- Mayor compatibilidad con el Acceso con Google
Para usar la clase AmbientModeSupport
, debes extender una de las subclases de FragmentActivity
y, luego, implementar una interfaz de proveedor, que a su vez puede usarse para detectar actualizaciones del modo ambiente.
Nota: El método AmbientModeSupport.attach(FragmentActivity)
adjunta un fragmento sin interfaz gráfica a la clase o subclase FragmentActivity
que proporcionas, y las llamadas subsiguientes a FragmentManager.getFragments()
muestran una referencia a este fragmento (que no debe usarse de ninguna manera).
A continuación, se describe el uso general de la clase AmbientModeSupport
:
- Crea una subclase de una de las clases
FragmentActivity
. -
Implementa la interfaz
AmbientCallbackProvider
, como en el siguiente ejemplo. Anula el métodogetAmbientCallback()
con el objetivo de proporcionar las devoluciones de llamada necesarias para reaccionar a eventos ambientales del sistema Android. En el Paso 4, crearemos la clase de devolución de llamada 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(); } … }
-
En el método
onCreate()
, habilita el modo ambiente. Para ello, llama aAmbientModeSupport.attach(FragmentActivity)
. Este método muestra un elementoAmbientModeSupport.AmbientController
. El controlador te permite verificar el estado ambiente fuera de las devoluciones de llamada; es recomendable mantener una referencia al 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); } ... }
-
Crea una clase interna que extienda la clase
AmbientCallback
para actuar sobre los eventos de ambiente. Esta se convertirá en el objeto que se muestra en el método que creaste en el paso 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 } }
Consulta el ejemplo de AlwaysOn para obtener más información y las prácticas recomendadas.
Modo ambiente con la clase WearableActivity
Tanto en proyectos nuevos como existentes, puedes agregar compatibilidad con el modo ambiente a tu app para Wear si actualizas la configuración de tu proyecto.
Cómo crear una actividad que admita el modo ambiente
Puedes usar la clase
WearableActivity
para habilitar el modo ambiente en tu actividad:
- Crea una actividad que extienda
WearableActivity
. - En el método
onCreate()
de tu actividad, llama al métodosetAmbientEnabled()
.
Habilita el modo ambiente en tu actividad de la siguiente manera:
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(); ... }
Cómo administrar transiciones entre modos
Si el usuario no interactúa con tu app durante un tiempo mientras esta se muestra, o bien si cubre la pantalla con la palma de la mano, el sistema activará el modo ambiente. Una vez que la app active el modo ambiente, actualiza la IU de actividad a un diseño más básico para reducir el consumo de energía. Deberías usar un fondo negro con la menor cantidad de gráficos y texto posible, ambos en color blanco. Para que la transición del modo interactivo al modo ambiente no sea muy brusca para el usuario, intenta mantener los elementos de la pantalla en el mismo lugar. Si quieres obtener más información sobre cómo presentar el contenido en una pantalla ambiente, consulta la guía de diseño de Caras de reloj para Wear OS.
Ten en cuenta que cuando tu app se ejecuta en un dispositivo que no tiene un botón de hardware, al cubrir la pantalla con la palma de la mano, la app no activa el modo ambiente, sino que se cierra y se muestra la pantalla principal. Este comportamiento se creó para garantizar que los usuarios puedan salir de las apps de manera fluida. No obstante, estos dispositivos activarán el modo ambiente de todas formas cuando se agote el tiempo de espera de la pantalla.
Nota: En el modo ambiente, inhabilita los elementos interactivos en pantalla, como los botones. Si quieres obtener más información sobre cómo diseñar interacciones del usuario para una app siempre activa, consulta la guía de diseño de Estructura de apps para Wear OS.
Cuando la actividad realiza un cambio al modo ambiente, el sistema llama al método onEnterAmbient()
en tu actividad para wearables. En el siguiente fragmento de código, se muestra cómo cambiar el color del texto a blanco y cómo inhabilitar la opción de suavizado de contorno luego de que el sistema cambie al 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); }
Cuando el usuario presiona la pantalla o levanta la muñeca, la actividad cambia del modo ambiente al interactivo. El sistema llama al método onExitAmbient()
. Anula este método para actualizar el diseño de la IU de manera que tu app se muestre en un estado interactivo a todo color.
En el siguiente fragmento de código, se muestra cómo cambiar el color de texto a verde y habilitar la opción de suavizado de contorno cuando el sistema cambia al modo interactivo:
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); }
Cómo actualizar contenido en el modo ambiente
El modo ambiente te permite actualizar la pantalla con información nueva para el usuario, pero debes lograr un balance entre las actualizaciones de pantalla y la duración de batería. Deberías considerar anular únicamente el método
onUpdateAmbient()
para actualizar la pantalla una vez por minuto en el modo ambiente. Si tu app requiere actualizaciones más frecuentes, ten en cuenta que hay una relación entre la duración de batería y la frecuencia de las actualizaciones. Para ahorrar batería, las actualizaciones no deberían tener una frecuencia mayor que una vez cada 10 segundos. Sin embargo, en la práctica, deberías actualizar tu app con menor frecuencia.
Cómo actualizar una vez por minuto
Con el fin de preservar la batería, la mayoría de las apps de Wear no deberían actualizar frecuentemente la pantalla en el modo ambiente. Te recomendamos que diseñes tu app para que actualice la pantalla una vez por minuto cuando esté en este modo. El sistema proporciona un método de devolución de llamada, onUpdateAmbient()
, que te permite actualizar la pantalla con la frecuencia recomendada.
Para actualizar el contenido de tu app, anula el método onUpdateAmbient()
en tu actividad wearable:
Kotlin
override fun onUpdateAmbient() { super.onUpdateAmbient() // Update the content }
Java
@Override public void onUpdateAmbient() { super.onUpdateAmbient(); // Update the content }
Cómo actualizar con mayor frecuencia
Si bien no se recomienda, es posible actualizar una app para Wear en el modo ambiente con una frecuencia mayor que una vez por minuto. En el caso de las apps que requieren actualizaciones más frecuentes, puedes usar un objeto AlarmManager
a fin de activar el procesador y actualizar la pantalla más seguido.
Para implementar una alarma que actualice el contenido con mayor frecuencia en el modo ambiente, sigue estos pasos:
- Prepara el administrador de alarmas.
- Establece la frecuencia de las actualizaciones.
- Programa la próxima actualización cuando la actividad cambie al modo ambiente o si actualmente está en este modo.
- Cancela la alarma cuando la actividad cambie al modo interactivo o cuando esta se detenga.
Nota: Es posible que el administrador de alarmas cree nuevas instancias de tu actividad a medida que estas se activen. Para evitarlo, asegúrate de que tu actividad esté declarada con el parámetro android:launchMode="singleInstance"
en el manifiesto.
En las siguientes secciones, se describen esos pasos en detalle.
Cómo preparar el administrador de alarmas
El administrador de alarmas inicia el intent pendiente que actualiza la pantalla y programa la siguiente alarma. En el siguiente ejemplo, se muestra cómo declarar el administrador de alarmas y el intent pendiente en el método onCreate()
de tu actividad:
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(); } }; ... }
Ahora, debemos registrar y cancelar el registro del receptor de emisión en onResume()
y 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); ... }
Cómo actualizar la pantalla y programar actualizaciones de datos
En esta actividad de ejemplo, el administrador de alarmas se activa cada 20 segundos en el modo ambiente. Cuando el temporizador marca, la alarma activa el intent para actualizar la pantalla y, luego, establece el retraso de la próxima actualización.
En el siguiente ejemplo, se muestra cómo actualizar la información de la pantalla y cómo establecer la alarma para la siguiente actualización:
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 } }
Cómo programar la siguiente alarma
Programa la alarma para que actualice la pantalla cuando la actividad entre en modo ambiente o cuando la actividad ya esté en modo ambiente. Para ello, anula el método onEnterAmbient()
y el método 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(); }
Nota: En este ejemplo, se llama al método refreshDisplayAndSetNextUpdate()
cada vez que se necesita actualizar la pantalla. Para obtener más ejemplos sobre cuándo llamar a este método, consulta el ejemplo de AwaysOn.
Cómo cancelar la alarma
Cuando el dispositivo cambie al modo interactivo, cancela la alarma en el método onExitAmbient()
:
Kotlin
override fun onExitAmbient() { super.onExitAmbient() ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) }
Java
@Override public void onExitAmbient() { super.onExitAmbient(); ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); }
Cuando el usuario cierre o detenga tu actividad, cancela la alarma en el método onDestroy()
de tu actividad:
Kotlin
override fun onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent) super.onDestroy() }
Java
@Override public void onDestroy() { ambientUpdateAlarmManager.cancel(ambientUpdatePendingIntent); super.onDestroy(); }
Cómo mantener la compatibilidad con versiones anteriores
Las actividades que admiten el modo ambiente automáticamente recurren a las actividades normales en dispositivos Wear que ejecutan versiones de Android anteriores a 5.1 (nivel de API 22). No se requiere ningún código de app especial para admitir dispositivos en estas versiones de Android. Cuando el dispositivo cambia al modo ambiente, este vuelve a la pantalla principal y cierra tu actividad.
Si tu app no debe instalarse o actualizarse en dispositivos con versiones de Android anteriores a 5.1, actualiza tu manifiesto con lo siguiente:
<uses-library android:name="com.google.android.wearable" android:required="true" />