Cómo agregar complicaciones a una cara de reloj

Una complicación de una cara de reloj muestra información de un proveedor de datos. Con la API de Complications, las caras de reloj pueden seleccionar los proveedores de datos que desean utilizar para obtener datos subyacentes. Esto permite que las caras de reloj muestren información independientemente de la hora del día, sin necesidad de utilizar código para obtener los datos.

La API de complicaciones también permite a los usuarios seleccionar los proveedores de datos que prefieran. Además, Wear OS by Google proporciona una interfaz de usuario para la selección de fuentes de datos.

Complicaciones

Para agregar complicaciones a una cara de reloj, haz lo siguiente:

Cómo configurar proveedores predeterminados para caras de reloj

Las caras de reloj pueden especificar proveedores predeterminados que se usan hasta que un usuario selecciona un proveedor. Establece los proveedores predeterminados usando el método setDefaultComplicationProvider() en WatchFaceService.Engine. Se puede llamar a este método en cualquier momento, pero no realizará ninguna acción si el usuario ya seleccionó un proveedor para la complicación en cuestión.

Para la mayoría de los proveedores, se debe otorgar el permiso RECEIVE_COMPLICATION_DATA a una cara de reloj antes de que se puedan transferir datos. No obstante, se considera que algunos proveedores de sistemas son seguros, ya que solo proporcionan información que la cara de reloj pudo obtener por sí misma. Los proveedores seguros no requieren que la cara de reloj tenga el permiso para datos que se enviarán (consulta Proveedores de sistemas). Es preferible usar estos proveedores como valores predeterminados, ya que pueden proporcionar datos de inmediato.

Como alternativa, si se asocia una cara de reloj con un proveedor específico y esta desea usarlo como predeterminado, puede solicitar que el proveedor la indique como una cara de reloj segura.

Proveedores de sistemas

El sistema incluye proveedores que se pueden usar como predeterminados. El método setDefaultSystemComplicationProvider(), en la clase WatchFaceService.Engine, establece un proveedor de sistemas predeterminado para una complicación. Este método toma un ID (como un número entero) que representa a un proveedor de sistemas. Los ID disponibles se indican en la clase SystemProviders.

La siguiente tabla contiene información detallada sobre algunos de los proveedores de sistemas admitidos:

Nombre del método en la clase SystemProviders Seguridad Puede ser el predeterminado Notas
dateProvider() Es el proveedor de fecha del sistema estándar. Al presionar, se abre la app estándar de Agenda.
currentTimeProvider() Es el proveedor estándar de "hora y fecha" del sistema. No hay acción de toque.
batteryProvider() Es el proveedor de batería estándar del sistema. No hay acción de toque.
stepCountProvider() Muestra el total diario de pasos, tal como lo informa readDailyTotal.
unreadCountProvider() Muestra la cantidad de notificaciones no leídas en el flujo.
worldClockProvider() La selección predeterminada será Londres o Nueva York. Se puede presionar para cambiar la zona horaria.
appsProvider() Primero mostrará un ícono de "apps", que se puede presionar para seleccionar una app.
nextEventProvider() No Sí (pero no es un proveedor seguro) Es el proveedor de "próximo evento" estándar del sistema. Al presionar, se abre la app estándar de Agenda.

Cómo permitir que los usuarios seleccionen proveedores de datos

Wear OS proporciona una interfaz de usuario (a través de una Actividad) que permite que los usuarios seleccionen proveedores para una complicación específica. Las caras de reloj pueden llamar al método createProviderChooserHelperIntent a fin de obtener un intent que se puede usar para mostrar la interfaz del selector.

Cuando una cara de reloj llama a createProviderChooserHelperIntent, la cara de reloj proporciona un ID de complicación de cara de reloj y una lista de tipos compatibles. Los tipos se deben indicar por orden de preferencia, generalmente con los que ofrezcan más información (como el valor de intervalos) en una posición de mayor preferencia.

Cuando el usuario selecciona un proveedor de datos, se guarda automáticamente la configuración; no se requiere nada más de la cara de reloj.

