Thẻ tĩnh

Bạn có thể chèn, cập nhật, đọc và xoá các thẻ tĩnh bằng cách sử dụng các API REST đơn giản. Ngoài ra, bạn có thể đính kèm các đối tượng vào một thẻ tĩnh, chẳng hạn như vị trí hoặc nội dung nghe nhìn.

Cách hoạt động

Theo mặc định, các thẻ tĩnh nằm ở bên phải đồng hồ Glass và hiển thị thông tin liên quan đến người dùng tại thời điểm phân phối. Tuy nhiên, các thông báo này không yêu cầu người dùng phải chú ý ngay lập tức như thẻ trực tiếp và người dùng có thể chọn đọc hoặc hành động theo thẻ vào thời gian rảnh.

Khi Glassware chèn thẻ tĩnh vào dòng thời gian, Glass có thể phát âm thanh thông báo để cảnh báo người dùng. Tất cả các thẻ tĩnh trước đó cũng sẽ chuyển sang bên phải và biến mất khỏi dòng thời gian sau 7 ngày hoặc khi có 200 thẻ mới hơn.

Khi nào nên sử dụng tiện ích vị trí đơn vị liên kết

Thẻ tĩnh rất phù hợp để gửi thông báo định kỳ cho người dùng khi có những việc quan trọng xảy ra. Ví dụ: một dịch vụ phân phối tin tức gửi các tin bài hàng đầu khi chúng xảy ra. Thẻ tĩnh Mirror API cũng có thể bắt đầu thẻ trực tiếp hoặc nội dung sống động thông qua mục trình đơn OPEN_URI. Điều này cho phép bạn tạo các hoạt động tương tác kết hợp, sử dụng thẻ tĩnh làm thông báo và thẻ trực tiếp hoặc chế độ sống động để có trải nghiệm tương tác cao hơn.

Để biết danh sách đầy đủ các thao tác có thể thực hiện đối với các mục trên dòng thời gian, hãy xem tài liệu tham khảo.

Chèn thẻ tĩnh

Để chèn thẻ tĩnh (mục trên dòng thời gian), hãy đăng biểu thị JSON của một mục trên dòng thời gian vào điểm cuối REST.

Hầu hết các trường trong một mục trên dòng thời gian đều không bắt buộc. Ở dạng đơn giản nhất, một mục trên dòng thời gian chỉ chứa một tin nhắn văn bản ngắn, chẳng hạn như trong ví dụ này:

HTTP thô

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

Khi thành công, bạn sẽ nhận được mã phản hồi 201 Created cùng với bản sao đầy đủ của mục đã tạo. Đối với ví dụ trước, một phản hồi thành công có thể có dạng như sau:

HTTP thô

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

Mục được chèn sẽ xuất hiện trên dòng thời gian của người dùng như sau:

Chèn một mục trên dòng thời gian có tệp đính kèm

Một bức ảnh đáng giá hơn ngàn lời nói, nhiều hơn rất nhiều so với những gì bạn có thể đưa vào một mục trên dòng thời gian. Để làm việc này, bạn cũng có thể đính kèm hình ảnh và video vào một mục trên dòng thời gian. Dưới đây là ví dụ về cách chèn một mục trên dòng thời gian có tệp đính kèm là ảnh:

HTTP thô

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

Một mục trong dòng thời gian có hình ảnh đính kèm sẽ trông như thế này trên Glass:

Đính kèm video

Nếu đang đính kèm tệp video vào các mục trên dòng thời gian, bạn nên phát trực tuyến video thay vì tải toàn bộ tải trọng lên cùng một lúc. Google Mirror API hỗ trợ truyền trực tuyến bằng giao thức truyền trực tuyến dựa trên HTTP, tải xuống liên tục và giao thức truyền trực tuyến theo thời gian thực (RTSP). RTSP thường bị tường lửa chặn, vì vậy, hãy sử dụng các lựa chọn khác nếu có thể.

Để phát trực tuyến video, hãy sử dụng mục trong trình đơn tích hợp PLAY_VIDEO và chỉ định URL của video là payload của mục trong trình đơn. Hãy xem phần Thêm các mục trong trình đơn tích hợp sẵncác định dạng nội dung nghe nhìn được hỗ trợ để biết thêm thông tin.

Phân trang

Bạn có thể phân trang các mục trên dòng thời gian không vừa với một thẻ dòng thời gian duy nhất, nhưng nếu không thì các mục này phải được liên kết với cùng một thẻ. Tất cả các mục được phân trang đều dùng chung cùng một timeline.id và do đó có cùng một nhóm mục trong trình đơn. Khi người dùng nhấn vào một mục trên dòng thời gian được phân trang, mục trình đơn Đọc thêm sẽ xuất hiện.

