Karty statyczne

Za pomocą prostych interfejsów REST API możesz wstawiać, aktualizować, czytać i usuwać karty statyczne. Możesz też dołączyć do karty statycznej obiekty, takie jak lokalizacja lub materiały multimedialne.

Jak działają

Karty statyczne znajdują się domyślnie po prawej stronie zegara w Glass i wyświetlają informacje istotne dla użytkownika w momencie dostawy. Nie wymagają jednak natychmiastowej uwagi, jak karty na żywo, a użytkownicy mogą czytać je lub podejmować działania na ich podstawie we własnym tempie.

Gdy Glassware wstawia statyczne karty na osi czasu, Glass może odtworzyć dźwięk powiadomienia, aby ostrzec użytkowników. Wszystkie wcześniejsze karty statyczne przesuwają się też w prawo i znikają z osi czasu po 7 dniach lub gdy pojawi się 200 nowszych kart.

Kiedy ich używać

Karty statyczne są świetnym sposobem na wysyłanie okresowych powiadomień do użytkowników, gdy dzieją się ważne rzeczy. Przykładem może być usługa dostarczania wiadomości, która wysyła najważniejsze wiadomości w miarę ich pojawiania się. Statyczne karty interfejsu Mirror API mogą też uruchamiać karty na żywo lub immersję za pomocą pozycji menu OPEN_URI. Dzięki temu możesz tworzyć interakcje hybrydowe, które wykorzystują karty statyczne jako powiadomienia i karty na żywo lub immersyjne, aby zapewnić bardziej interaktywne wrażenia.

Pełną listę możliwych operacji dotyczących elementów osi czasu znajdziesz w dokumentacji.

Wstawianie kart statycznych

Aby wstawić karty statyczne (elementy osi czasu), prześlij reprezentację elementu osi czasu w formacie JSON do punktu końcowego REST.

Większość pól w elemencie osi czasu jest opcjonalna. W najprostszej formie element osi czasu zawiera tylko krótką wiadomość tekstową, jak w tym przykładzie:

Nieprzetworzony HTTP

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

W przypadku powodzenia otrzymasz kod odpowiedzi 201 Created z pełną kopią utworzonego elementu. W przypadku poprzedniego przykładu odpowiedź informująca o pomyślnym zakończeniu może wyglądać tak:

Nieprzetworzony HTTP

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

Wstawioną pozycję, która pojawi się na osi czasu użytkownika, będzie można zobaczyć w takiej postaci:

Wstawianie elementu osi czasu z załącznikiem

Jedno zdjęcie wyraża więcej niż tysiąc słów, czyli dużo więcej niż możesz zmieścić w elemencie osi czasu. W tym celu możesz też dołączyć obrazy i filmy do elementu osi czasu. Oto przykład wstawiania elementu osi czasu z załączonym zdjęciem:

Nieprzetworzony HTTP

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

Element osi czasu z załączonym obrazem wygląda w Google Glass tak:

Dołączanie filmu

Jeśli załączasz pliki wideo do elementów osi czasu, zalecamy przesyłanie ich strumieniowo zamiast przesyłać cały ładunek naraz. Interfejs Google Mirror API obsługuje strumieniowanie z wykorzystaniem transmisji na żywo przez HTTP, pobierania progresywnego i protokołu strumieniowego przesyłania w czasie rzeczywistym (RTSP). Protokół RTSP jest często blokowany przez zapory sieciowe, dlatego w miarę możliwości używaj innych opcji.

Aby przesyłać strumieniowo filmy, użyj wbudowanego elementu menu PLAY_VIDEO i podaj adres URL filmu jako payload elementu menu. Więcej informacji znajdziesz w artykule Dodawanie wbudowanych elementów menu oraz Obsługiwane formaty multimediów.

Podział na strony

Możesz podzielić na strony elementy osi czasu, które nie mieszczą się na jednej karcie osi czasu, ale powinny być powiązane z tą samą kartą. Wszystkie elementy pogrupowane w sekcji mają ten sam timeline.id, a co za tym idzie, ten sam zestaw elementów menu. Gdy użytkownik kliknie element strony przewijanej, pojawi się menu z opcją Więcej informacji.

