Tarjetas estáticas

Puedes insertar, actualizar, leer y borrar tarjetas estáticas con las API de REST simples. Además, puedes adjuntar objetos a una tarjeta estática, como una ubicación o contenido multimedia.

Cómo funcionan

De forma predeterminada, las tarjetas estáticas se ubican a la derecha del reloj de Glass y muestran información relevante para el usuario en el momento de la entrega. Sin embargo, no requieren atención inmediata, como las tarjetas en vivo, y los usuarios pueden optar por leer o realizar acciones en la tarjeta a su propio ritmo.

Cuando Glassware inserta tarjetas estáticas en el cronograma, es posible que Glass reproduzca un sonido de notificación para alertar a los usuarios. Todas las tarjetas estáticas anteriores también se desplazan hacia la derecha y desaparecen de la línea de tiempo después de 7 días o cuando 200 tarjetas son más nuevas.

Cuándo usarlos

Las tarjetas estáticas son ideales para entregar notificaciones periódicas a los usuarios a medida que suceden los eventos importantes. Por ejemplo, un servicio de publicación de noticias que envía las noticias principales a medida que ocurren. Las tarjetas estáticas de la API de Mirror también pueden iniciar tarjetas en vivo o inmersiones mediante el elemento de menú OPEN_URI. Esto te permite crear interacciones híbridas que usan tarjetas estáticas como notificaciones y una tarjeta en vivo o inmersión para brindar una experiencia más interactiva.

Si deseas obtener una lista completa de las operaciones posibles para los elementos del cronograma, consulta la documentación de referencia.

Insertar tarjetas estáticas

Para insertar tarjetas estáticas (elementos de cronograma), PUBLICA una representación JSON de un elemento de cronograma en el extremo de REST.

La mayoría de los campos de un elemento del cronograma son opcionales. En su forma más simple, un elemento de cronograma contiene solo un mensaje de texto breve, como en este ejemplo:

HTTP sin procesar

POST /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 26

{ "text": "Hello world" }

Java

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
service.timeline().insert(timelineItem).execute();

Python

timeline_item = {'text': 'Hello world'}
service.timeline().insert(body=timeline_item).execute()

Si lo haces correctamente, recibirás un código de respuesta 201 Created con una copia completa del elemento creado. En el ejemplo anterior, una respuesta correcta podría verse así:

HTTP sin procesar

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
 "kind": "glass#timelineItem",
 "id": "1234567890",
 "selfLink": "https://www.googleapis.com/mirror/v1/timeline/1234567890",
 "created": "2012-09-25T23:28:43.192Z",
 "updated": "2012-09-25T23:28:43.192Z",
 "etag": "\"G5BI0RWvj-0jWdBrdWrPZV7xPKw/t25selcGS3uDEVT6FB09hAG-QQ\"",
 "text": "Hello world"
}

El elemento insertado que aparecerá en la línea de tiempo del usuario tendrá el siguiente aspecto:

Insertar un elemento de cronograma con un archivo adjunto

Una imagen vale más que mil palabras, lo que es mucho más de lo que cabe en un elemento del cronograma. Para ello, también puedes adjuntar imágenes y videos a un elemento de cronograma. A continuación, se muestra un ejemplo de cómo insertar un elemento de cronograma con un archivo adjunto de foto:

HTTP sin procesar

POST /upload/mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: multipart/related; boundary="mymultipartboundary"
Content-Length: {length}

--mymultipartboundary
Content-Type: application/json; charset=UTF-8

{ "text": "A solar eclipse of Saturn. Earth is also in this photo. Can you find it?" }
--mymultipartboundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary

[binary image data]
--mymultipartboundary--

Java

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
InputStreamContent mediaContent = new InputStreamContent(contentType, attachment);
service.timeline().insert(timelineItem, mediaContent).execute();

Python

timeline_item = {'text': 'Hello world'}
media_body = MediaIoBaseUpload(
    io.BytesIO(attachment), mimetype=content_type, resumable=True)
service.timeline().insert(body=timeline_item, media_body=media_body).execute()

