You can insert, update, read, and delete static cards using simple REST APIs. In addition, you can attach objects to a static card, such as a location or media.
How they work
Static cards reside to the right of the Glass clock by default and display information relevant to the user at the time of delivery. However, they do not require immediate attention like live cards and users can choose to read or act on the card at their own leisure.
When Glassware inserts static cards into the timeline, Glass may play a notification sound to alert users. All previous static cards also shift to the right and disappear from the timeline after 7 days or when 200 cards are newer.
When to use them
Static cards are great for delivering
periodic notifications
to users as important things happen.
For example, a news delivery service that
sends the top news stories as they happen. Mirror API static cards
can also start live cards or
immersions through the
OPEN_URI
menu item. This allows you to create hybrid interactions that utilize
static cards as notifications and a live card or immersion for
a more interactive experience.
For a full list of possible operations for timeline items, see the reference documentation.
Inserting static cards
To insert static cards (timeline items), POST a JSON representation of a timeline item to the REST endpoint.
Most of the fields in a timeline item are optional. In its simplest form, a timeline item contains only a short text message, like in this example:
Raw 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()
On success, you receive a 201 Created
response code with a
full copy of the created item. For the previous example, a successful response
might look like this:
Raw 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"
}
The inserted item that would appear in the user's timeline looks like this:
Inserting a timeline item with an attachment
A picture is worth a thousand words, which is a lot more than you can fit into a timeline item. To this end, you can also attach images and video to a timeline item. Here's an example of how to insert a timeline item with a photo attachment:
Raw 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()
A timeline item with an attached image looks something like this on Glass:
Attaching video
If you are attaching video files to your timeline items, we recommend that you stream the video instead of uploading the entire payload at once. The Google Mirror API supports streaming with HTTP live streaming, progressive download, and the real time streaming protocol (RTSP). RTSP is frequently blocked by firewalls, so use the other options when possible.
To stream video, use the PLAY_VIDEO
built-in menu item and specify the video's URL to be the menu item's
payload
. See
Adding built-in menu items and
supported media formats
for more information.
Paginating
You can paginate timeline items that do not fit on a single timeline card,
but should otherwise be associated with the same card. Paginated
items all share the same timeline.id
and therefore have the
same set of menu items. When a user taps a paginated timeline item, a
Read more menu item appears.
Glass automatically paginates timeline items that display
text
. To have Glass automatically
paginate html
, use the article
tag with its class property set to auto-paginate
like in the following example:
<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>
To paginate manually, use the article
tag for the content
that you want to display on each card. Glass displays the contents of each
article
tag in a separate sub-timeline card. For example, you can create a
paginated timeline item with the following 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>
By default, the paginated timeline item's first card is displayed as the
cover card and is again displayed when the user selects the Read more
menu item. To prevent the first card from appearing again after tapping
Read more, you can specify the cover-only
CSS class for the first
<article>
tag:
<article class="cover-only">
...
The cover-only
class also supports auto-paginated timeline items:
<article class="auto-paginate cover-only">
...
Bundling
Bundling allows you to group related but distinct items together, like for individual messages in an email thread. Bundles have a main cover card that a user taps to display a sub-timeline that contains the other cards in the bundle. Bundles are distinguished from normal timeline cards by a corner fold in the upper right corner of the bundle's cover card.
To bundle timeline items, create them with the same value for
bundleId
. The most recently added
item is the bundle's cover card.
The following images show a bundle cover card with the corner fold at the top right corner and two bundled cards below it.
Reading timeline items
Your service can access all timeline items that it created, and all timeline items that were shared with it. Here's how to list the timeline items that are visible to your service.
Raw 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()
You can use other REST operations to get, update and delete timeline items.
Accessing attachments
You can access attachments to a timeline item through
an array property named attachments
.
You can then obtain the binary data of an attachment through the
contentUrl
property of the attachment or with the
attachments endpoint.
Raw 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();
Creating menu items
Menu items allow users to request actions that are related to the timeline card, and come in two types: built-in menu items and custom menu items.
Built-in menu items provide access to special functionalities provided by Glass, such as reading a timeline card aloud, navigating to a location, sharing an image, or replying to a message:
Custom menu items allow your application to expose behavior that is specific to your Glassware, and you can also provide a menu item icon to match your branding.
Adding built-in menu items
You can add built-in menu items to your timeline items by populating the
menuItems array
when you insert them.
To use a built-in menu item, you only need to populate the
action
of each menuItem
.
Raw 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"
}
]
}
Defining custom menu items
If built-in menu items don't work for you, you can create custom menu items with your own actions by doing the following when inserting or updating a timeline item:
- Specify
CUSTOM
formenuItem.action
. - Specify a
menuItem.id
. When users tap the custom menu item, your Glassware receives a notification withmenuItem.id
populated. This allows you to determine the source of the notification. - Specify
menuItem.values
to add aniconUrl
anddisplayName
that appears on Glass. Point to a 50 x 50 PNG image that is white in color with a transparent background for theiconUrl
. Specify a
displayTime
. If you do not specify adisplayTime
, the timeline item moves to the front of the timeline whenever users tap the custom menu item.
Raw 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"
}]
}
]
}
Allowing users to pin your timeline card
You can create a menu item that lets your users pin the timeline card, which permanently displays the timeline card to the left of the main clock card. Users can unpin the card as well, by using the same menu item.
The pinning menu item is a built-in menu item, so all you need to do is provide the TOGGLE_PINNED
action
for a menuItem
.
Raw 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"
}
...
]
}
Subscriptions
The Mirror API allows you to subscribe to notifications that are sent when the user takes specific actions on a Timeline Item or when the user location has been updated. When you subscribe to a notification, you provide a callback URL that processes the notification.
Receiving notifications
A notification from the Mirror API is sent as a POST
request to the
subscribed endpoint containing a JSON
request body.
Raw 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)
Your service must respond to the API with a 200 OK
HTTP status
code if no error occurred.
If your service responds with an error code, the Mirror API might
try to resend the notification to your service.
Notification types
The Mirror API sends a different notification payload for different events.
Reply
The user has replied to your timeline item using the built-in REPLY
menu item:
{
"collection": "timeline",
"itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
"operation": "INSERT",
"userToken": "harold_penguin",
"verifyToken": "random_hash_to_verify_referer",
"userActions": [
{
"type": "REPLY"
}
]
}
The itemId
attribute is set to the ID
of the item containing:
inReplyTo
attribute set to theID
of the timeline item it is a reply to.text
attribute set to the text transcription.recipients
attribute set to thecreator
of the timeline item it is a reply to, if it exists.
Example:
{
"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"
]
}
]
}
Delete
The user has deleted a timeline item:
{
"collection": "timeline",
"itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
"operation": "DELETE",
"userToken": "harold_penguin",
"verifyToken": "random_hash_to_verify_referer",
"userActions": [
{
"type": "DELETE"
}
]
}
The itemId
attribute is set to the ID of the deleted
item. The item no longer contains metadata other than its ID and the
isDeleted
property.
Custom menu item selected
The user has selected a custom menu item set by your service:
{
"collection": "timeline",
"itemId": "3hidvm0xez6r8_dacdb3103b8b604_h8rpllg",
"operation": "UPDATE",
"userToken": "harold_penguin",
"userActions": [
{
"type": "CUSTOM",
"payload": "PING"
}
]
}
The itemId
attribute is set to the ID of the menu item that
the user selected.
The userActions
array contains the list of custom actions
that the user took on this item. Your service should handle those
actions accordingly.
Location update
A new location is available for the current user:
{
"collection": "locations",
"itemId": "latest",
"operation": "UPDATE",
"userToken": "harold_penguin",
"verifyToken": "random_hash_to_verify_referer"
}
When your Glassware receives a location update, send a request to the glass.locations.get endpoint to retrieve the latest known location. Your Glassware receives location updates every ten minutes.
Voice command
Your user has activated a voice command, for example: "Ok Glass, take a note, Cat Stream, Chipotle's birthday is tomorrow". The following notification is sent to your Glassware:
{
"collection": "timeline",
"operation": "INSERT",
"userToken": "chipotle's_owner",
"verifyToken": "mew mew mew",
"itemId": "<ITEM_ID>",
"userActions": [
{“type”: "LAUNCH"}
]
}
This notification is distinguished from other notifications by the LAUNCH
value
in the userActions
property.
You can then use the value in itemId
to fetch the timeline item:
{
"id": "<ITEM_ID>",
"text": "Chipotle's birthday is tomorrow",
"recipients": [
{"id": "CAT_STREAM"}
]
}
The recipients
property contains the id
of the contact that represents the
voice command used.