Karty statyczne

Możesz wstawiać, aktualizować, odczytywać i usuwać karty statyczne za pomocą prostych interfejsów API typu REST. Do karty statycznej możesz dołączać obiekty, np. lokalizację lub nośnik.

Jak działają

Karty statyczne są domyślnie umieszczone po prawej stronie zegara Glass i wyświetlają informacje istotne dla użytkownika w momencie dostawy. Nie wymagają jednak natychmiastowej uwagi (np. kart transmisji na żywo), a użytkownicy mogą samodzielnie odczytać lub wykonać inne działania na karcie.

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

Kiedy ich używać

Karty statyczne idealnie nadają się do dostarczania okresowych powiadomień o ważnych wydarzeniach. Może to być na przykład usługa dostarczania wiadomości, która na bieżąco przesyła najważniejsze wiadomości. Karty statyczne interfejsu Mirror API mogą też uruchamiać karty transmisji na żywo lub materiały informacyjne za pomocą pozycji menu OPEN_URI. Dzięki temu możesz tworzyć interakcje hybrydowe, które wykorzystują karty statyczne jako powiadomienia oraz aktywne karty lub gry immersyjne, aby zapewnić bardziej interaktywną rozgrywkę.

Pełną listę możliwych operacji na elementach osi czasu znajdziesz w dokumentacji referencyjnej.

Wstawianie kart statycznych

Aby wstawić karty statyczne (elementy osi czasu), opublikuj reprezentację elementu osi czasu w formacie JSON w punkcie końcowym REST.

Większość pól elementu osi czasu jest opcjonalna. W najprostszej formie element na osi czasu zawiera tylko krótki komunikat tekstowy, jak w tym przykładzie:

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

Jeśli wszystko się uda, otrzymasz kod odpowiedzi 201 Created z pełną kopią utworzonego elementu. W poprzednim przykładzie pomyślna odpowiedź może wyglądać tak:

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

Wstawiony element, który pojawi się na osi czasu użytkownika, będzie wyglądał tak:

Wstawianie elementu na osi czasu z załącznikiem

Obraz jest wart tysiąca słów, a to znacznie więcej, niż można zmieścić na osi czasu. Do elementu osi czasu możesz też dołączać obrazy i filmy. Oto przykład wstawiania elementu osi czasu z załączonym zdjęciem:

Nieprzetworzony kod 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 na Google Glass podobny do tego:

Załączam film

Jeśli do elementów na osi czasu dołączasz pliki wideo, zalecamy przesyłanie strumieniowe filmu zamiast przesyłania całego ładunku za jednym razem. Interfejs Google Mirror API obsługuje strumieniowanie z użyciem transmisji na żywo przez HTTP, progresywnego pobierania oraz protokołu strumieniowego przesyłania w czasie rzeczywistym (RTSP). Protokół RTSP jest często blokowany przez zapory sieciowe, więc w miarę możliwości korzystaj z innych opcji.

Aby strumieniować wideo, użyj wbudowanego polecenia PLAY_VIDEO i jako URL filmu podaj payload tego elementu. Więcej informacji znajdziesz w sekcjach Dodawanie wbudowanych pozycji menu i obsługiwanych formatów multimediów.

Podział na strony

Możesz dzielić 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 pozycje podzielone na strony korzystają z tego samego elementu timeline.id i dlatego mają ten sam zestaw pozycji menu. Gdy użytkownik kliknie element osi czasu podzielony na strony, pojawi się pozycja menu Więcej informacji.

Google Glass automatycznie dzieli elementy osi czasu na strony z wyświetlonym symbolem text. Aby Google Glass automatycznie dzieliło strony na strony html, użyj tagu article z właściwością klasy 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 podzielić treści na strony, użyj tagu article dla treści, które chcesz wyświetlać na poszczególnych kartach. Google Glass wyświetla zawartość każdego tagu article na osobnej karcie osi czasu. Na przykład możesz utworzyć element osi czasu podzielony na strony, używając 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 osi czasu z podziałem na strony jest wyświetlana jako okładka i pojawia się ponownie, gdy użytkownik wybierze pozycję menu Więcej informacji. Aby uniemożliwić wyświetlanie pierwszej karty 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ż elementy osi czasu podzielone automatycznie na strony:

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

Łączenie

Grupowanie pozwala na grupowanie powiązanych, ale odrębnych elementów, np. pojedynczych wiadomości w wątku e-maila. Pakiety mają główną okładkę pakietu, którą użytkownik może kliknąć, aby wyświetlić podoś czasu, która obejmuje inne karty z pakietu. Pakiety różnią się od zwykłych kart osi czasu dzięki zawinięciu narożnika w prawym górnym rogu okładki pakietu.

Aby połączyć elementy osi czasu, utwórz je z tą samą wartością bundleId. Ostatnim dodanym elementem jest okładkę pakietu.

Poniższe obrazy przedstawiają pakiet ze zwijaną okładką w prawym górnym rogu, a pod nim 2 pakiety kart.

