The Mirror Code

With our list of tasks in order, now we get to implement the behavior we expect from our Glassware extension.

Login/Authorization

Adding Google Glass authorization requires that a user already have a Google account. All Glass users must have one for Glass to function, so luckily you’ll never have to deal with the case where a user doesn’t have an account. However, that doesn’t mean your application employs any of Google’s user-management systems, like OpenID or OAuth. When integrating Glassware into your existing app, you’ll have to give some thought to how your own user-management system can associate its accounts with the necessary Google account.

One option is to have a user first log in to your own app, keeping her credentials in session as you normally would. Then, when she wants to activate your Glassware extension, she uses Google’s OAuth mechanism. Your OAuth callback will then associate the Google user ID with the ID currently in session, and store those tokens together as a single user profile. However you choose to implement your user manager, you’ll have to keep track of Google’s user credentials to make use of the Mirror API.

If you aren’t married to any particular login system, it’s easiest to utilize Google’s user profiles, which is exactly what we did with ChittrChattr. In that case, it’s a simple matter of adding the glass.timeline scope to the GoogleAuthorizationCodeFlow.Builder, as we did in Chapter 3, Authorizing Your Glassware.

A Contact and a Subscription

The next two items tie into the user-authorization step. Once a user has successfully authorized your Glassware, you’re free to immediately start making Mirror requests. The first step is to create a contact object that will represent ChittrChattr, and the second is a create a new Subscription to inform Mirror that your app wants to be notified when a user issues a TAKE_A_NOTE command to ChittrChattr.

Before adding any Mirror code, you’ll need the Mirror API client. Since our app is written as a Java web app in Android Developer Tools, you can add it easily enough: right-click the project, then choose Google -> Add Google APIs, search for mirror to find the Google Mirror API, select it, and click Finish.

We’ll also be using MirrorUtils class code similar to that from previous chapters. It’s just a collection of convenience functions for getting a Mirror object from any credentials or user ID.

Now let’s look at the code we’ll need to add. At the end of the OAuth2Servlet, before a user is redirected, add the following Contact-creation code. Note that you should change the PROD_BASE_URL value to be your own app’s URL.

chapter-8/src/test/book/glass/auth/OAuth2Servlet.java
 
Contact contact = ​new​ Contact()
 
.setId(​"chittrchattr"​)
 
.setImageUrls( ​Collections​.singletonList(
 
PROD_BASE_URL + ​"/static/images/chittrchattr.png"​ ) )
 
.setPriority( 100L )
 
.setAcceptCommands(
 
Collections​.singletonList(​new​ Command().setType(​"TAKE_A_NOTE"​)))
 
.setDisplayName(​"ChittrChattr"​)
 
.setSpeakableName(​"chitter chatter"​);
 
 
mirror.contacts().insert( contact ).execute();

The important thing to see here is the TAKE_A_NOTE value put into acceptCommands. This will let a user add a verbal note to the ChittrChattr contact. However, since all of these commands are verbal, Glass must know how to pronounce ChittrChattr. So we also add a speakableName field in natural English terms: chitter chatter. Without this level of specificity, Glass may have a hard time figuring out how to match what a user says with the contact’s lexically awkward displayName.

Next, add the Subscription-creation code.

chapter-8/src/test/book/glass/auth/OAuth2Servlet.java
 
Subscription subscription = ​new​ Subscription()
 
.setCallbackUrl( PROD_BASE_URL + ​"/postcallback"​ )
 
.setVerifyToken( ​"a_secret_to_everybody"​ )
 
.setUserToken( userId )
 
.setCollection( ​"timeline"​ )
 
.setOperation( ​Collections​.singletonList( ​"UPDATE"​ ) );
 
 
mirror.subscriptions().insert( subscription ).execute();

This directs that timeline insertions trigger a POST with Notification payload to the /postcallback URL, which we’ll create next.

Turning Notifications into Blog Posts

When a user says, “OK, Glass, take a note, ChittrChattr…” anything that follows will be converted into text. That text will then be sent as a payload to a servlet that we’re about a create.

Before we create the servlet, we should take a minor detour. Since we want PostCallbackServlet to create a new Post in the same way that POSTing to the web app’s PostServlet does, let’s create a BlogHelper class that both servlets can call to perform the same createPost action. We’ll dig into the details of this class later. Just know for now that it accepts at minimum a post body and a user, and creates a new blog post under that user’s blog.

