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 Complications API, las caras de reloj pueden seleccionar los proveedores de datos que desean utilizar para obtener los 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 Complications API 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.

Complications

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

Configura 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. Este método se puede llamar en cualquier momento, pero no hará nada 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 transferir datos a esa cara de reloj. No obstante, algunos proveedores de sistemas se consideran 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 una cara de reloj se asocia con un proveedor específico y 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 valor 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() Proveedor de fecha del sistema estándar. Con un toque se abre la app Agenda estándar.
currentTimeProvider() Proveedor de “hora y fecha” del sistema estándar. No hay acción de toque.
batteryProvider() Proveedor de batería del sistema estándar. 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 “apps”, que se puede presionar para seleccionar una app.
nextEventProvider() No Sí (pero no es un proveedor seguro) El proveedor de “próximo evento” estándar del sistema. Con un toque se abre la app Agenda estándar.

Permite que los usuarios seleccionen proveedores de datos

Wear OS proporciona una interfaz de usuario (a través de una Activity) 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 de 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 tipos 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, la configuración se guarda automáticamente; no se requiere nada más de la cara de reloj.

Observa el ejemplo de app 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.

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

Una cara de reloj a la que no se le otorgue 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.

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.

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 para 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 del callback 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 una cara de reloj “segura”.
  • 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 (“--”) para permitir su representación como si fuera de tipo de texto corto o tipo de ícono, por cuestiones de conveniencia.

Cuando una cara de reloj recibe datos de TYPE_NO_PERMISSION, la cara de reloj debe representar esto correctamente, de modo que el usuario pueda ver que se debe hacer algo para que la complicación funcione. 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 solicitan actualizaciones para todas las complicaciones activas en la cara de reloj de forma automática, lo que permite que los datos de TYPE_NO_PERMISSION se reemplacen por datos reales.

Representar complicaciones

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

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

Diseñar complicaciones

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

La clase 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. sin límites.
  • Te permite configurar muchas opciones. Estas incluyen, entre otras, opciones para lo siguiente: 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 mediante programación. Debes usar el método draw() para diseñar una complicación y configurar las opciones de estilo para los modos ambiente e interactivo.

ComplicationDrawable usará íconos e imágenes 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 e 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.

Representar texto

La clase TextRenderer está pensada para usarse en complicaciones y facilita el diseño de texto en un lienzo. La clase 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 reduce el tamaño del texto hasta que entre.
  • El texto puede ocupar una cantidad de líneas especificada.
  • Si no entra, se puede acortar.
  • La representación se ajusta para una pantalla siempre visible (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.

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

Presionar las complicaciones

Usa el método ComplicationDrawable.onTap() para que tu cara de reloj para pase eventos de toque a las complicaciones. Este método se basa en la funcionalidad en la cual se activa el método WatchFaceService.Engine.onTapCommand() al presionar 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 inició la acción asociada, recibirás un valor de retorno de true.

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 Crear caras de reloj interactivas para aprender a crear caras de reloj 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 claves conforman una string corta. En el ejemplo del tipo 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 proveedores 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. Generalmente, 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 en la siguiente tabla). Por ejemplo, el campo Short title del tipo RANGED_VALUE no es obligatorio, de modo que, por ejemplo, los medidores se pueden mostrar 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 muestra un valor predeterminado para el campo. 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 (null).

Tipo Campos obligatorios Campos opcionales Notas
SHORT_TEXT Short text Icon
Burn-in protection icon
Short title
Se prevé que se muestre Icon o Short title 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 recibirlo de la cara de reloj.
RANGED_VALUE Value
Min value
Max value
Icon
Burn-in protection icon
Short text
Short title
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 Long text Long title
Icon
Burn-in protection icon
Small image
Se prevé que se muestre un título si se proporciona.
SMALL_IMAGE Small image Una imagen pequeña puede tener dos estilos: estilo de foto o estilo de ícono. El estilo de foto implica que debe llenar el espacio y se puede recortar; el estilo ícono, que no se debe recortar y 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 con modo ambiente con velocidad de bits baja. 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, la imagen no debería mostrarse.
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 con modo ambiente con velocidad de bits baja. 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 velocidad de bits baja.

Los tipos que se indican en la tabla siguiente son para datos vacíos y se pueden enviar para cualquier ranura de complicación. Estos tipos no tienen campos y no es necesario incluirlos en una lista de tipos compatibles. Estos tipos habilitan a las caras de reloj para que diferencien los siguientes tres casos:

  • No se seleccionó 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.

En la siguiente tabla, encontrarás información detallada sobre los tipos de complicaciones para datos “vacíos”:

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, bien o cuando la cara de reloj no selecciona un proveedor y 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.

Usar campos para los datos de complicación

Los campos de un objeto ComplicationData tienen diferentes características. Por ejemplo, un campo de texto contiene los datos principales mientras que un campo de título es descriptivo; una complicación de conteo de pasos podría tener un valor de campo de texto “2,543” con un valor de campo de título “steps”.

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

Campo Descripción
Short text Campo de texto principal para complicaciones pequeñas. La extensión máxima de este campo es de 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 string 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 Una imagen de un solo color que representa los datos o la fuente de los datos. Debe poder colorearse. Se recomienda usar diseños vectoriales para este campo.
Burn-in protection icon Campo que permite que un ícono se muestre 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 represente 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.
Burn-in protection small image Campo que permite que una imagen se muestre 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 represente 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.
Short title Campo descriptivo para complicaciones pequeñas. Solo tiene relevancia si se combina con el campo Short text. La extensión máxima de este campo es de 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 string 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 Campo de datos principal para complicaciones amplias basadas en texto.
Long title Campo descriptivo para complicaciones amplias basadas en texto. Solo tiene relevancia si se combina con Long text.
Value Representación numérica (float) 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 dichos límites).
Min value Límite inferior para el rango dentro del que se debe representar Value. Solo tiene relevancia si se combina con Value y Max value.
Max value Límite superior para el rango dentro del que se debe representar Value. Solo tiene relevancia si se combina con Value y Min value.
Small image Imagen pequeña para representar los datos o la fuente de estos. Puede ir en colores. No se prevé que ocupe toda la cara de reloj.
Large image Imagen con suficiente resolución para ocupar la cara de reloj. Puede ir en colores.

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 probar la representación de los tipos de complicaciones. Por lo tanto, no es necesario que escribas código para 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:

  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 seleccionar 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 para verificar que todas las combinaciones de campos pertinentes se muestren de forma correcta.

Por ejemplo, si una complicación admite texto corto, presiona la complicación para ver todas las combinaciones de campos principales para texto corto.