Odczytywanie elementów osi czasu

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

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

Do pobierania, aktualizowania i usuwania elementów na osi czasu możesz używać innych operacji REST.

Dostęp do załączników

Dostęp do załączników do elementu osi czasu możesz uzyskiwać za pomocą właściwości tablicy o nazwie attachments. Dane binarne załącznika możesz wtedy pobrać za pomocą właściwości contentUrl załącznika lub za pomocą punktu końcowego załączników.

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

Tworzę pozycje menu

Pozycje menu umożliwiają użytkownikom wysyłanie żądań działań związanych z kartą osi czasu. Są 2 rodzaje elementów menu: wbudowane i niestandardowe.

Wbudowane pozycje menu dają dostęp do specjalnych funkcji Google Glass, takich jak odczytywanie karty osi czasu, nawigowanie do lokalizacji, udostępnianie obrazu czy odpowiadanie na wiadomość:

Niestandardowe pozycje menu pozwalają aplikacji pokazać zachowanie charakterystyczne dla oprogramowania Glassware. Możesz też dodać ikonę menu, która pasuje do Twojej marki.

Dodawanie wbudowanych pozycji menu

Możesz dodać wbudowane pozycje menu do elementów na osi czasu, wypełniając pole menuItems array podczas ich wstawiania. Aby użyć wbudowanej pozycji menu, wystarczy, że wypełnisz action każdego elementu menuItem.

Nieprzetworzony kod 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 pozycje menu nie sprawdzają się w Twoim przypadku, możesz utworzyć niestandardowe pozycje menu z własnymi działaniami, wykonując te czynności podczas wstawiania lub aktualizowania elementu osi czasu:

  • W polu menuItem.action podaj CUSTOM.
  • Określ wartość w polu menuItem.id. Gdy użytkownik dotknie tego menu, aplikacja Glassware otrzyma powiadomienie z wypełnioną wartością menuItem.id. Dzięki temu możesz określić źródło powiadomienia.
  • Wpisz menuItem.values, aby dodać iconUrl i displayName, które będą widoczne na Google Glass. Wskaż obraz PNG o wymiarach 50 x 50, który jest biały z przezroczystym tłem dla elementu iconUrl.
  • Określ wartość w polu displayTime. Jeśli nie określisz wartości displayTime, element osi czasu przesuwa się na początek osi czasu po kliknięciu tego elementu menu przez użytkownika.

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

Umożliwianie użytkownikom przypinania karty osi czasu

Możesz utworzyć element menu umożliwiający użytkownikom przypięcie karty osi czasu, która na stałe wyświetla ją po lewej stronie głównej karty zegara. Użytkownicy mogą też odpiąć kartę za pomocą tego samego elementu menu.

Przypięcie pozycji menu jest wbudowaną funkcją, więc wystarczy, że podasz TOGGLE_PINNED action dla: menuItem.

Nieprzetworzony kod 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ń wysyłanych, gdy użytkownik wykona określone działania na elemencie osi czasu lub po zaktualizowaniu lokalizacji użytkownika. 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 zawierającego treść żądania JSON.

Nieprzetworzony kod 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ł błąd, Twoja usługa musi odpowiedzieć na interfejs API kodem stanu HTTP 200 OK. Jeśli usługa w odpowiedzi wyświetli kod błędu, interfejs Mirror API może spróbować ponownie wysłać powiadomienie do usługi.

Typy powiadomień

Interfejs Mirror API wysyła inny ładunek powiadomień w przypadku różnych zdarzeń.

Odpowiedz

Użytkownik odpowiedział na element na osi czasu, używając 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 wartość ID produktu zawierającego:

  • inReplyTo ma wartość ID elementu osi czasu, na który odpowiada.
  • Atrybut text został ustawiony na transkrypcję tekstu.
  • Atrybut recipients jest ustawiony na creator elementu osi czasu, na który jest 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 przyjmuje identyfikator usuniętego elementu. Element nie zawiera już metadanych innych niż jego identyfikator i właściwość isDeleted.

Wybrano niestandardową pozycję menu

Użytkownik wybrał niestandardową pozycję menu ustawioną 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 pozycji menu wybranej przez użytkownika.

Tablica userActions zawiera listę niestandardowych działań, które użytkownik podjął w odniesieniu do danego elementu. Usługa powinna odpowiednio wykonać te działania.

Aktualizacja lokalizacji

Dla bieżącego użytkownika dostępna jest nowa lokalizacja:

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

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

Polecenie głosowe

Użytkownik aktywował polecenie głosowe, na przykład: „OK Glass, zanotuj, Cat Stream, urodziny Chipotle'a są jutro”. Na urządzenie Glass zostanie wysłane następujące powiadomienie:

{
  "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 we właściwości userActions.

Następnie możesz użyć wartości w polu itemId do pobrania elementu osi czasu:

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

Właściwość recipients zawiera element id kontaktu, który reprezentuje użyte polecenie głosowe.