Observa el ejemplo de la app de Watch Face y accede al código completo recomendado para la interfaz de usuario de configuración.

Ese código incluye lo siguiente:

  • Una interfaz estándar para la configuración de complicaciones
  • Acceso sencillo a otras configuraciones

Un punto de partida para revisar el código es la clase AnalogComplicationConfigActivity; esta tiene un método getDataToPopulateAdapter() que muestra una lista de las entradas de configuración disponibles en la IU.

Cómo abrir el selector de proveedores

Una cara de reloj debe tener el siguiente permiso para recibir datos de complicación y abrir el selector de proveedores:

    com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA
    

Si a una cara de reloj no se le otorga el permiso anterior, no podrá iniciar el selector de proveedores.

Para facilitar la solicitud del permiso y el inicio del selector, se encuentra disponible la clase ComplicationHelperActivity en la biblioteca de compatibilidad de wearables. En casi todos los casos, para iniciar el selector se debe usar esta clase en lugar de ProviderChooserIntent.

Cómo solicitar el permiso necesario

Para usar ComplicationHelperActivity, agrégala a la cara de reloj en el archivo de manifiesto:

    <activity android:name="android.support.wearable.complications.ComplicationHelperActivity"/>
    

Para iniciar el selector de proveedores, llama al método ComplicationHelperActivity.createProviderChooserHelperIntent a fin de obtener un intent.

El nuevo intent se puede usar con startActivity o startActivityForResult para iniciar el selector.

A continuación, te mostramos un ejemplo de uso del nuevo intent con startActivityForResult:

Kotlin

    startActivityForResult(
            ComplicationHelperActivity.createProviderChooserHelperIntent(
                    activity,
                    watchFace,
                    complicationId,
                    ComplicationData.TYPE_LARGE_IMAGE
            ),
            PROVIDER_CHOOSER_REQUEST_CODE
    )
    

Java

    startActivityForResult(
      ComplicationHelperActivity.createProviderChooserHelperIntent(
         getActivity(),
         watchFace,
         complicationId,
         ComplicationData.TYPE_LARGE_IMAGE),
      PROVIDER_CHOOSER_REQUEST_CODE);
    

Cuando se inicia la actividad auxiliar, esta comprueba si se otorgó el permiso. Si no se otorgó el permiso, la actividad auxiliar realiza una solicitud de permiso en tiempo de ejecución. Si se acepta la solicitud de permiso (o no se necesita), se muestra el selector de proveedores.

Si se usó startActivityForResult con el intent, el resultado transmitido a la actividad de llamada tendrá un código de resultado RESULT_OK, si el proveedor se estableció correctamente, o un código de resultado RESULT_CANCELLED, si no se estableció ningún proveedor.

Cuando se establezca un proveedor, la clase ComplicationProviderInfo para el proveedor seleccionado se incluirá en el intent de datos del resultado como elemento adicional con la clave ProviderChooserIntent#EXTRA_PROVIDER_INFO.

Cómo recibir datos de complicación

Para comenzar a recibir datos de complicación, una cara de reloj llama a setActiveComplications(), en la clase WatchFaceService.Engine, con una lista de ID de complicaciones de cara de reloj. Una cara de reloj crea estos ID a fin de identificar de forma exclusiva las ranuras de la cara de reloj en las que pueden aparecer complicaciones y los pasa al método createProviderChooserIntent(), para permitir que el usuario decida qué complicación debe ir en cada ranura. Los datos de complicación se envían a través de la devolución de llamada onComplicationDataUpdate().

En general, las caras de reloj necesitan el permiso anterior para poder recibir datos de complicación, pero hay algunas excepciones. Específicamente, una cara de reloj solo puede recibir datos de un proveedor si se da una de las siguientes condiciones:

  • El proveedor es un proveedor de sistemas "seguro".
  • El proveedor y la cara de reloj pertenecen a la misma app.
  • El proveedor incluye en la lista blanca la cara de reloj como un elemento "seguro".
  • La cara de reloj tiene el permiso.