Glass automatycznie dzieli na strony elementy osi czasu, które wyświetlają się na text. Aby Glass automatycznie dzielił stronę html, użyj tagu article z właściwością class ustawioną na auto-paginate, jak w tym przykładzie:

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

Aby ręcznie utworzyć strony, użyj tagu article w przypadku treści, które mają być wyświetlane na każdej karcie. Glass wyświetla zawartość każdego tagu article na osobnej karcie podrzędnej. Możesz na przykład utworzyć podzielony na strony element osi czasu za pomocą tego kodu 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>

Domyślnie pierwsza karta elementu na stronicowanej osi czasu jest wyświetlana jako karta tytułowa i ponownie, gdy użytkownik kliknie pozycję menu Więcej informacji. Aby pierwsza karta nie pojawiała się ponownie po kliknięciu Więcej informacji, możesz określić klasę CSS cover-only dla pierwszego tagu <article>:

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

Klasa cover-only obsługuje też automatyczne paginację elementów osi czasu:

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

Pakiety

Dzięki grupowaniu możesz łączyć powiązane, ale odrębne elementy, np. poszczególne wiadomości w wątku e-mail. Pakiety mają główną kartę okładki, którą użytkownik może kliknąć, aby wyświetlić podczas trwania podczas, zawierający inne karty w pakiecie. Pakiety różnią się od zwykłych kart osi czasu zagięciem w prawym górnym rogu karty z okładką.

Aby połączyć elementy osi czasu, utwórz je z tą samą wartością atrybutu bundleId. Ostatnio dodany element to karta okładki pakietu.

Na poniższych obrazach widać kartę z pakietem z zawiniętym rogiem w prawym górnym rogu oraz 2 karty z pakietu poniżej.

Czytanie elementów osi czasu

Usługa ma dostęp do wszystkich elementów osi czasu, które utworzyła, oraz wszystkich elementów osi czasu, które zostały jej udostępnione. Oto jak wyświetlić elementy osi czasu, które są widoczne dla Twojej usługi.

Nieprzetworzony HTTP

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

Możesz używać innych operacji REST, aby pobierać, aktualizować i usuwać elementy osi czasu.

Dostęp do załączników

Do załączników dołączonych do elementu osi czasu możesz uzyskać dostęp za pomocą właściwości tablicy o nazwie attachments. Następnie możesz uzyskać dane binarne załącznika za pomocą właściwości contentUrl załącznika lub za pomocą punktu końcowego attachments.

Nieprzetworzony HTTP

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

Tworzenie pozycji menu

Pozycje menu umożliwiają użytkownikom wykonywanie działań związanych z kartą osi czasu. Występują one w 2 typach: wbudowane pozycje menu i niestandardowe pozycje menu.

Wbudowane pozycje menu zapewniają dostęp do specjalnych funkcji Google Glass, takich jak odczytywanie na głos karty osi czasu, nawigowanie do lokalizacji, udostępnianie zdjęcia czy odpowiadanie na wiadomość:

Niestandardowe elementy menu umożliwiają aplikacji wyświetlanie zachowań związanych z Twoim Glassware. Możesz też podać ikonę elementu menu pasującą do Twojej marki.

Dodawanie wbudowanych elementów menu

Możesz dodawać do elementów osi czasu wbudowane elementy menu, wypełniając podczas wstawiania te pola: menuItems array. Aby użyć wbudowanego elementu menu, musisz wypełnić tylko pole action w każdym menuItem.

Nieprzetworzony HTTP

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

Definiowanie niestandardowych pozycji menu

