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

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

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

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

Когда 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"
    }
  ...
 ]
}

Подписки

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 , если ошибок не произошло. Если ваша служба отвечает кодом ошибки, API зеркала может попытаться повторно отправить уведомление в вашу службу.

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

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