Our PostCallbackServlet is a standard HttpServlet that will accept a POST (don’t forget to add the servlet to the web.xml file). Just as we’ve done in previous chapters, we create a notification object from Mirror’s posted JavaScript Object Notation message body.

With our Notification in hand, we can start extracting values and check to ensure that this particular call is meant to be a blog post. First, we check that the call is a LAUNCH user action, which means the user launched the verbal command. If not, we return from the method.

chapter-8/src/test/book/glass/blog/mirror/PostCallbackServlet.java
 
// Get this user action's type
 
UserAction launchAction = null;
 
for​ (UserAction userAction : notification.getUserActions()) {
 
if​( ​"LAUNCH"​.equals( userAction.getType() ) ) {
 
launchAction = userAction;
 
break​;
 
}
 
}
 
// return, because this is the wrong kind of user action
 
if​( launchAction == null ) ​return​;

Next we want to validate that our ChittrChattr is an intended recipient of this verbal message. We do that because there’s no reason why another application couldn’t be the target of a TAKE_A_NOTE action. So we compare all contact recipient IDs to verify that our app’s contact ID (chittrchattr) is in the list.

chapter-8/src/test/book/glass/blog/mirror/PostCallbackServlet.java
 
String​ userId = notification.getUserToken();
 
String​ itemId = notification.getItemId();
 
 
Mirror mirror = MirrorUtils.getMirror( userId );
 
TimelineItem timelineItem = mirror.timeline().get( itemId ).execute();
 
 
// ensure that ChittrChattr is one of this post's intended recipients
 
boolean​ belongsHere = false;
 
for​( Contact contact : timelineItem.getRecipients() ) {
 
if​( ​"chittrchattr"​.equals( contact.getId() ) ) {
 
belongsHere = true;
 
break​;
 
}
 
}
 
// return, because this post wasn't intended for ChittrChattr
 
if​( !belongsHere ) ​return​;

Once we’ve made it through the verification gauntlet, it’s a simple matter of retrieving the given text and posting it to the user’s blog.

chapter-8/src/test/book/glass/blog/mirror/PostCallbackServlet.java
 
String​ body = timelineItem.getText();
 
 
User user = User.get( userId );
 
 
BlogHelper.createPost( null, body, user );

Notifying Followers of New Posts

To wrap this app up, we’re looking to create a timeline item for every follower of any blog that has a new post. This is an inversion of how the web app operates. In the web application, a user loads the /followed web page, which queries for every post on all blogs that the current user follows. In other words, the local web-page user pulls the posts. However, in Glass that behavior is flipped on its head. Whenever a blog has a new post, that post should be pushed to every user that follows the blog.

Let’s circle back around and look at some details of BlogHelper.

First, the createPost method we used in PostCallbackServlet (and the web app code, PostServlet) creates a new post object and stores it with the creating user.

chapter-8/src/test/book/glass/blog/BlogHelper.java
 
public​ ​static​ ​final​ Post createPost( ​String​ title, ​String​ body,
 
User user, Blog blog )
 
throws​ ServletException, IOException
 
{
 
if​( user == null || !user.ownsBlog( blog )) {
 
throw​ ​new​ ServletException(
 
"You must be logged in and own this blog to create a post"​ );
 
}
 
 
Post post = ​new​ Post( blog.getNickname(), title, body, ​new​ ​Date​() );
 
post = post.save();
 
 
pushPost( blog, post );
 
 
return​ post;
 
}

The last action creating a post takes is to push that post to every following user.

chapter-8/src/test/book/glass/blog/BlogHelper.java
 
private​ ​static​ ​void​ pushPost( Blog blog, Post post )
 
throws​ IOException
 
{
 
// find every user that follows that nickname
 
List​<User> users = blog.getFollowers();
 
 
for​ (User user : users) {
 
String​ userId = user.getId();
 
Mirror mirror = MirrorUtils.getMirror( userId );
 
TimelineItem timelineItem = ​new​ TimelineItem()
 
.setText( post.getBody() );
 
mirror.timeline().insert( timelineItem ).execute();
 
}
 
}

For every user that follows, create a new timeline item with the blog post’s body.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.93.245