Cómo exponer datos en complicaciones

Las apps de proveedores de datos exponen información a complicaciones de caras de reloj proporcionando campos 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.

Crea un proyecto de proveedor de datos

Si quieres crear un proyecto en Android Studio para tu app de proveedor de datos, haz lo siguiente:

  1. Haz clic en File > New > New Project.
  2. En la ventana Create Android Project, acepta los valores predeterminados y haz clic en Next.
  3. En la ventana Target Android Devices, selecciona solo la opción Wear y, en la lista de versiones de SDK, selecciona la versión más reciente disponible. Haz clic en Next.
  4. En la ventana Add an Activity to Wear, elige Add No Activity y haz clic en Finish.

    Android Studio creará un proyecto con un módulo de app para tu 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 a diseñar tu app de proveedor de datos, crea una nueva clase 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 nueva clase que extienda ComplicationProviderService para proporcionar datos según lo soliciten las complicaciones apropiadas. Para obtener más información, consulta lo siguiente:

    Nota: Es opcional agregar una actividad para tu proveedor de datos. Te recomendamos que agregues una que se inicie solamente cuando un usuario presiona una complicación, por ejemplo.

Cómo implementar un método para solicitudes de actualización

Cuando se necesitan datos de complicaciones, el sistema Wear OS envía solicitudes de actualización a tu proveedor de datos, que recibe BroadcastReceiver. Para responder a las solicitudes de actualización, el proveedor debe implementar el método onComplicationUpdate() de la clase ComplicationProviderService. El sistema Wear OS llama a este método cuando se necesitan datos de tu proveedor (p. ej., cuando se activa una complicación que usa o cuando transcurre un período de tiempo fijo). 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 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, we grab 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, 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, 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 con qué frecuencia quieres que el sistema compruebe las actualizaciones de los datos. Si la información que se muestra en la complicación no necesita actualizarse de forma regular, como cuando usas actualizaciones push, establece ese valor como 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 vida útil de la batería del dispositivo. Además, ten en cuenta que las solicitudes de actualización pueden ser menos frecuentes cuando no se usa 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.

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, 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. 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. 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.

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 ProviderUpdateRequester a fin de solicitar actualizaciones de manera dinámica. Para solicitar una actualización del contenido de la complicación que ve el usuario, llama a onComplicationUpdate().

Precaución: Para preservar la vida útil de la batería del dispositivo, la instancia de ProviderUpdateRequester no debería llamar a onComplicationUpdate() con una frecuencia superior a 5 minutos, en promedio.

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; 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.