Jeśli wbudowane elementy menu Ci nie odpowiadają, możesz utworzyć własne elementy menu, wykonując te czynności podczas wstawiania lub aktualizowania elementu na osi czasu:

  • W polu menuItem.action wpisz CUSTOM.
  • Podaj wartość w polu menuItem.id. Gdy użytkownicy klikną niestandardowy element menu, Twoja aplikacja Glassware otrzyma powiadomienie z wypełnionym parametrem menuItem.id. Dzięki temu możesz określić źródło powiadomienia.
  • Określ menuItem.values, aby dodać iconUrldisplayName, które będą widoczne na Glass. Wskaż obraz PNG o wymiarach 50 x 50, który jest biały i ma przezroczyste tło. Taki obraz będzie miał wartość iconUrl.
  • Podaj wartość w polu displayTime. Jeśli nie określisz wartości displayTime, element osi czasu przesunie się na początek osi, gdy użytkownicy klikną niestandardowy element menu.

Nieprzetworzony HTTP

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

Zezwalanie użytkownikom na przypinanie karty osi czasu

Możesz utworzyć element menu, który umożliwia użytkownikom przypinanie karty osi czasu. Karta osi czasu będzie się wtedy wyświetlać na stałe po lewej stronie głównej karty zegara. Użytkownicy mogą też odpiąć kartę, korzystając z tego samego menu.

Element menu przypinania jest wbudowanym elementem menu, więc wystarczy, że podasz parametr TOGGLE_PINNED action dla parametru menuItem.

Nieprzetworzony HTTP

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

Subskrypcje

Interfejs Mirror API umożliwia subskrybowanie powiadomień, które są wysyłane, gdy użytkownik wykona określone działania dotyczące elementu osi czasu lub gdy zaktualizuje swoją lokalizację. Gdy subskrybujesz powiadomienie, podajesz adres URL wywołania zwrotnego, który przetwarza powiadomienie.

Otrzymywanie powiadomień

Powiadomienie z interfejsu Mirror API jest wysyłane jako żądanie POST do subskrybowanego punktu końcowego z zawartością żądania JSON.

Nieprzetworzony HTTP

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

Jeśli nie wystąpił żaden błąd, usługa musi odpowiedzieć interfejsowi API kodem stanu HTTP 200 OK. Jeśli usługa odpowie kodem błędu, interfejs Mirror API może spróbować ponownie wysłać powiadomienie do usługi.

Typy powiadomień

Interfejs Mirror API wysyła różne dane powiadomienia w zależności od zdarzenia.

Odpowiedz

Użytkownik odpowiedział na Twój element osi czasu, korzystając z wbudowanego elementu menu REPLY:

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

Atrybut itemId jest ustawiony na ID elementu zawierającego:

  • atrybut inReplyTo ustawiony na ID elementu osi czasu, na który jest odpowiedzią;
  • atrybut text ustawiony na transkrypcję tekstu.
  • Atrybut recipients ustawiony na creator elementu osi czasu, do którego jest on odpowiedzią (jeśli istnieje).

Przykład:

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

Usuń

Użytkownik usunął element osi czasu:

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

Atrybut itemId jest ustawiony na identyfikator usuniętego elementu. Element nie zawiera już żadnych metadanych poza identyfikatorem i właściwością isDeleted.

Wybrano element menu niestandardowego

Użytkownik wybrał element menu niestandardowego ustawiony przez Twoją usługę:

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

Atrybut itemId jest ustawiony na identyfikator wybranego przez użytkownika elementu menu.

Tablica userActions zawiera listę działań niestandardowych, które użytkownik wykonał na tym elemencie. Usługa powinna odpowiednio obsługiwać te działania.

Aktualizacja lokalizacji

Nowa lokalizacja jest dostępna dla bieżącego użytkownika:

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

Gdy Glassware otrzyma aktualizację lokalizacji, wyślij żądanie do punktu końcowego glass.locations.get, aby pobrać najnowszą znaną lokalizację. Urządzenie Glassware otrzymuje aktualizacje lokalizacji co 10 minut.

Polecenie głosowe

Użytkownik aktywował polecenie głosowe, na przykład: „OK Glass, zanotuj, że jutro jest urodziny Cat Stream w Chipotle”. Na Twój adres Glassware:

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

To powiadomienie różni się od innych powiadomień wartością LAUNCH w właściwości userActions.

Następnie możesz użyć wartości w itemId, aby pobrać element osi czasu:

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

Właściwość recipients zawiera id kontaktu, który reprezentuje użytą komendę głosową.