Cómo exponer datos en complicaciones

Una complicación de cara de reloj muestra datos proporcionados por un proveedor de datos. Estos proveedores 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.

Cómo 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. Se llamará a este método cuando el sistema necesite datos de tu proveedor (por ejemplo, cuando se active una complicación que use tu proveedor o cuando haya transcurrido un tiempo determinado). Se pasa un objeto ComplicationManager 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 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 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.

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

Cuando está activo tu proveedor de datos de complicación, 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 se envíen las solicitudes de actualización 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 no se usa el dispositivo o cuando se encuentra en el modo ambiente.

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 muestre al usuario cuando este último seleccione un proveedor de datos. Para incluir la actividad de configuración, agrega 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 encontrarse 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 (se ignoran los espacios en blanco). 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"/>
    

Proporciona 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 con ComplicationData.Builder#setIcon, incluye una versión de protección de pantalla con ComplicationData.Builder#setBurnInProtectionIcon.

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

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 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 esos valores.