Статические карты

Вы можете вставлять, обновлять, читать и удалять статические карты с помощью простых REST API. Кроме того, к статической карточке можно прикреплять объекты, такие как местоположение или медиа.

Как они работают

Статические карты по умолчанию располагаются справа от часов Glass и отображают информацию, актуальную для пользователя на момент доставки. Однако они не требуют немедленного внимания, как живые карты , и пользователи могут читать или действовать на карте по своему усмотрению.

Когда Glassware вставляет статические карты на временную шкалу, Glass может воспроизводить звук уведомления, чтобы предупредить пользователей. Все предыдущие статические карты также смещаются вправо и исчезают с временной шкалы через 7 дней или когда 200 карт новее.

Когда их использовать

Статические карточки отлично подходят для периодических уведомлений пользователей о важных событиях. Например, служба доставки новостей, которая рассылает самые популярные новости по мере их появления. Статические карты Mirror API также могут запускать живые карты или погружения через пункт меню OPEN_URI . Это позволяет создавать гибридные взаимодействия, в которых статические карточки используются в качестве уведомлений, а живые карточки или погружение — для более интерактивного взаимодействия.

Полный список возможных операций с элементами временной шкалы смотрите в справочной документации .

Вставка статических карт

Чтобы вставить статические карточки (элементы временной шкалы), отправьте JSON-представление элемента временной шкалы в конечную точку REST.

Большинство полей в элементе временной шкалы являются необязательными. В своей простейшей форме элемент временной шкалы содержит только короткое текстовое сообщение, как в этом примере:

Необработанный 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" }

Джава

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
service.timeline().insert(timelineItem).execute();

питон

timeline_item = {'text': 'Hello world'}
service.timeline().insert(body=timeline_item).execute()

В случае успеха вы получите код ответа 201 Created с полной копией созданного элемента. Для предыдущего примера успешный ответ может выглядеть так:

Необработанный 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"
}

Вставленный элемент, который появится на временной шкале пользователя, выглядит следующим образом:

Вставка элемента временной шкалы с вложением

Изображение стоит тысячи слов, а это намного больше, чем вы можете вместить в элемент временной шкалы. С этой целью вы также можете прикреплять изображения и видео к элементу временной шкалы. Вот пример того, как вставить элемент временной шкалы с прикрепленным фото:

Необработанный 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--

Джава

TimelineItem timelineItem = new TimelineItem();
timelineItem.setText("Hello world");
InputStreamContent mediaContent = new InputStreamContent(contentType, attachment);
service.timeline().insert(timelineItem, mediaContent).execute();

питон

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

Элемент временной шкалы с прикрепленным изображением выглядит на Glass примерно так:

Прикрепление видео

Если вы прикрепляете видеофайлы к элементам временной шкалы, мы рекомендуем выполнять потоковую передачу видео, а не загружать всю полезную нагрузку сразу. API-интерфейс Google Mirror поддерживает потоковую передачу в режиме реального времени по протоколу HTTP, прогрессивную загрузку и протокол потоковой передачи в реальном времени (RTSP). RTSP часто блокируется брандмауэрами, поэтому по возможности используйте другие варианты.

Для потоковой передачи видео используйте встроенный пункт меню PLAY_VIDEO и укажите URL-адрес видео в качестве payload пункта меню. Дополнительную информацию см. в разделе Добавление встроенных элементов меню и поддерживаемых форматов мультимедиа .

Пагинация

Вы можете разбить на страницы элементы временной шкалы, которые не помещаются на одной карточке временной шкалы, но в противном случае должны быть связаны с одной и той же карточкой. Все элементы с разбивкой на страницы имеют один и тот же timeline.id и, следовательно, имеют одинаковый набор пунктов меню. Когда пользователь касается элемента временной шкалы с разбивкой на страницы, появляется пункт меню «Читать далее» .

