Cómo exponer datos a complicaciones

Una complicación de cara de reloj muestra datos proporcionados por un proveedor de datos. Los proveedores de datos proporcionan a las caras de reloj campos sin formato que contienen texto, strings, imágenes y números.

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

Crear apps de proveedores de datos

Wear OS by Google envía solicitudes de actualización a las apps de proveedores de datos cuando necesita actualizar los datos de complicaciones.

Para responder a las solicitudes de actualización del sistema, tu app proveedora de datos debe implementar el método onComplicationUpdate() de la clase ComplicationProviderService. Este método se llamará cuando el sistema necesite datos de tu proveedor; esto podría ocurrir cuando se active una complicación que use tu proveedor, o cuando haya transcurrido un tiempo determinado. Un objeto ComplicationManager se pasa como parámetro al método onComplicationUpdate y se puede usar para volver a enviar datos al sistema.

Nota: Cuando proporcionas datos como un proveedor de datos de complicaciones, la cara de reloj recibe los valores sin formato que envías para poder representarlos en la cara de reloj.

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, we grab an incrementing number from SharedPrefs.
    val preferences = getSharedPreferences(
            ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY,
            0
    )

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

    when (dataType) {
        ComplicationData.TYPE_SHORT_TEXT ->
            ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                    .setShortText(ComplicationText.plainText(numberText))
                    .build().also { complicationData ->
                        complicationManager.updateComplicationData(complicationId, complicationData)
                    }
        else -> {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Unexpected complication type $dataType")
            }
            // 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, we grab 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 proveedores de datos. 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 agregando el permiso BIND_COMPLICATION_PROVIDER para garantizar que solo el sistema Wear OS pueda vincularse a servicios de proveedores.

Además, dentro del elemento de servicio debes incluir un atributo android:icon. El ícono de proveedor debe ser un ícono de color blanco únicamente. Se recomienda el uso de elementos de diseño vectoriales para los íconos. Un ícono debe representar al proveedor y se mostrará en el selector de proveedores.

A continuación, te mostramos un 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>

Especificar 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, si es necesario. Si deseas información detallada, consulta los temas indicados para la clase ComplicationProviderService en la Referencia de la Wear API.

Cuando tu proveedor de datos de complicación está activo, UPDATE_PERIOD_SECONDS especifica la frecuencia con la que quieres que el sistema compruebe la disponibilidad de actualizaciones de los datos. Esa frecuencia debe representar un tiempo lo más prolongado posible, o tener el valor 0 cuando no se requieran actualizaciones programadas, ya que un exceso en la frecuencia de actualización puede afectar la duración de batería. Ten en cuenta que no se garantiza que las solicitudes de actualización se envíen con esta frecuencia. El sistema aplica un período de actualización mínimo de 300 segundos y, en particular, las solicitudes de actualización pueden ser menos frecuentes cuando el dispositivo se encuentra en el modo ambiente o no se usa.

Como opción, puedes usar un “estilo push” para enviar actualizaciones, en lugar de solicitar actualizaciones según un cronograma fijo. Usa ProviderUpdateRequester para activar llamadas a onComplicationUpdate según sea necesario. Por 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="0"/>

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 una acción que tú elijas.

Luego crea la actividad de configuración con un filtro de intents para esa acción. La actividad de configuración debe residir en el mismo paquete que el proveedor. La actividad de configuración 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. Esto está pensado para usarse únicamente cuando una cara de reloj intenta usar el proveedor como predeterminado (ver a continuación) y este confía en la app de cara de reloj.

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 debe ser una lista separada por comas (los espacios en blanco se ignoran). Las entradas de la lista pueden ser nombres de componentes (de WatchFaceServices, proporcionado como si se hubiera llamado a ComponentName.flattenToString()), o nombres de paquetes (de apps, en cuyo caso cada cara de reloj en una app específica se considera segura). 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"/>

Proporcionar imágenes de protección de pantalla

En las pantallas que admiten protección, 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 usando ComplicationData.Builder#setIcon, incluye una versión de protección de pantalla con ComplicationData.Builder#setBurnInProtectionIcon.

Cuando proporcionas una imagen usando ComplicationData.Builder#setSmallImage, incluye una versión de protección de pantalla con ComplicationData.Builder#setBurnInProtectionSmallImage.

Proporcionar valores dependientes del tiempo

Algunas complicaciones necesitan mostrar un valor que se relacione con la hora y el día actuales. 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 a cada segundo o minuto para mantener esos valores actualizados; las complicaciones nunca deberían requerir actualizaciones tan frecuentes. En su lugar, especifica los valores relacionados con la fecha o la hora actual usando texto dependiente del tiempo. Puedes usar generadores en la clase ComplicationText para crear estos valores dependientes del tiempo.