Si no se cumple ninguna de las condiciones anteriores, si un proveedor normalmente envía ComplicationData a una cara de reloj, el sistema envía como alternativa datos de tipo TYPE_NO_PERMISSION. Este tipo incluye un ícono (un signo de exclamación) y texto corto ("--") a fin de permitir que se procese como si fuera del tipo de texto corto o el tipo de icono, para mayor comodidad.

Cuando una cara de reloj recibe datos de TYPE_NO_PERMISSION, debe procesar esto correctamente, de modo que el usuario pueda ver que se debe hacer algo para que funcione la complicación. Si fuera posible, con solo presionar una complicación en este estado debería iniciarse una solicitud de permiso. Esto se puede hacer usando ComplicationHelperActivity.createPermissionRequestHelperIntent(), si la actividad auxiliar se agregó a la app de cara de reloj.

Si un usuario acepta la solicitud de permiso creada por la actividad auxiliar, se solicitarán actualizaciones para todas las complicaciones activas en la cara de reloj de forma automática, lo que permitirá que se reemplacen los datos de TYPE_NO_PERMISSION por información real.

Cómo procesar complicaciones

La cara de reloj puede procesar los datos de la forma deseada, siempre que se representen los campos previstos (se deben incluir los campos obligatorios en todo momento). Según el tipo, también se pueden incluir algunos campos opcionales (consulta la columna "Notas" de la que tabla que aparece a continuación).

Proporcionamos pautas de diseño para nuestro estilo, como sugerencias para complicaciones estándares, pero los desarrolladores pueden usar sus propios estilos o incorporar los datos a la cara de reloj de diferentes maneras.

Cómo diseñar complicaciones

La clase ComplicationDrawable te permite procesar una complicación completa en un lienzo.

Admite los seis tipos de complicación principales y hace lo siguiente:

  • Controla todos los aspectos de diseño y estilo para las complicaciones.
  • Diseña fondos, íconos, texto, etc. dentro de los límites establecidos.
  • Te permite configurar muchas opciones, entre las que se incluyen: color de fondo, forma y radio de las esquinas, borde (o ausencia de este), color de texto y tipo de letra.
  • Decodifica y guarda imágenes en caché.

Si el nivel de API de destino es el 24, se puede definir un objeto ComplicationDrawable en XML como recurso. También puedes crear un objeto ComplicationDrawable de manera programática. Debes usar el método draw() con el objetivo de diseñar una complicación y configurar las opciones de estilo para los modos interactivo y ambiente.

ComplicationDrawable usará íconos e imágenes seguras de protección de pantalla si se proporcionaron y el dispositivo los requiere. Para habilitar esto, llama al método ComplicationDrawable.setBurnInProtection() cuando recibas las propiedades del dispositivo.

Si deseas instrucciones detalladas y ejemplos para diseñar complicaciones, consulta ComplicationDrawable, que incluye XML de ejemplo. Para acceder a un ejemplo de cara de reloj que utilice esta clase y que incluya XML de ejemplo, consulta el ejemplo AnalogComplicationWatchFaceService en el ejemplo de app Watch Face.

Si no usas un objeto ComplicationDrawable, usa TextRenderer para el texto de una complicación.

Cómo procesar texto

La clase TextRenderer está pensada para usarse en complicaciones y facilita el diseño de texto en un lienzo. La misma incluye estas características:

  • Si no entran siete caracteres en los límites del tamaño de texto solicitado (la cantidad máxima en el campo de texto corto), la clase reducirá el tamaño del texto hasta que entre.
  • El texto puede ocupar una cantidad de líneas especificada.
  • Si no entra, se puede acortar.
  • El procesamiento se ajusta para una pantalla siempre encendida (modo ambiente).

Cuando inicializas el motor de tu cara de reloj, puedes crear un objeto TextRenderer y pasar el objeto TextPaint que desees que el objeto TextRenderer use. El objeto TextPaint define, entre otras opciones, la fuente, el tamaño del texto y el color. Debes crear un objeto TextRenderer para cada campo; p. ej., uno para un campo de texto y uno para un campo de título.

A fin de acceder a código de ejemplo, incluido el código para especificar límites en el texto que desees procesar, consulta TextRenderer.

Cómo presionar complicaciones

