Cómo exponer datos a complicaciones

Las apps de proveedores de datos exponen información a complicaciones de caras de reloj proporcionando campos que contienen texto, cadenas, imágenes y números.

Un servicio de proveedor de datos extiende ComplicationProviderService para proporcionar información útil para los usuarios directamente a la cara de reloj.

Crea un proyecto de proveedor de datos

Para crear un proyecto en Android Studio para tu app de proveedor de datos, sigue estos pasos:

  1. Haz clic en File > New > New Project.
  2. En la ventana Project Template, haz clic en la pestaña Wear OS, selecciona No Activity y, luego, haz clic en Next.
  3. En la ventana Configure Your Project, asígnale un nombre al proyecto, completa la información básica y haz clic en Finish.
  4. Android Studio creará un proyecto con un módulo de app para el proveedor de datos. Si quieres obtener más información sobre los proyectos de Android Studio, consulta Cómo crear un proyecto.
  5. Para comenzar tu app de proveedor de datos, crea una clase nueva que extienda BroadcastReceiver. El propósito de esa clase es escuchar las solicitudes de actualización de complicaciones del sistema Wear OS. Además, crea una clase nueva que extienda ComplicationProviderService para proporcionar datos según lo soliciten las complicaciones apropiadas. Para obtener más información, consulta lo siguiente:

    Nota: Agregar una actividad para tu proveedor de datos es opcional. Por ejemplo, es posible que quieras una actividad que se inicie solo cuando el usuario presione una complicación.

Implementa un método para las solicitudes de actualización

Cuando se necesitan datos de complicaciones, el sistema Wear OS envía solicitudes de actualización al proveedor de datos, que recibe BroadcastReceiver. Para responder a las solicitudes de actualización, tu proveedor de datos debe implementar el método onComplicationUpdate() de la clase ComplicationProviderService.

El sistema Wear OS llama a onComplicationUpdate() cuando necesita datos del proveedor (por ejemplo, cuando se activa una complicación que usa tu proveedor o cuando transcurre un período de tiempo fijo). Pasa un objeto ComplicationManager como parámetro a onComplicationUpdate, que se usa para enviar datos al sistema.

Nota: Cuando la app del proveedor de datos proporciona información, la cara de reloj recibe los valores sin procesar que envías, de modo que pueda extraer la información.

En el siguiente fragmento de código, se muestra un ejemplo de implementación del método onComplicationUpdate:

Kotlin

override fun onComplicationUpdate(
    complicationId: Int, dataType: Int, complicationManager: ComplicationManager) {

    Log.d(TAG, "onComplicationUpdate() id: $complicationId")

    // Used to create a unique key to use with SharedPreferences for this complication.
    val thisProvider = ComponentName(this, javaClass)

    // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
    val preferences = getSharedPreferences(ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0)

    val number = preferences.getInt(
            ComplicationTapBroadcastReceiver.getPreferenceKey(
                    thisProvider, complicationId),
                    0)
    val numberText = String.format(Locale.getDefault(), "%d!", number)

    var complicationData: ComplicationData? = null

    when (dataType) {
        ComplicationData.TYPE_SHORT_TEXT -> complicationData = ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                .setShortText(ComplicationText.plainText(numberText))
                .build()
        else -> if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Unexpected complication type $dataType")
                }
    }

    if (complicationData != null) {
        complicationManager.updateComplicationData(complicationId, complicationData)
    } else {
        // If no data is sent, we still need to inform the ComplicationManager, so
        // the update job can finish and the wake lock isn't held any longer.
        complicationManager.noUpdateRequired(complicationId)
    }
}

Java