Un elemento de cronograma con una imagen adjunta tiene el siguiente aspecto en Glass:

Adjuntando el video

Si adjuntas archivos de video a los elementos del cronograma, te recomendamos transmitir el video en lugar de subir la carga útil completa de una sola vez. La API de duplicación de Google admite transmisiones con transmisión en vivo HTTP, descarga progresiva y el protocolo de transmisión en tiempo real (RTSP). Con frecuencia, los firewalls bloquean el RTSP, por lo que debes usar las otras opciones siempre que sea posible.

Para transmitir video, usa el elemento de menú integrado PLAY_VIDEO y especifica que la URL del video sea la payload del elemento de menú. Consulta Cómo agregar elementos de menú integrados y Formatos de medios compatibles para obtener más información.

Paginación

Puedes paginar elementos de cronograma que no entran en una sola tarjeta de cronograma, pero que de otra manera deberían estar asociados con la misma tarjeta. Todos los elementos paginados comparten el mismo timeline.id y, por lo tanto, tienen el mismo conjunto de elementos de menú. Cuando un usuario presiona un elemento del cronograma paginado, aparece un elemento de menú Leer más.

Glass pagina automáticamente los elementos del cronograma que muestran text. Para que Glass pagina automáticamente html, usa la etiqueta article con su propiedad de clase establecida en auto-paginate, como en el siguiente ejemplo:

<article class="auto-paginate">
 <h3>Very long list</h3>
 <ul>
   <li>First item</li>
   <li>Second item</li>
   <li>Third item</li>
   <li>Fourth item</li>
   <li>Fifth item</li>
   <li>Sixth item</li>
   <li>...</li>
 </ul>
<article>

Para paginar de forma manual, usa la etiqueta article del contenido que deseas mostrar en cada tarjeta. Glass muestra el contenido de cada etiqueta article en una tarjeta de sublínea de tiempo independiente. Por ejemplo, puedes crear un elemento de línea de tiempo paginada con el siguiente código HTML:

<article>
 <section>
   <p>First page</p>
 </section>
</article>

<article>
 <section>
   <p>Second page</p>
 </section>
</article>

<article>
 <section>
   <p>Third page</p>
 </section>
</article>

De forma predeterminada, la primera tarjeta del elemento del cronograma paginado se muestra como la tarjeta de portada y se vuelve a mostrar cuando el usuario selecciona el elemento de menú Leer más. Para evitar que la primera tarjeta vuelva a aparecer después de presionar Leer más, puedes especificar la clase cover-only de CSS para la primera etiqueta <article>:

<article class="cover-only">
...

La clase cover-only también admite elementos de línea de tiempo de paginación automática:

<article class="auto-paginate cover-only">
...

Empaquetado

La agrupación te permite agrupar elementos relacionados, pero distintos, para mensajes individuales en una conversación de correo electrónico. Los paquetes tienen una tarjeta de portada principal que el usuario presiona para mostrar un cronograma que contiene las demás tarjetas del paquete. Los paquetes se distinguen de las tarjetas normales de la línea de tiempo por un pliegue de esquina en la esquina superior derecha de la tarjeta de portada del paquete.

A fin de agrupar los elementos del cronograma, créalos con el mismo valor para bundleId. El elemento agregado más recientemente es la tarjeta de portada del paquete.

En las siguientes imágenes, se muestra una tarjeta de cobertura de paquete con el pliegue de esquinas en la esquina superior derecha y dos tarjetas agrupadas debajo.

Leer elementos del cronograma

El servicio puede acceder a todos los elementos del cronograma que creó y a todos los elementos del cronograma que se compartieron con él. Aquí se muestra cómo enumerar los elementos del cronograma que son visibles para tu servicio.

HTTP sin procesar

GET /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

Java

TimelineItem timelineItem = new TimelineItem();
service.timeline().list().execute();

Python

service.timeline().list().execute()

Puedes usar otras operaciones de REST para obtener, actualizar y borrar elementos del cronograma.

Cómo acceder a los archivos adjuntos