Glass tự động phân trang các mục trên dòng thời gian hiển thị text. Để Glass tự động phân trang html, hãy dùng thẻ article có thuộc tính lớp được đặt thành auto-paginate như trong ví dụ sau:

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

Để phân trang theo cách thủ công, hãy dùng thẻ article cho nội dung mà bạn muốn hiển thị trên mỗi thẻ. Glass hiển thị nội dung của từng thẻ article trong một thẻ phụ riêng biệt trên dòng thời gian. Ví dụ: bạn có thể tạo một mục trên dòng thời gian được phân trang bằng HTML sau:

<article>
 <section>
   <p>First page</p>
 </section>
</article>

<article>
 <section>
   <p>Second page</p>
 </section>
</article>

<article>
 <section>
   <p>Third page</p>
 </section>
</article>

Theo mặc định, thẻ đầu tiên của mục dòng thời gian được phân trang sẽ xuất hiện dưới dạng thẻ bìa và xuất hiện lại khi người dùng chọn mục trình đơn Đọc thêm. Để ngăn thẻ đầu tiên xuất hiện lại sau khi nhấn vào Đọc thêm, bạn có thể chỉ định lớp CSS cover-only cho thẻ <article> đầu tiên:

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

Lớp cover-only cũng hỗ trợ các mục trên dòng thời gian được phân trang tự động:

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

Nhóm

Tính năng kết hợp cho phép bạn nhóm các mục riêng biệt nhưng có liên quan với nhau, chẳng hạn như đối với từng tin nhắn trong một chuỗi email. Gói có một thẻ bìa chính mà người dùng nhấn vào để hiển thị một dòng thời gian phụ chứa các thẻ khác trong gói. Các gói được phân biệt với thẻ thông thường trên dòng thời gian bằng một nếp gấp ở góc trên bên phải của thẻ bìa gói.

Để nhóm các mục trên dòng thời gian, hãy tạo các mục đó bằng cùng một giá trị cho bundleId. Mặt hàng được thêm gần đây nhất là thẻ bìa của gói.

Các hình ảnh sau đây cho thấy một thẻ bìa gói có nếp gấp ở góc trên cùng bên phải và hai thẻ gói bên dưới.

Đọc các mục trên dòng thời gian

Dịch vụ của bạn có thể truy cập vào tất cả các mục trên dòng thời gian mà dịch vụ đó đã tạo và tất cả các mục trên dòng thời gian được chia sẻ với dịch vụ đó. Sau đây là cách liệt kê các mục trên dòng thời gian mà dịch vụ của bạn có thể nhìn thấy.

HTTP thô

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

Bạn có thể sử dụng các thao tác REST khác để lấy, cập nhậtxoá các mục trên dòng thời gian.

Truy cập vào tệp đính kèm

Bạn có thể truy cập vào tệp đính kèm của một mục trên dòng thời gian thông qua một thuộc tính mảng có tên là attachments. Sau đó, bạn có thể lấy dữ liệu nhị phân của một tệp đính kèm thông qua thuộc tính contentUrl của tệp đính kèm hoặc bằng điểm cuối tệp đính kèm.

HTTP thô

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

Tạo mục trong trình đơn

Các mục trong trình đơn cho phép người dùng yêu cầu các thao tác liên quan đến thẻ trên dòng thời gian và có 2 loại: mục trong trình đơn tích hợp và mục trong trình đơn tuỳ chỉnh.

Các mục trong trình đơn tích hợp cho phép truy cập vào các chức năng đặc biệt do Glass cung cấp, chẳng hạn như đọc to thẻ trên dòng thời gian, chuyển đến một vị trí, chia sẻ hình ảnh hoặc trả lời tin nhắn:

Các mục trong trình đơn tuỳ chỉnh cho phép ứng dụng của bạn hiển thị hành vi cụ thể cho Glassware, đồng thời bạn cũng có thể cung cấp biểu tượng mục trong trình đơn cho phù hợp với thương hiệu của mình.

Thêm các mục trong trình đơn tích hợp

Bạn có thể thêm các mục trình đơn tích hợp vào các mục trên dòng thời gian bằng cách điền sẵn menuItems array khi chèn các mục đó. Để sử dụng một mục trong trình đơn tích hợp, bạn chỉ cần điền action của mỗi menuItem.

HTTP thô

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

Xác định các mục tuỳ chỉnh trong trình đơn