Glass автоматически разбивает на страницы элементы временной шкалы, отображающие text . Чтобы Glass автоматически разбивал html на страницы, используйте тег article со свойством класса, установленным на auto-paginate как в следующем примере:

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

Чтобы разбить страницы вручную, используйте тег article для контента, который вы хотите отобразить на каждой карточке. Glass отображает содержимое каждого тега article на отдельной карточке временной шкалы. Например, вы можете создать элемент временной шкалы с разбивкой на страницы со следующим 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>

По умолчанию первая карточка элемента временной шкалы с разбивкой на страницы отображается как обложка и снова отображается, когда пользователь выбирает пункт меню Подробнее . Чтобы первая карточка не появлялась снова после нажатия «Подробнее» , вы можете указать класс CSS cover-only для первого тега <article> :

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

Класс cover-only также поддерживает элементы временной шкалы с автоматической разбивкой на страницы:

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

Комплектация

Объединение позволяет группировать связанные, но разные элементы вместе, например, отдельные сообщения в ветке электронной почты. Пакеты имеют основную обложку, которую пользователь нажимает, чтобы отобразить вспомогательную временную шкалу, содержащую другие карты в пакете. Пакеты отличаются от обычных карточек временной шкалы сгибом в правом верхнем углу обложки пакета.

Чтобы связать элементы временной шкалы, создайте их с тем же значением для bundleId . Последний добавленный элемент — это обложка набора.

На следующих изображениях показана обложка пакета со сгибом в правом верхнем углу и двумя пакетами карт под ним.

Чтение элементов временной шкалы

Ваша служба может получить доступ ко всем элементам временной шкалы, которые она создала, и ко всем элементам временной шкалы, к которым она предоставила общий доступ. Вот как составить список элементов временной шкалы, видимых для вашего сервиса.

Необработанный HTTP

GET /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

Джава

TimelineItem timelineItem = new TimelineItem();
service.timeline().list().execute();

питон

service.timeline().list().execute()

Вы можете использовать другие операции REST для получения , обновления и удаления элементов временной шкалы.

Доступ к вложениям

Вы можете получить доступ к вложениям к элементу временной шкалы через свойство массива с именем attachments . Затем вы можете получить двоичные данные вложения через свойство contentUrl вложения или с помощью конечной точки вложения .

Необработанный HTTP

GET /mirror/v1/timeline/{itemId}/attachments/{attachmentId} HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}

Джава

TimelineItem item = service.timeline().get(itemId).execute();
String attachmentId = item.getAttachments().get(0).getId();
service.attachments().get(itemId, attachmentId).executeAsInputStream();

Создание пунктов меню

Элементы меню позволяют пользователям запрашивать действия, связанные с карточкой временной шкалы, и бывают двух типов: встроенные элементы меню и настраиваемые элементы меню.

Встроенные элементы меню обеспечивают доступ к специальным функциям, предоставляемым Glass, таким как чтение вслух карты временной шкалы, навигация к местоположению, совместное использование изображения или ответ на сообщение:

Настраиваемые элементы меню позволяют вашему приложению отображать поведение, специфичное для вашего Glassware, и вы также можете предоставить значок элемента меню, соответствующий вашему брендингу.

Добавление встроенных пунктов меню

Вы можете добавлять встроенные элементы меню к элементам временной шкалы, заполняя menuItems array при их вставке. Чтобы использовать встроенный пункт меню, вам нужно только заполнить action каждого menuItem .

Необработанный 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"
    }
  ]
}

Определение пользовательских пунктов меню

Если встроенные элементы меню вам не подходят, вы можете создать настраиваемые элементы меню с помощью собственных действий, выполнив следующие действия при вставке или обновлении элемента временной шкалы:

  • Укажите CUSTOM для menuItem.action .
  • Укажите menuItem.id . Когда пользователи нажимают на пользовательский элемент меню, ваш Glassware получает уведомление с заполненным menuItem.id . Это позволяет определить источник уведомления.
  • Укажите menuItem.values , чтобы добавить iconUrl и displayName , которые отображаются на Glass. Укажите на изображение PNG размером 50 x 50 белого цвета с прозрачным фоном для iconUrl .
  • Укажите displayTime . Если вы не укажете displayTime , элемент временной шкалы перемещается в начало временной шкалы всякий раз, когда пользователи касаются пользовательского элемента меню.

