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
paramenuItem.action
. - Especifica un
menuItem.id
. Cuando los usuarios presionan el elemento de menú personalizado, tu Glassware recibe una notificación conmenuItem.id
propagado. Esto te permite determinar la fuente de la notificación. - Especifica
menuItem.values
para agregar uniconUrl
y undisplayName
que aparezcan en Glass. Señala una imagen PNG de 50 x 50 que sea de color blanco con un fondo transparente para eliconUrl
. Especifica un
displayTime
. Si no especificas undisplayTime
, 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 elID
del elemento de la línea de tiempo al que responde. - Atributo
text
establecido en la transcripción de texto. - Atributo
recipients
establecido en elcreator
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ó.