Nếu các mục trong trình đơn tích hợp không phù hợp với bạn, bạn có thể tạo các mục trong trình đơn tuỳ chỉnh bằng các thao tác của riêng mình bằng cách làm như sau khi chèn hoặc cập nhật một mục trên dòng thời gian:

  • Chỉ định CUSTOM cho menuItem.action.
  • Chỉ định một menuItem.id. Khi người dùng nhấn vào mục tuỳ chỉnh trong trình đơn, Glassware của bạn sẽ nhận được một thông báo có menuItem.id được điền sẵn. Nhờ đó, bạn có thể xác định nguồn của thông báo.
  • Chỉ định menuItem.values để thêm iconUrldisplayName xuất hiện trên Glass. Chỉ đến một hình ảnh PNG 50 x 50 có màu trắng và nền trong suốt cho iconUrl.
  • Chỉ định một displayTime. Nếu bạn không chỉ định displayTime, thì mục trên dòng thời gian sẽ di chuyển lên đầu dòng thời gian bất cứ khi nào người dùng nhấn vào mục tuỳ chỉnh trong trình đơn.

HTTP thô

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

Cho phép người dùng ghim thẻ dòng thời gian của bạn

Bạn có thể tạo một mục trong trình đơn cho phép người dùng ghim thẻ dòng thời gian. Thẻ này sẽ hiển thị vĩnh viễn ở bên trái thẻ đồng hồ chính. Người dùng cũng có thể bỏ ghim thẻ bằng cách sử dụng cùng một mục trong trình đơn.

Mục trong trình đơn ghim là một mục trong trình đơn tích hợp, vì vậy, bạn chỉ cần cung cấp TOGGLE_PINNED action cho menuItem.

HTTP thô

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

Gói thuê bao

Mirror API cho phép bạn đăng ký nhận thông báo được gửi khi người dùng thực hiện các hành động cụ thể trên một Mục trên dòng thời gian hoặc khi vị trí của người dùng được cập nhật. Khi đăng ký nhận thông báo, bạn sẽ cung cấp một URL gọi lại để xử lý thông báo.

Nhận thông báo

Thông báo từ Mirror API được gửi dưới dạng yêu cầu POST đến điểm cuối đã đăng ký chứa nội dung yêu cầu JSON.

HTTP thô

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

Dịch vụ của bạn phải phản hồi API bằng mã trạng thái HTTP 200 OK nếu không xảy ra lỗi. Nếu dịch vụ của bạn phản hồi bằng mã lỗi, Mirror API có thể cố gắng gửi lại thông báo đến dịch vụ của bạn.

Loại thông báo

Mirror API gửi một tải trọng thông báo khác cho các sự kiện khác nhau.

Trả lời

Người dùng đã trả lời mục trên dòng thời gian của bạn bằng mục trình đơn REPLY tích hợp:

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

Thuộc tính itemId được đặt thành ID của mặt hàng chứa:

  • Thuộc tính inReplyTo được đặt thành ID của mục trên dòng thời gian mà đó là câu trả lời.
  • Thuộc tính text được đặt thành bản chép lời văn bản.
  • Thuộc tính recipients được đặt thành creator của mục trên dòng thời gian mà mục đó là câu trả lời, nếu có.

Ví dụ:

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

Xoá

Người dùng đã xoá một mục trên dòng thời gian:

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

Thuộc tính itemId được đặt thành mã nhận dạng của mặt hàng đã bị xoá. Mặt hàng không còn chứa siêu dữ liệu nào khác ngoài mã nhận dạng và thuộc tính isDeleted.

Đã chọn mục tuỳ chỉnh trong trình đơn

Người dùng đã chọn một mục tuỳ chỉnh trong trình đơn do dịch vụ của bạn đặt:

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

Thuộc tính itemId được đặt thành mã nhận dạng của mục trong trình đơn mà người dùng đã chọn.

Mảng userActions chứa danh sách các thao tác tuỳ chỉnh mà người dùng đã thực hiện trên mục này. Dịch vụ của bạn phải xử lý những thao tác đó cho phù hợp.

Thông báo cập nhật vị trí

Một vị trí mới có sẵn cho người dùng hiện tại:

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

Khi Glassware nhận được thông tin cập nhật về vị trí, hãy gửi yêu cầu đến điểm cuối glass.locations.get để truy xuất vị trí đã biết gần đây nhất. Glassware của bạn nhận được thông tin cập nhật vị trí cứ mười phút một lần.

Lệnh thoại

Người dùng đã kích hoạt một lệnh thoại, ví dụ: "Ok Glass, take a note, Cat Stream, Chipotle's birthday is tomorrow" ("Ok Glass, ghi chú, Cat Stream, sinh nhật của Chipotle là vào ngày mai"). Thông báo sau đây sẽ được gửi đến Glassware của bạn:

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

Thông báo này khác với các thông báo khác nhờ giá trị LAUNCH trong thuộc tính userActions.

Sau đó, bạn có thể dùng giá trị trong itemId để tìm nạp mục trên dòng thời gian:

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

Thuộc tính recipients chứa id của người liên hệ đại diện cho lệnh thoại được dùng.