Cards estáticos

É possível inserir, atualizar, ler e excluir cards estáticos usando APIs REST simples. Além disso, é possível anexar objetos a um card estático, como um local ou mídia.

Como funcionam

Por padrão, os cards estáticos ficam à direita do relógio do Glass e mostram informações relevantes para o usuário no momento da entrega. No entanto, eles não exigem atenção imediata, como os cards dinâmicos, e os usuários podem ler ou interagir com o card quando quiserem.

Quando o Glassware insere cards estáticos na linha do tempo, o Google Glass pode emitir um som de notificação para alertar os usuários. Todos os cards estáticos anteriores também mudam para a direita e desaparecem da linha do tempo após 7 dias ou quando 200 cards são mais recentes.

Quando usar as extensões

Os cards estáticos são ótimos para enviar notificações periódicas aos usuários quando algo importante acontece. Por exemplo, um serviço de entrega de notícias que envia as principais notícias assim que elas acontecem. Os cards estáticos da API Mirror também podem iniciar cards dinâmicos ou imersões pelo item de menu OPEN_URI. Isso permite criar interações híbridas que usam cards estáticos como notificações e um card dinâmico ou imersão para uma experiência mais interativa.

Para uma lista completa de operações possíveis para itens da linha do tempo, consulte a documentação de referência.

Inserir cards estáticos

Para inserir cards estáticos (itens da linha do tempo), faça POST de uma representação JSON de um item da linha do tempo para o endpoint REST.

A maioria dos campos em um item da linha do tempo é opcional. Na forma mais simples, um item da linha do tempo contém apenas uma mensagem de texto curta, como neste exemplo:

HTTP bruto

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

Se a solicitação for bem-sucedida, você vai receber um código de resposta 201 Created com uma cópia completa do item criado. No exemplo anterior, uma resposta bem-sucedida seria assim:

HTTP bruto

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"
}

O item inserido que apareceria na linha do tempo do usuário tem esta aparência:

Inserir um item da linha do tempo com um anexo

Uma imagem vale mais do que mil palavras, o que é muito mais do que você pode incluir em um item da linha do tempo. Para isso, você também pode anexar imagens e vídeos a um item da linha do tempo. Confira um exemplo de como inserir um item da linha do tempo com um anexo de foto:

HTTP bruto

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

Um item da linha do tempo com uma imagem anexada fica assim no Glass:

Anexando vídeo

Se você estiver anexando arquivos de vídeo aos itens da linha do tempo, recomendamos transmitir o vídeo em vez de fazer upload de toda a carga de uma vez. A API Google Mirror oferece suporte a streaming com HTTP live streaming, download progressivo e o protocolo de streaming em tempo real (RTSP). O RTSP é frequentemente bloqueado por firewalls. Por isso, use as outras opções quando possível.

Para transmitir vídeo, use o item de menu integrado PLAY_VIDEO e especifique o URL do vídeo como o payload do item de menu. Consulte Como adicionar itens de menu integrados e formatos de mídia compatíveis para mais informações.

Paginação

É possível paginar itens da linha do tempo que não cabem em um único card, mas que devem ser associados ao mesmo card. Os itens paginados compartilham o mesmo timeline.id e, portanto, têm o mesmo conjunto de itens de menu. Quando um usuário toca em um item da linha do tempo paginada, um item de menu Leia mais aparece.

O Glass pagina automaticamente os itens da linha do tempo que mostram text. Para que o Glass pagine automaticamente html, use a tag article com a propriedade de classe definida como auto-paginate, como no exemplo a seguir:

<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 fazer a paginação manual, use a tag article no conteúdo que você quer mostrar em cada card. O Glass mostra o conteúdo de cada tag article em um cartão de subtimeline separado. Por exemplo, é possível criar um item de linha do tempo paginado com o seguinte 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>

Por padrão, o primeiro card do item da linha do tempo paginada é mostrado como o card de capa e aparece novamente quando o usuário seleciona o item de menu Leia mais. Para evitar que o primeiro card apareça novamente depois de tocar em Leia mais, especifique a classe CSS cover-only para a primeira tag <article>:

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

A classe cover-only também é compatível com itens de linha do tempo com paginação automática:

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

Agrupamento

O agrupamento permite reunir itens relacionados, mas distintos, como mensagens individuais em uma conversa por e-mail. Os pacotes têm um card de capa principal que um usuário toca para mostrar uma subtimeline com os outros cards do pacote. Os pacotes são diferenciados dos cards normais da linha do tempo por uma dobra no canto superior direito do card de capa do pacote.

Para agrupar itens da linha do tempo, crie-os com o mesmo valor para bundleId. O item adicionado mais recentemente é o card da capa do pacote.

As imagens a seguir mostram um card de capa de pacote com a dobra no canto superior direito e dois cards agrupados abaixo dele.

Como ler itens da linha do tempo

Seu serviço pode acessar todos os itens da linha do tempo que criou e todos os itens compartilhados com ele. Veja como listar os itens da linha do tempo que estão visíveis para seu serviço.