Puedes acceder a los archivos adjuntos de un elemento de cronograma mediante una propiedad de arreglo llamada attachments. Luego, puedes obtener los datos binarios de un adjunto mediante la propiedad contentUrl del adjunto o con el extremo adjunto.

HTTP sin procesar

GET /mirror/v1/timeline/{itemId}/attachments/{attachmentId} HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

Java

TimelineItem item = service.timeline().get(itemId).execute();
String attachmentId = item.getAttachments().get(0).getId();
service.attachments().get(itemId, attachmentId).executeAsInputStream();

Crea elementos de menú

Los elementos de menú permiten a los usuarios solicitar acciones relacionadas con la tarjeta del cronograma y se dividen en dos tipos: integrados y personalizados.

Los elementos de menú integrados proporcionan acceso a las funciones especiales que proporciona Glass, como leer una tarjeta de cronograma en voz alta, navegar a una ubicación, compartir una imagen o responder un mensaje:

Los elementos de menú personalizados permiten a tu aplicación exponer un comportamiento específico de tu Glassware y también puedes proporcionar un ícono de elemento de menú que coincida con tu marca.

Cómo agregar elementos de menú integrados

Puedes agregar elementos de menú integrados a tus elementos de línea de tiempo. Para ello, propaga menuItems array cuando los insertes. Para usar un elemento de menú integrado, solo tienes que propagar action de cada menuItem.

HTTP sin procesar

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "Hello world",
  "menuItems": [
    {
      "action": "REPLY"
    }
  ]
}

Cómo definir elementos de menú personalizados

Si los elementos de menú integrados no funcionan, puedes crear elementos de menú personalizados con tus propias acciones de la siguiente manera cuando insertes o actualices un elemento de cronograma:

  • Especifica CUSTOM para menuItem.action.
  • Especifica un menuItem.id. Cuando los usuarios presionan el elemento de menú personalizado, tu Glassware recibe una notificación con menuItem.id propagado. Esto te permite determinar la fuente de la notificación.
  • Especifica menuItem.values para agregar un iconUrl y un displayName que aparece en Glass. Señala una imagen PNG de 50 x 50 que es de color blanco con un fondo transparente para el iconUrl.
  • Especifica un displayTime. Si no especificas un displayTime, el elemento del cronograma se mueve al principio de este cada vez que los usuarios presionan el elemento de menú personalizado.

HTTP sin procesar

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "Hello world",
  "displayTime": "2013-08-08T22:47:31-07:00",
  "menuItems": [
    {
      "action": "CUSTOM",
      "id": "complete"
      "values": [{
        "displayName": "Complete",
        "iconUrl": "http://example.com/icons/complete.png"
      }]
    }
  ]
}

Permitir que los usuarios fijen tu tarjeta de cronograma

Puedes crear un elemento de menú que permita a los usuarios fijar la tarjeta del cronograma, que muestra de forma permanente la tarjeta del cronograma a la izquierda de la tarjeta del reloj principal. Los usuarios también pueden dejar de fijar la tarjeta si usan el mismo elemento de menú.

El elemento de menú fijo es un elemento de menú integrado, por lo que lo único que debes hacer es proporcionar el TOGGLE_PINNED action para un menuItem.

HTTP sin procesar

HTTP/1.1 201 Created
Date: Tue, 25 Sep 2012 23:30:11 GMT
Content-Type: application/json
Content-Length: 303

{
  "text": "You can pin or unpin this card.",
 "menuItems": [
    {
      "action": "TOGGLE_PINNED"
    }
  ...
 ]
}

Suscripciones

La API de Mirror te permite suscribirte a las notificaciones que se envían cuando el usuario realiza acciones específicas en un elemento de cronograma o cuando se actualiza su ubicación. Cuando te suscribes a una notificación, proporcionas una URL de devolución de llamada que procesa la notificación.

Recibe notificaciones

Se envía una notificación de la API de Mirror como una solicitud POST al extremo suscrito que contiene un cuerpo de solicitud JSON.

HTTP sin procesar

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "<TYPE>",
      "payload": "<PAYLOAD>"
    }
  ]
}