@Override
public void onComplicationUpdate(
       int complicationId, int dataType, ComplicationManager complicationManager) {

   Log.d(TAG, "onComplicationUpdate() id: " + complicationId);

   // Used to create a unique key to use with SharedPreferences for this complication.
   ComponentName thisProvider = new ComponentName(this, getClass());

   // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
   SharedPreferences preferences =
     getSharedPreferences( ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);

   int number =
           preferences.getInt(
                   ComplicationTapBroadcastReceiver.getPreferenceKey(
                           thisProvider, complicationId),
                   0);
   String numberText = String.format(Locale.getDefault(), "%d!", number);

   ComplicationData complicationData = null;

   switch (dataType) {
       case ComplicationData.TYPE_SHORT_TEXT:
           complicationData =
                   new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                           .setShortText(ComplicationText.plainText(numberText))
                           .build();
           break;
       default:
           if (Log.isLoggable(TAG, Log.WARN)) {
               Log.w(TAG, "Unexpected complication type " + dataType);
           }
   }

   if (complicationData != null) {
       complicationManager.updateComplicationData(complicationId, complicationData);

   } else {
       // If no data is sent, we still need to inform the ComplicationManager, so
       // the update job can finish and the wake lock isn't held any longer.
       complicationManager.noUpdateRequired(complicationId);
   }
}

Permisos y declaraciones de manifiesto

Las apps de proveedores de datos deben incluir declaraciones específicas en sus manifiestos para que el sistema Android las reconozca como proveedores de datos. En esta sección, se explican las configuraciones necesarias para las apps de ese tipo.

En el manifiesto de tu app, declara el servicio y agrega un filtro de intents para la acción de solicitud de actualización. El manifiesto también debe proteger el servicio. Para ello, debe agregar el permiso BIND_COMPLICATION_PROVIDER para garantizar que solo el sistema Wear OS pueda vincularse a servicios de proveedores.

Además, incluye un atributo android:icon en el elemento service que proporciona un ícono blanco de un solo color. Recomendamos el uso de elementos de diseño vectoriales para los íconos. El ícono representa al proveedor y se muestra en el selector de proveedores.

Por ejemplo:

<service
    android:name=".provider.IncrementingNumberComplicationProviderService"
    android:icon="@drawable/icn_complications"
    android:label="@string/complications_provider_incrementing_number"
    android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
    <intent-filter>
        <action
         android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
    </intent-filter>
</service>

Especifica los elementos de metadatos

En tu archivo de manifiesto, incluye metadatos para especificar los tipos admitidos, el período de actualización y la acción de configuración, como se muestra en el siguiente ejemplo:

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT" />

<meta-data
    android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
    android:value="300" />

Cuando está activo tu proveedor de datos de complicaciones, UPDATE_PERIOD_SECONDS especifica la frecuencia con la que quieres que el sistema compruebe la disponibilidad de actualizaciones de los datos. Si no es necesario que la información que se muestra en la complicación se actualice de forma regular, como cuando usas actualizaciones push, establece ese valor en 0.

Si no configuras UPDATE_PERIOD_SECONDS como 0, debes usar un valor de al menos 300 (5 minutos), que es el período mínimo de actualización que aplica el sistema, para preservar la duración de batería del dispositivo. Además, ten en cuenta que las solicitudes de actualización son menos frecuentes cuando no se lleva puesto el dispositivo o cuando se encuentra en el modo ambiente.

Para obtener más detalles sobre el envío de actualizaciones, consulta las claves indicadas para la clase ComplicationProviderService en la Referencia de la API de Wear OS.

Agrega una actividad de configuración

Si es necesario, un proveedor puede incluir una actividad de configuración que se muestra al usuario cuando este último selecciona un proveedor de datos. Para incluir la actividad de configuración, incluye un elemento de metadatos en la declaración de servicios del proveedor del manifiesto con la siguiente clave:

<meta-data
    android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
    android:value="PROVIDER_CONFIG_ACTION"/>

El valor puede ser cualquier acción.

Luego, crea la actividad de configuración con un filtro de intents para esa acción. La actividad de configuración debe encontrarse en el mismo paquete que el proveedor. Además, debe mostrar RESULT_OK o RESULT_CANCELED para indicar al sistema si se debe establecer el proveedor.