HTTP bruto

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

Você pode usar outras operações REST para receber, atualizar e excluir itens da linha do tempo.

Como acessar anexos

É possível acessar os anexos de um item da linha do tempo usando uma propriedade de matriz chamada attachments. Em seguida, é possível extrair os dados binários de um anexo usando a propriedade contentUrl do anexo ou com o endpoint de anexos.

HTTP bruto

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

Criar itens de menu

Os itens de menu permitem que os usuários solicitem ações relacionadas ao card da linha do tempo e vêm em dois tipos: itens de menu integrados e personalizados.

Os itens de menu integrados oferecem acesso a funcionalidades especiais fornecidas pelo Glass, como ler um card da linha do tempo em voz alta, navegar até um local, compartilhar uma imagem ou responder a uma mensagem:

Os itens de menu personalizados permitem que seu aplicativo exponha um comportamento específico do Glassware. Você também pode fornecer um ícone de item de menu que corresponda à sua marca.

Como adicionar itens de menu integrados

É possível adicionar itens de menu integrados aos itens da linha do tempo preenchendo o menuItems array ao inseri-los. Para usar um item de menu integrado, basta preencher o action de cada menuItem.

HTTP bruto

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"
    }
  ]
}

Como definir itens de menu personalizados

Se os itens de menu integrados não funcionarem para você, crie itens de menu personalizados com suas próprias ações fazendo o seguinte ao inserir ou atualizar um item da linha do tempo:

  • Especifique CUSTOM para menuItem.action.
  • Especifique um menuItem.id. Quando os usuários tocam no item de menu personalizado, o Glassware recebe uma notificação com menuItem.id preenchido. Assim, é possível determinar a origem da notificação.
  • Especifique menuItem.values para adicionar um iconUrl e displayName que aparecem no Glass. Aponte para uma imagem PNG de 50 x 50 branca com um plano de fundo transparente para o iconUrl.
  • Especifique um displayTime. Se você não especificar um displayTime, o item da linha do tempo vai para a frente da linha do tempo sempre que os usuários tocarem no item do menu personalizado.

HTTP bruto

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 os usuários fixem o card da linha do tempo

Você pode criar um item de menu que permite aos usuários fixar o card da linha do tempo, que é exibido permanentemente à esquerda do card do relógio principal. Os usuários também podem desafixar o card usando o mesmo item de menu.

O item de menu de fixação é integrado. Portanto, basta fornecer o action do TOGGLE_PINNED para um menuItem.

HTTP bruto

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"
    }
  ...
 ]
}

Inscrições

Com a API Mirror, você pode inscrever-se em notificações enviadas quando o usuário realiza ações específicas em um item da linha do tempo ou quando a localização do usuário é atualizada. Ao se inscrever em uma notificação, você fornece um URL de retorno de chamada que processa a notificação.

Como receber notificações

Uma notificação da API Mirror é enviada como uma solicitação POST para o endpoint inscrito que contém um corpo de solicitação JSON.

HTTP bruto

{
  "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)

Seu serviço precisa responder à API com um código de status HTTP 200 OK se nenhum erro ocorrer. Se o serviço responder com um código de erro, a API Mirror poderá tentar reenviar a notificação para seu serviço.

Tipos de notificação

A API Mirror envia um payload de notificação diferente para cada evento.

Responder

O usuário respondeu ao item da linha do tempo usando o item de menu REPLY integrado:

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

O atributo itemId é definido como o ID do item que contém:

  • O atributo inReplyTo definido como o ID do item da linha do tempo a que ele é uma resposta.
  • Atributo text definido como a transcrição do texto.
  • O atributo recipients definido como o creator do item da linha do tempo a que ele responde, se existir.

Exemplo:

{
  "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"
      ]
    }
  ]
}

Excluir

O usuário excluiu um item da linha do tempo:

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

O atributo itemId é definido como o ID do item excluído. O item não contém mais metadados além do ID e da propriedade isDeleted.

Item de menu personalizado selecionado

O usuário selecionou um item de menu personalizado definido pelo seu serviço:

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

O atributo itemId é definido como o ID do item de menu que o usuário selecionou.

A matriz userActions contém a lista de ações personalizadas que o usuário realizou no item. Seu serviço precisa processar essas ações de acordo.

Atualização de local

Um novo local está disponível para o usuário atual:

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

Quando o Glassware receber uma atualização do local, envie uma solicitação ao endpoint glass.locations.get para recuperar o último local conhecido. Seu Glassware recebe atualizações de local a cada dez minutos.

Comando de voz

O usuário ativou um comando de voz, por exemplo: "Ok Glass, anote: Cat Stream, o aniversário do Chipotle é amanhã". A seguinte notificação é enviada para seu Glassware:

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

Essa notificação é diferenciada de outras pelo valor LAUNCH na propriedade userActions.

Em seguida, use o valor em itemId para buscar o item da linha do tempo:

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

A propriedade recipients contém o id do contato que representa o comando de voz usado.