Java

import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.mirror.model.Notification;

import java.io.IOException;
import java.io.InputStream;
// ...

public class MyClass {
  // ...

  /**
    * Parse a request body into a Notification object.
    *
    * @param requestBody The notification payload sent by the Mirror API.
    * @return Parsed notification payload if successful, {@code null} otherwise.
    */
  static Notification parseNotification(InputStream requestBody) {
    try {
      JsonFactory jsonFactory = new JacksonFactory();

      return jsonFactory.fromInputStream(requetBody, Notification.class);
    } catch (IOException e) {
      System.out.println("An error occurred: " + e);
      return null;
    }
  }

  // ...
}

Python

import json

def parse_notification(request_body):
  """Parse a request body into a notification dict.

  Params:
    request_body: The notification payload sent by the Mirror API as a string.
  Returns:
    Dict representing the notification payload.
  """
  return json.load(request_body)

Tu servicio debe responder a la API con un código de estado HTTP 200 OK si no se produjo ningún error. Si tu servicio responde con un código de error, la API de Mirror podría intentar reenviar la notificación al servicio.

Tipos de notificación

La API de Mirror envía una carga útil de notificación diferente para diferentes eventos.

Responder

El usuario respondió a tu elemento de cronograma mediante el elemento de menú integrado REPLY:

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "INSERT",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "REPLY"
    }
  ]
}

El atributo itemId se establece en el ID del artículo que contiene:

  • inReplyTo configurado como el ID del elemento del cronograma al que responde
  • text. Se establece en la transcripción de texto.
  • El atributo recipients establecido en el creator del elemento del cronograma al que responde, si existe.

Ejemplo:

{
  "kind": "glass#timelineItem",
  "id": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "inReplyTo": "3236e5b0-b282-4e00-9d7b-6b80e2f47f3d",
  "text": "This is a text reply",
  "recipients": [
    {
      "id": "CREATOR_ID",
      "displayName": "CREATOR_DISPLAY_NAME",
      "imageUrls": [
        "CREATOR_IMAGE_URL"
      ]
    }
  ]
}

Borrar

El usuario borró un elemento del cronograma:

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "DELETE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "DELETE"
    }
  ]
}

El atributo itemId se establece en el ID del elemento borrado. El elemento ya no contiene metadatos que no sean su ID y la propiedad isDeleted.

Se seleccionó el elemento de menú personalizado

El usuario seleccionó un elemento de menú personalizado que establece el servicio:

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "userActions": [
    {
      "type": "CUSTOM",
      "payload": "PING"
    }
  ]
}

El atributo itemId se establece en el ID del elemento de menú que seleccionó el usuario.

El arreglo userActions contiene la lista de acciones personalizadas que el usuario realizó en este elemento. Tu servicio debe controlar esas acciones según corresponda.

Actualización de ubicación

Hay una nueva ubicación disponible para el usuario actual:

{
  "collection": "locations",
  "itemId": "latest",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer"
}

Cuando tu Glassware reciba una actualización de ubicación, envía una solicitud al extremo glass.locations.get para recuperar la ubicación más reciente. Tu Glassware recibe actualizaciones de ubicación cada diez minutos.

Comando por voz

Tu usuario activó un comando por voz, por ejemplo: "Ok Glass, toma nota, Cat Stream, el cumpleaños de Chipotle es mañana". La siguiente notificación se envía a tu Glass:

{
  "collection": "timeline",
  "operation": "INSERT",
  "userToken": "chipotle's_owner",
  "verifyToken": "mew mew mew",
  "itemId": "<ITEM_ID>",
  "userActions": [
    {“type”: "LAUNCH"}
  ]
}

Esta notificación se distingue de otras por el valor LAUNCH en la propiedad userActions.

Luego, puedes usar el valor en itemId para recuperar el elemento de cronograma:

{
  "id": "<ITEM_ID>",
  "text": "Chipotle's birthday is tomorrow",
  "recipients": [
    {"id": "CAT_STREAM"}
  ]
}

La propiedad recipients contiene el id del contacto que representa el comando por voz usado.