Tarjetas estáticas

Puedes insertar, actualizar, leer y borrar tarjetas estáticas con APIs 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 encuentran 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 elegir leerlas o actuar en función de ellas cuando quieran.

Cuando Glassware inserta tarjetas estáticas en la línea de tiempo, Glass puede reproducir 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 del cronograma después de 7 días o cuando hay 200 tarjetas más recientes.

Cuándo usarlos

Las tarjetas estáticas son ideales para enviar notificaciones periódicas a los usuarios a medida que ocurren eventos importantes. Por ejemplo, un servicio de entrega 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 imágenes inmersivas a través del 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 una experiencia más interactiva.

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

Cómo insertar tarjetas estáticas

Para insertar tarjetas estáticas (elementos de cronograma), envía una representación JSON de un elemento de cronograma al extremo REST.

La mayoría de los campos de un elemento de cronograma son opcionales. En su forma más simple, un elemento de cronograma solo contiene 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 se realiza 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 de la siguiente manera:

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ía en la línea de tiempo del usuario se ve de la siguiente manera:

Cómo insertar un elemento de cronograma con un archivo adjunto

Una imagen vale más que mil palabras, que es mucho más de lo que puedes incluir en un elemento de cronograma. Para ello, también puedes adjuntar imágenes y videos a un elemento de la línea de tiempo. Este es un ejemplo de cómo insertar un elemento de cronograma con una foto adjunta:

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 la línea de tiempo con una imagen adjunta se ve de la siguiente manera en Glass:

Cómo adjuntar un video

Si adjuntas archivos de video a tus elementos de línea de tiempo, te recomendamos que transmitas el video en lugar de subir toda la carga útil a la vez. La API de Google Mirror admite la transmisión con transmisión en vivo HTTP, descarga progresiva y el protocolo de transmisión en tiempo real (RTSP). Los firewalls suelen bloquear RTSP, por lo que debes usar las otras opciones cuando sea posible.

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

Paginación

Puedes paginar los elementos de la línea de tiempo que no se ajustan a una sola tarjeta de línea de tiempo, pero que, de otro modo, deberían estar asociados con la misma tarjeta. 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 de línea de tiempo paginada, aparece el elemento de menú Más información.

Glass pagina automáticamente los elementos de la línea de tiempo 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 manualmente, usa la etiqueta article para el 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 cronograma paginado 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 de línea de tiempo paginada se muestra como la tarjeta de portada y se vuelve a mostrar cuando el usuario selecciona el elemento de menú Más información. Para evitar que la primera tarjeta vuelva a aparecer después de presionar Más información, puedes especificar la clase CSS cover-only para la primera etiqueta <article>:

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

La clase cover-only también admite elementos de cronograma paginados automáticamente:

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

Agrupación

El agrupamiento te permite agrupar elementos relacionados, pero distintos, como en el caso de los mensajes individuales de una conversación por correo electrónico. Los paquetes tienen una tarjeta de portada principal en la que el usuario presiona para mostrar un subrecorrido que contiene las otras tarjetas del paquete. Los paquetes se distinguen de las tarjetas de cronograma normales por una esquina doblada en la esquina superior derecha de la tarjeta de portada del paquete.

Para agrupar elementos de la línea de tiempo, 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 portada del paquete con el pliegue de esquina en la esquina superior derecha y dos tarjetas del paquete debajo.

Cómo leer elementos de la línea de tiempo

Tu servicio puede acceder a todos los elementos de Rutas que creó y a todos los elementos de Rutas que se compartieron con él. A continuación, se muestra cómo enumerar los elementos de la ruta de acceso 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 de la línea de tiempo.

Cómo acceder a los archivos adjuntos

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

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();

Cómo crear elementos de menú

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

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

Los elementos de menú personalizados permiten que tu aplicación exponga un comportamiento específico de tu Glassware. También puedes proporcionar un ícono de elemento de menú que coincida con tu desarrollo de la marca.

Cómo agregar elementos de menú integrados

Para agregar elementos de menú integrados a tus elementos de línea de tiempo, propaga el elemento menuItems array cuando los insertes. Para usar un elemento de menú integrado, solo debes propagar el 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. Para ello, sigue estos pasos 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 aparezcan en Glass. Señala una imagen PNG de 50 x 50 que sea de color blanco con un fondo transparente para el iconUrl.
  • Especifica un displayTime. Si no especificas un displayTime, el elemento de la línea de tiempo se moverá al principio cada vez que los usuarios presionen 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"
      }]
    }
  ]
}

Permite que los usuarios fijen tu tarjeta de cronograma

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

El elemento de menú de fijación es un elemento de menú integrado, por lo que solo debes 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 notificaciones que se envían cuando el usuario realiza acciones específicas en un elemento de Ruta o cuando se actualiza su ubicación. Cuando te suscribes a una notificación, proporcionas una URL de devolución de llamada que la procesa.

Recibe notificaciones

Una notificación de la API de Mirror se envía 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, es posible que la API de Mirror intente volver a enviar la notificación a tu 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 Ruta con el elemento de menú REPLY integrado:

{
  "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 elemento que contiene lo siguiente:

  • Atributo inReplyTo configurado en el ID del elemento de la línea de tiempo al que responde.
  • Atributo text establecido en la transcripción de texto.
  • Atributo recipients establecido en el creator del elemento de la línea de tiempo 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 de la línea de tiempo:

{
  "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, excepto su ID y la propiedad isDeleted.

Se seleccionó el elemento de menú personalizado

El usuario seleccionó un elemento de menú personalizado que configuró tu 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 array 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 conocida más reciente. Tu Glassware recibe actualizaciones de ubicación cada diez minutos.

Comando por voz

El usuario activó un comando por voz, por ejemplo: "Ok Glass, toma nota, Cat Stream, el cumpleaños de Chipotle es mañana". Se enviará la siguiente notificación a tu Glassware:

{
  "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 la línea de tiempo:

{
  "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 que se usó.