Usa el método ComplicationDrawable.onTap() para habilitar el pase eventos de toque a las complicaciones en tu cara de reloj. Este método se basa en la funcionalidad en la cual se activa el método WatchFaceService.Engine.onTapCommand() cuando se presiona la cara de reloj.

Puedes pasar coordenadas a un ComplicationDrawable con una llamada onTap. Esto iniciará la acción asociada con el ComplicationDrawable que contiene las coordenadas de toque. Cuando se llama al método, si un ComplicationDrawable lanzó la acción asociada, recibirás un valor de retorno verdadero.

Usa el método setHighlightDuration() para establecer el tiempo que una complicación permanecerá destacada luego de que se llame al método onTap.

Si no usas ComplicationDrawable para una complicación, deberás detectar toques y activar la acción de toque PendingIntent tú mismo. Consulta Cómo crear caras de reloj interactivas para aprender a crear elementos que respondan a los toques de los usuarios.

Tipos de complicaciones

Los tipos de complicaciones determinan la clase de datos que se muestran en una complicación. Por ejemplo, el tipo SHORT_TEXT está disponible cuando los datos clave conforman una string corta. En el ejemplo de SHORT_TEXT, los datos opcionales son un ícono y un título corto.

Los proveedores de datos usan estos tipos de complicaciones de forma diferente en comparación con los de caras de reloj:

  • Un proveedor de datos selecciona los tipos de datos de complicaciones que proporcionará. Por ejemplo, un proveedor de conteo de pasos podría admitir los tipos RANGED_VALUE y SHORT_TEXT, mientras que un proveedor de "próxima reunión" podría admitir los tipos SHORT_TEXT y LONG_TEXT. El proveedor de datos también selecciona los campos opcionales de esos tipos que incluirá.
  • Un proveedor de caras de reloj selecciona la cantidad de tipos de complicaciones que admitirá. Por ejemplo, una complicación redonda en una cara de reloj podría admitir los tipos SHORT_TEXT, ICON y RANGED_VALUE, mientras que un medidor podría admitir solo el tipo RANGED_VALUE.

Un objeto ComplicationData siempre tendrá un solo tipo de complicación. Cada tipo de complicación tiene campos obligatorios y opcionales. Por lo general, un campo obligatorio representa los datos más importantes; la mayoría de los tipos toman su nombre del campo obligatorio.

Un tipo determinado puede incluir diferentes conjuntos de campos. Por ejemplo, SHORT_TEXT puede ser solo texto, un título y texto, o un ícono y texto. Una complicación compatible con un tipo determinado debe poder mostrar todas las variantes previstas. No obstante, no es necesario mostrar algunos campos opcionales (consulta la columna Notas de la siguiente tabla). Por ejemplo, el campo "Título corto" del tipo RANGED_VALUE no es obligatorio, de modo que, por ejemplo, es posible mostrar medidores sin texto.

Ejemplos de tipos de complicaciones

A continuación, se muestran ejemplos de tipos de complicaciones:

Tipos de complicaciones

Tipos y campos

En la tabla siguiente se describen los tipos y campos del objeto ComplicationData. Si una cara de reloj solicita un campo que no es válido para un tipo de complicación, se mostrará un valor predeterminado. Por ejemplo, si una cara de reloj intenta acceder a un campo Long text en un tipo SHORT_TEXT, se muestra el valor predeterminado para el campo Long text (nulo).

