Cloud printing on the go

Back in April 2010 we announced Google Cloud Print, a service that in Beta allows printing from any app on any device, OS or browser without the need to install any software. Just last month we opened Google Cloud Print to users in the Chrome notebook pilot program. Today we are very pleased to announce the beta launch of Google Cloud Print for mobile documents and Gmail for mobile, which we will be rolling out to users throughout the next few days.

Imagine printing an important document from your smartphone on the way to work and finding the printout waiting for you when you walk in the door. Just open a document in Google Docs or an email in Gmail in your mobile browser and choose “Print” from the dropdown menu in the top right corner. You can also print certain kinds of email attachments (such as .pdf or .doc) by clicking the “Print” link that appears next to them.

This feature will be rolling out today and tomorrow for English speaking users in the US and will work on most phones that support HTML5, such as devices running Android 2.1+ and iOS 3+. To get started, you’ll need to connect your printer to Google Cloud Print. This step requires a Windows PC for now, but Linux and Mac support are coming soon. You can learn more at the Google Cloud Print help center.

Happy printing!

Amping Up Chrome’s Background Feature

Many users rely on apps to provide timely notifications for things like calendar events and incoming chat messages, but find it cumbersome to always keep a Chrome window open. Extensions and packaged apps can already display notifications and maintain state without any visible windows, using background pages. This functionality is now available to hosted apps – the most common form of apps in the Chrome Web Store – via a new background window mechanism.

Apps and extensions that use the new “background” feature can continue to run in the background—even if the user closes down all of Chrome’s windows. “Background apps” will continue to run until Chrome exits. The next time Chrome starts up, any background windows that were previously running will also be re-launched. These windows are not going to be visible but they will be able to perform tasks like checking for server-side changes and pre-emptively loading content into local storage.
One way you can use background windows is to preload content and data so that they are immediately available when the user opens your app. You could also issue HTML5 notifications to alert the user when important events occur—for example, a friend wants to initiate a chat session. There are plenty of possibilities here, and we look forward to seeing what you’ll do.

To protect our users’ privacy, we’ve made this functionality available only to apps and extensions; regular websites will not be able to open background windows. Developers will also need to declare the “background” capability on their apps.

Users can easily see which background apps (and extensions) are running in their system through the “Background Apps” menu of the Chrome icon in the system tray (Windows/Linux) or dock (Mac). Chrome will automatically load background components when the user logs in, and the Chrome icon will remain in the system tray or dock as long as background apps are running- even if all Chrome windows are closed. To close all background components, a user just needs to exit Chrome.

The feature is already available in Chrome’s Dev channel. For details on the API, check out our developer’s guide, which also includes sample apps to try out.

Posted by Andrew Wilson, Software Engineer and Michael Mahemoff, Developer Relations

Pushing Updates with the Channel API

As part of Best Buy’s Connected Store initiative, we have placed QR codes on our product information Fact Tags, in addition to the standard pricing and product descriptions already printed there. When a customer uses the Best Buy app, or any other QR code scanner, they are shown the product details for the product they have scanned, powered by the BBYOpen API or the m.bestbuy.com platform.

To track what stores and products are most popular, QR codes are also encoded with the store number. My project at Best Buy has been to analyze these scans and make new landing pages for QR codes easier to create.

Since we have the geo-location of the stores and product details from our API, it is a natural fit to display these scans on a map. We implemented an initial version of this idea, which used polling to visualize recent scans. To take our this a step further, we thought it would be exciting to use the recently launched App Engine Channel API to update our map in real-time.

Our biggest challenge was pushing the updates to multiple browsers, since we’d most certainly have more than one user at a time looking at our map. The Channel API does not currently support broadcasting a single update to many connected clients. In order to broadcast updates to multiple users, our solution was to keep a list of client IDs and send an update message to each of them.

To implement this, we decided to store the list of active channels in memcache. This solution is not ideal as there are race conditions when we modify the list of client IDs. However, it works well for our demo.

Here’s how we got it working. The code has been slightly simplified for clarity, including removing the rate limiting that we do. To play with a working demo, check out the channel-map-demo project from GitHub.

As customers in our stores scan QR codes, those scans are recorded by enqueuing a deferred. We defer all writes so we can return a response to the client as quickly as possible.

In the deferred, we call a function to push the message to all the active channels (see full source).

def push_to_channels(scan):
    content = '
(...)
' % { 'product_name': scan.product.name, 'timestamp' : scan.timestamp.strftime('%I:%M %p'), 'store_name': scan.store.name, 'state': scan.store.state, 'image': scan.product.image } message = {'lat': scan.store.lat, 'lon': scan.store.lon, 'content': content} channels = simplejson.loads(memcache.get('channels') or '{}') for channel_id in channels.iterkeys(): encoded_message = simplejson.dumps(message) channel.send_message(channel_id, encoded_message)

The message is a JSON data structure containing the latitude and longitude of the store where the scan occurred, plus a snippet of HTML to display in an InfoWindow on the map. The product information (such as name and thumbnail image) comes from our BBYOpen Products API.

Then, when a user opens up the site and requests the map page, we create a channel, add it to the serialized channels Python dictionary, stored in memcache, and pass the token back to the client (see full source).

channel_id = uuid.uuid4().hex
token = channel.create_channel(channel_id)

channels = simplejson.loads(memcache.get('channels') or '{}')

channels[channel_id] = str(datetime.now())

memcache.set('channels', simplejson.dumps(channels))

On the map page, JavaScript creates a Google Maps map and uses the token to open a channel. When the onMessage callback is called by the Channel API, a new InfoWindow is displayed on the map using the HTML content and latitude and longitude in the message (see full source).

function onMessage(message) {
  var scan = JSON.parse(message.data);

  var infoWindow = new google.maps.InfoWindow(
    {content: scan.content,
     disableAutoPan: true,
     position: new google.maps.LatLng(scan.lat, scan.lon)});

  infoWindow.open(map);
  setTimeout(function() { infoWindow.close(); }, 10000);
};

Finally, since channels can only be open for two hours, we have a cron job that runs once an hour to remove old channels. Before deleting the client ID, a message is sent on the channel which triggers code in the JavaScript onMessage function to reload the page, thus giving it a new channel and client ID (see full source).

You can see the end result on our map, watch a video about the BBYScan project or checkout the sample channel-map-demo project and create your own Channel API based application.