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 leer la tarjeta o realizar acciones en ella cuando lo deseen.

Cuando Glassware inserta tarjetas estáticas en el cronograma, 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 nuevas.

Cuándo usarlos

Las tarjetas estáticas son ideales para enviar notificaciones periódicas a los usuarios cuando suceden cosas importantes. Por ejemplo, un servicio de entrega de noticias que envía las noticias más importantes a medida que suceden. Las tarjetas estáticas de la API de Mirror también pueden iniciar tarjetas en vivo o inmersiones a través del OPEN_URI elemento de menú. Esto te permite crear interacciones híbridas que utilizan 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 del cronograma, consulta la documentación de referencia.

Cómo insertar tarjetas estáticas

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

La mayoría de los campos de un elemento del cronograma son opcionales. En su forma más sencilla, un elemento del cronograma solo contiene un mensaje de texto corto, 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 la operación 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 el cronograma del usuario se ve de la siguiente manera:

Cómo insertar un elemento del 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 del cronograma. Para ello, también puedes adjuntar imágenes y videos a un elemento del cronograma. Este es un ejemplo de cómo insertar un elemento del 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 del cronograma con una imagen adjunta se ve de la siguiente manera en Glass:

Cómo adjuntar video

Si adjuntas archivos de video a los elementos del cronograma, 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 HTTP Live Streaming, la 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 video, usa el PLAY_VIDEO elemento de menú integrado y especifica que la URL del video sea el payload. Consulta Cómo agregar elementos de menú integrados y formatos de contenido multimedia admitidos para obtener más información.

Paginación

Puedes paginar los elementos del cronograma que no caben en una sola tarjeta del cronograma, pero que, de lo contrario, deberían asociarse 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 pagine automáticamente html, usa la article etiqueta 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 subcronograma independiente. Por ejemplo, puedes crear un elemento del cronograma paginado con el siguiente 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 cover-only clase CSS para la primera <article> etiqueta:

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

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

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

Agrupación

La agrupación te permite agrupar elementos relacionados, pero distintos, como mensajes individuales en un hilo de correo electrónico. Los paquetes tienen una tarjeta de portada principal que un usuario presiona para mostrar un subcronograma que contiene las otras tarjetas del paquete. Los paquetes se distinguen de las tarjetas normales del cronograma por un pliegue de esquina en la esquina superior derecha de la tarjeta de portada del paquete.

Para agrupar 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 portada del paquete con el pliegue de esquina en la esquina superior derecha y dos tarjetas agrupadas debajo de ella.

Cómo leer elementos del cronograma

Tu servicio puede acceder a todos los elementos del cronograma que creó y a todos los elementos del cronograma que se compartieron con él. Sigue estos pasos para 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 del 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 contentUrl propiedad del archivo adjunto o con el endpoint 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 del cronograma y se presentan en dos tipos: elementos de menú integrados y elementos de menú personalizados.

Los elementos de menú integrados proporcionan acceso a funcionalidades especiales que proporciona Glass, como leer una tarjeta del cronograma 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, 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 los elementos del cronograma propagando el menuItems array cuando los insertas. 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 te funcionan, puedes crear elementos de menú personalizados con tus propias acciones haciendo lo siguiente cuando insertes o actualices un elemento del 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. Apunta a 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 del cronograma se mueve al frente del cronograma 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"
      }]
    }
  ]
}

Cómo permitir que los usuarios fijen tu tarjeta del 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 desafijar la tarjeta con el mismo elemento de 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 las notificaciones que se envían cuando el usuario realiza acciones específicas en un elemento del cronograma o cuando se actualiza la ubicación del usuario. Cuando te suscribes a una notificación, proporcionas una URL de devolución de llamada que procesa la notificación.

Recibir 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 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ó tu elemento del cronograma con 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 elemento que contiene lo siguiente:

  • Atributo inReplyTo establecido en el ID del elemento del cronograma al que responde
  • Atributo text establecido en la transcripción de texto
  • 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 isDeleted propiedad.

Elemento de menú personalizado seleccionado

El usuario seleccionó un elemento de menú personalizado establecido por 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 en consecuencia.

Ubicación actualizada

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 recibe una ubicación actualizada, envía una solicitud al glass.locations.get para recuperar la ubicación más reciente conocida. 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 una nota, Cat Stream, el cumpleaños de Chipotle es mañana". Se envía 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 notificaciones por el valor LAUNCH en la userActions propiedad.

Luego, puedes usar el valor en itemId para recuperar el elemento del 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 utilizado.