Tipo Campos obligatorios Campos opcionales Notas
SHORT_TEXT Texto corto Ícono
Ícono de protección de pantalla
Título corto
Se prevé que se muestre "Ícono" o "Título corto" si se proporciona uno de ellos o ambos.
ICON Icon Burn-in protection icon Se usa cuando no se necesita texto. Se prevé que el ícono sea de un solo color y que lo ajuste la cara de reloj.
RANGED_VALUE Valor
Valor mínimo
Valor máximo
Ícono
Ícono de protección de pantalla
Texto corto
Título corto
No se garantiza que se muestren los campos opcionales. Si quieres diseñar tu propia barra de progreso, puedes usar el método setRangedValueProgressHidden() para ocultar la barra de progreso proporcionada por la clase ComplicationDrawable.
LONG_TEXT Texto largo Ícono de título largo
Ícono
Ícono de protección de pantalla
Imagen pequeña
Se prevé que se muestre un título si se proporciona.
SMALL_IMAGE Small image Una imagen pequeña puede tener dos estilos: de foto o de ícono. El estilo de foto implica que debe llenar el espacio y se puede recortar; el de ícono, que no se debe recortar y que se puede rellenar. La variabilidad de la imagen puede producir una imagen no apta para exhibición en el modo ambiente en dispositivos con protección de pantalla o en modo ambiente con baja velocidad de bits. Cuando la protección de pantalla o el modo ambiente con velocidad de bits baja están habilitados, la cara de reloj puede usar Burn-in protection small image ya que es seguro. De lo contrario, debido a que para una cara de reloj es difícil determinar la aptitud, no debería mostrarse la imagen.
LARGE_IMAGE Large image Se prevé que esta imagen sea suficientemente grande como para llenar la cara de reloj. La variabilidad de la imagen puede producir una imagen no apta para exhibición en el modo ambiente en dispositivos con protección de pantalla o en modo ambiente con baja velocidad de bits. Debido a que es difícil para una cara de reloj determinar si una imagen es apta para mostrar, no debe mostrar una imagen en modo ambiente si se habilita la protección de pantalla o el modo ambiente con baja velocidad de bits.

Los tipos que se indican en la siguiente tabla corresponden a datos vacíos y se pueden enviar para cualquier ranura de complicación. No tienen campos y no es necesario incluirlos en una lista de tipos compatibles. Permiten a las caras de reloj diferenciar entre estos tres casos:

  • No se seleccionó ningún proveedor.
  • El usuario seleccionó "empty" para una ranura.
  • Un proveedor no tiene datos para enviar.

Los proveedores no deben enviar TYPE_EMPTY en respuesta a solicitudes de actualización. En su lugar, deben enviar TYPE_NO_DATA.

Los detalles correspondientes a los tipos de complicaciones para datos "vacíos" se encuentran en la siguiente tabla:

Tipo de complicación Descripción
TYPE_NOT_CONFIGURED Lo envía el sistema cuando se activa una complicación y el usuario no selecciona un proveedor o no se establece un valor predeterminado.

No lo pueden enviar los proveedores.

TYPE_EMPTY Lo envía el sistema cuando se activa una complicación y el usuario selecciona "empty" en lugar de un proveedor, o bien cuando la cara de reloj no selecciona un proveedor ni este tipo como valor predeterminado.

No lo pueden enviar los proveedores.

TYPE_NO_DATA Lo envía el sistema cuando se activa una complicación (que tiene un proveedor) para borrarla antes de que el proveedor envíe datos reales.

Lo deben enviar los proveedores si no tienen datos reales para enviar.

Cómo usar campos para los datos de una complicación

Los campos de un objeto ComplicationData tienen diferentes características. Por ejemplo, un campo de texto contiene los datos primarios mientras que uno de título es descriptivo; una complicación de conteo de pasos puede tener un valor de campo de texto de "2,543" con un valor de campo de título de "pasos".

La siguiente tabla contiene descripciones de los campos de un objeto ComplicationData. Pueden propagarse o no, según el tipo de complicación.