Caras de reloj seguras especificadas por el proveedor

Los proveedores pueden especificar ciertas caras de reloj como "seguras" para recibir sus datos. Solo se utiliza cuando una cara de reloj intenta usar el proveedor como predeterminado y este confía en la app.

Para declarar una cara de reloj como segura, el proveedor agrega metadatos con una clave android.support.wearable.complications.SAFE_WATCH_FACES. El valor de los metadatos es una lista separada por comas de nombres de componentes WatchFaceService, proporcionados como si se llamara a ComponentName.flattenToString(), o nombres de paquetes de apps, en cuyo caso cada cara de reloj dentro de una app especificada se considera segura. Se ignoran los espacios en blanco de la lista de valores. Por ejemplo:

<meta-data
       android:name="android.support.wearable.complications.SAFE_WATCH_FACES"
       android:value="
          com.app.watchface/com.app.watchface.MyWatchFaceService,
          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
          com.something.text"/>

Cómo proporcionar imágenes de protección de pantalla contra el efecto quemado

En las pantallas susceptibles al efecto quemado, se deben evitar los bloques sólidos de color en el modo ambiente. Si tus íconos o imágenes incluyen bloques sólidos de color, también debes proporcionar una versión con protección de pantalla.

Cuando proporciones un ícono con ComplicationData.Builder#setIcon, usa ComplicationData.Builder#setBurnInProtectionIcon para incluir una versión con protección de pantalla.

Cuando proporciones una imagen con ComplicationData.Builder#setSmallImage, usa ComplicationData.Builder#setBurnInProtectionSmallImage para incluir una versión con protección de pantalla.

Usa actualizaciones push

Como alternativa a especificar un intervalo de actualización constante que no sea cero para una complicación en el manifiesto de tu app, puedes usar una instancia de ComplicationDataSourceUpdateRequester para solicitar actualizaciones de manera dinámica. Para solicitar una actualización del contenido visible para el usuario de la complicación, llama a requestUpdate().

Precaución: Para preservar la duración de batería del dispositivo, no llames a requestUpdate() desde tu instancia de ComplicationDataSourceUpdateRequester con más frecuencia que un promedio de 5 minutos.

Proporciona valores dinámicos

A partir de Wear OS 4, algunas complicaciones pueden mostrar valores que se actualizan con más frecuencia de acuerdo con los valores que están disponibles directamente en la plataforma. Para brindar esta capacidad tus complicaciones, usa ComplicationData campos que aceptan valores dinámicos. La plataforma evalúa y estos valores se actualizan con frecuencia, sin necesidad de que se ejecute el proveedor de complicaciones.

Algunos campos de ejemplo incluyen campo de valor dinámico de GoalProgressComplicationData. DynamicComplicationText, que se puede usar en cualquier ComplicationText. Estos valores dinámicos se basan en el biblioteca androidx.wear.protolayout.expression.

En ciertas situaciones, la plataforma no puede evaluar valores dinámicos:

Proporciona valores dependientes del tiempo

Algunas complicaciones necesitan mostrar un valor que se relacione con la hora actual. Entre algunos ejemplos, se incluyen la fecha actual, el tiempo hasta la próxima reunión o la hora en otra zona horaria.

No actualices una complicación cada segundo o minuto para mantener esos valores actualizados. En cambio, especifica los valores como relativos a la fecha o la hora actual a través de texto dependiente del tiempo. Puedes usar compiladores en la clase ComplicationText para crear estos valores dependientes del tiempo.

Frecuencia de actualización de complicaciones

Es posible que quieras actualizar las complicaciones con gran frecuencia. Sin embargo, esto puede afectar la duración de batería del dispositivo. Puedes usar una API de Complication request con privilegios que permita actualizar complicaciones específicas con más frecuencia. Sin embargo, el uso de esta API debe estar permitido por el fabricante del reloj. Cada fabricante de relojes decide las complicaciones que se pueden actualizar a una frecuencia mayor que la permitida habitualmente.