Необработанный 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"
      }]
    }
  ]
}

Разрешить пользователям закреплять вашу карточку временной шкалы

Вы можете создать пункт меню, который позволит вашим пользователям закрепить карточку временной шкалы, которая будет постоянно отображать карточку временной шкалы слева от основной карточки часов. Пользователи также могут открепить карту, используя тот же пункт меню.

Пункт меню закрепления — это встроенный пункт меню, поэтому все, что вам нужно сделать, это указать action TOGGLE_PINNED для menuItem .

Необработанный 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"
    }
  ...
 ]
}

Подписки

Mirror API позволяет подписаться на уведомления , которые отправляются, когда пользователь выполняет определенные действия с элементом временной шкалы или когда местоположение пользователя обновляется. Когда вы подписываетесь на уведомление, вы предоставляете URL-адрес обратного вызова, который обрабатывает уведомление.

Получение уведомлений

Уведомление от Mirror API отправляется в виде запроса POST на подписанную конечную точку, содержащую тело запроса JSON .

Необработанный HTTP

{
  "collection": "timeline",
  "itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
  "operation": "UPDATE",
  "userToken": "harold_penguin",
  "verifyToken": "random_hash_to_verify_referer",
  "userActions": [
    {
      "type": "<TYPE>",
      "payload": "<PAYLOAD>"
    }
  ]
}

Джава

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

  // ...
}

питон

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)

Ваша служба должна ответить API с кодом состояния HTTP 200 OK , если не произошло ошибки. Если ваша служба отвечает кодом ошибки, Mirror API может попытаться повторно отправить уведомление вашей службе.

Типы уведомлений

Mirror API отправляет разные полезные данные уведомления для разных событий.

Отвечать

Пользователь ответил на ваш элемент временной шкалы, используя встроенный пункт меню REPLY :

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

Атрибут itemId устанавливается на ID элемента, содержащего:

  • Атрибут inReplyTo установлен на ID элемента временной шкалы, на который он является ответом.
  • атрибут text установлен на транскрипцию текста.
  • Атрибут recipients , установленный для creator элемента временной шкалы, на который он является ответом, если он существует.

Пример:

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

Удалить

Пользователь удалил элемент временной шкалы:

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

Атрибут itemId устанавливается равным идентификатору удаленного элемента. Элемент больше не содержит метаданных, кроме его идентификатора и свойства isDeleted .

Выбран пользовательский пункт меню

Пользователь выбрал настраиваемый пункт меню , установленный вашим сервисом:

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

Атрибут itemId устанавливается равным идентификатору пункта меню, который выбрал пользователь.

Массив userActions содержит список настраиваемых действий, которые пользователь выполнил над этим элементом. Ваша служба должна соответствующим образом обрабатывать эти действия.

Обновление местоположения

Для текущего пользователя доступно новое местоположение:

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

Когда ваше устройство Glassware получит обновление местоположения, отправьте запрос на конечную точку glass.locations.get , чтобы получить последнее известное местоположение. Ваша стеклянная посуда получает обновления местоположения каждые десять минут.

Голосовая команда

Ваш пользователь активировал голосовую команду, например: «Окей, Стекло, возьми на заметку, Cat Stream, у Chipotle завтра день рождения». На ваш Glassware отправляется следующее уведомление:

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

Это уведомление отличается от других уведомлений значением LAUNCH в свойстве userActions .

Затем вы можете использовать значение в itemId для получения элемента временной шкалы:

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

Свойство recipients содержит id контакта, представляющего использованную голосовую команду.