Campo Descripción
Short text Es el campo de texto principal para complicaciones pequeñas. La longitud máxima de este campo no debe superar los siete caracteres (incluido el texto temporal). Se prevé que las caras de reloj tengan la capacidad de representar cualquier string de siete caracteres. Las strings varían respecto del ancho, según los caracteres que se utilicen. Una cara de reloj debe ajustar el tamaño del texto para permitir que quepa en la complicación. Si el texto supera los siete caracteres, podría truncarse.
Icon Es una imagen de un solo color que representa los datos o su fuente. Debe poder ajustarse el tono de su color. Se recomienda usar diseños vectoriales para este campo.
Ícono de protección de pantalla Es un campo que permite que se muestre un ícono en el modo ambiente en dispositivos que usan protección de pantalla. En el modo ambiente, las caras de reloj en dispositivos que usan protección de pantalla no deben mostrar bloques sólidos de píxeles. El campo Burn-in protection icon es opcional para cualquier tipo de complicación que incluya el campo icon. El campo Burn-in protection icon no debe contener bloques sólidos de píxeles. Los proveedores deben proporcionar el campo Burn-in protection icon si su ícono estándar no es apto para la protección de pantalla. Una cara de reloj que se procese en el modo ambiente en un dispositivo con protección de pantalla debe usar el campo Burn-in protection icon, si está disponible, en lugar de icon.
Imagen pequeña de protección de pantalla Es el campo que permite que se muestre una imagen en el modo ambiente en dispositivos que usan protección de pantalla. En el modo ambiente, las caras de reloj en dispositivos que usan protección de pantalla no deben mostrar bloques sólidos de píxeles. El campo Burn-in protection small image es opcional para cualquier tipo de complicación que incluya un campo small image. El campo Burn-in protection small image no debe contener bloques sólidos de píxeles. Los proveedores deben proporcionar el campo Burn-in protection small image si su imagen pequeña estándar no es apta para protección de pantalla. Una cara de reloj que se procese en el modo ambiente en un dispositivo con protección de pantalla debe usar el campo Burn-in protection small image, si está disponible, en lugar de small image.
Título corto Campo descriptivo para complicaciones pequeñas. Solo tiene relevancia si se combina con el campo Short text. La longitud máxima de este campo no debe superar los siete caracteres (incluido el texto dependiente del tiempo). Se prevé que las caras de reloj tengan la capacidad de representar cualquier string de siete caracteres. Las strings varían respecto del ancho, según los caracteres que se utilicen. Una cara de reloj debe ajustar el tamaño del texto para permitir que quepa en la complicación. Si el texto supera los siete caracteres, podría truncarse.
Long text Es el campo de datos principal para complicaciones amplias basadas en texto.
Long title Es el campo descriptivo para complicaciones amplias basadas en texto. Solo tiene relevancia si se combina con Long text.
Value Es la representación numérica (decimal) de los datos. Se prevé que se represente de acuerdo con los límites de los campos Min value y Max value (aunque no es obligatorio que se encuentre dentro de esos límites).
Min value Es el límite inferior correspondiente al rango dentro del que se debe representar Value. Solo tiene relevancia si se combina con Value y Max value.
Max value Es el límite superior correspondiente al rango dentro del que se debe representar Value. Solo tiene relevancia si se combina con Value y Min value.
Small image Es una imagen pequeña para representar los datos o su fuente. Puede estar en color. No se prevé que ocupe toda la cara de reloj.
Large image Imagen con suficiente resolución para ocupar la cara de reloj. Puede estar en color.

Cómo probar tipos de complicación

Cada tipo de complicación tiene campos, como los de texto e íconos. Si tu cara de reloj admite un tipo de complicación, debes admitir todas las combinaciones de campos válidas.

Puedes probar la manera en la que se muestran los datos de complicación en una cara de reloj. Específicamente, un conjunto de pruebas te permite evaluar la representación de los tipos de complicaciones. Por lo tanto, no es necesario que escribas código a fin de probar las combinaciones de campos válidas para un objeto ComplicationData.

El conjunto de pruebas es un proveedor de datos, disponible como ejemplo, que alterna las combinaciones de campos válidas para un tipo de complicación determinado.

Para usar este conjunto de pruebas, haz lo siguiente:

  1. Instala el APK del conjunto de pruebas en un dispositivo o emulador.
  2. Accede a tu cara de reloj y presiona su ícono de configuración principal.
  3. Usa la IU de configuración para elegir el conjunto de pruebas WearComplication-ProviderTestSuite.
  4. Selecciona un tipo de datos de complicación para probarlo.
  5. Presiona tu complicación para ver las variaciones del tipo de datos.
  6. Presiónala repetidamente a fin de verificar que se muestren de forma correcta todas las combinaciones de campos pertinentes.

Por ejemplo, si una complicación admite texto corto, presiónala a fin de ver todas las combinaciones de campos principales para texto corto.