Google+ Photos Chrome App


  • Create a photos story for ChromeOS
  • Serve as a test bed for Google+ Photos
  • Push the limits of the Chrome platform
  • Identify and fulfill API gaps

Chrome Principles


The Need for Speed

Challenge: Hashing Images

  • Hash used to prevent uploading a photo more than once
  • App must remain responsive during upload

Solution: Hashing Images

Native Client

Challenge: Efficient Data Store

  • Store records of each data object, e.g., a photo
  • Average user has 4500 photos
    • Extreme users have tens of thousands of photos
  • User actions must complete ASAP

Solution: Efficient Data Store

IndexedDB Transactions

Challenge: 60 Frames Per-Second

  • Scalable smooth scrolling views
    • Equal performance for views with 100 photos and 10000 photos
  • Snappy animations
  • No hiccups or hangs

Solution: 60 Frames Per-Second

Fast Scroll Path

With compositor enabled, the fast scroll path enables the GPU to maintain the rendered view in memory.

  • Scroll the body element
  • Minimize work done in the scroll event
  • Reduce img element loads

Solution: 60 Frames Per-Second

Avoid excessive painting and layouts

Reflows may trigger paints even if the view does not change.

  • requestAnimationFrame
  • Avoid measuring elements and scroll position
    • window.scrollTop
    • element.getClientBoundingRect()

Solution: 60 Frames Per-Second

Contain memory pressure

Garbage collection is an expensive, janky operation.

  • Reduce the number of DOM nodes
  • Identify and fix leaks
  • Agressively detach listeners
  • Profile memory usage via Web Inspector
Making the simple complicated is commonplace; making the complicated simple, awesomely simple, that's creativity.
Charles Mingus
Jazz musician

Challenge: Seamless Sign-in

  • No sign-in, if possible
  • Fast app start-up
  • Avoid account management

Solution: Seamless Sign-in

Identity API

getAuthToken returns the OAuth2 access token of the currently-signed in user.

  function initalizeApp() {
    chrome.experimental.identity.getAuthToken(function(token) {
      app.authToken = token;

  // Request all photos for the user.
  function requestPhotos() {
    var request =;, storePhotos);

Challenge: Effortless Photo Upload

  • Avoid platform UI at all costs
  • Acquire access to the user's most relevant photos
  • Respect the user's privacy

Solution: Effortless Photo Upload

Media Galleries API

chrome.mediaGalleries provides access to the user's galleries on the device.

  • Platform media locations
  • External devices, e.g. SD cards, containing a DCIM directory

Solution: Effortless Photo Upload

Media Galleries API

  function uploadUserMedia() {
    chrome.mediaGalleries.getMediaFileSystems({interactive: no}, function(galleries) {
      for (var i = 0; i < galleries.length; i++) {

  function uploadMediaInFileSystem(fileSystem) {
    // FileSystem manipulation here, e.g., collect FileEntry objects per media
    // file.

Challenge: Optimize for the Pixel Chromebook

  • Magnificently high-resolution display
  • Touch screen

Solution: Optimize for the Pixel Chromebook

Provide high-resolution assets

The Pixel display has a resolution of 239 pixels/inch. Take advantage of this display with gorgeous, high-res media.

  • Warning: Low-res media will be scaled up sub-optimally by the renderer
  • Prepare 1x and 2x assets
.close-button {
  background-image: -webkit-media-set(
    url(resources/1x/close.png) 1x,
    url(resources/2x/close.png) 2x
  background-size: 32px;

Solution: Optimize for the Pixel Chromebook

Increase Accessibility by Adding Touch Support

  • Requires rethinking user interactions in the app
    • Tap-to...?
  • Consider unifying touch and mouse events
    • Touch events are translated as mouse events
    • Confusing UX if different actions produce different results
  • Detecting touch does not imply no mouse device


Challenge: Comply with Platform Security Restrictions

  • Content Security Policy
  • XMLHttpRequest
  • Offline support

Solution: Comply with Platform Security Restrictions

Content Security Policy

CSP is a black/whitelisting mechanism used to restrict access to resources loaded or executed by apps in Chrome.

  • No in-line script
    • <script src=remote>
  • In-line event handlers
  • eval()
  • img element src

Solution: Comply with Platform Security Restrictions


XmlHttpRequest is an API used to send requests to a web server.

  1. Construct request URL
  2. Asynchronously handle response
  3. Save response in the data store
  4. Update the models and refresh the UI

Solution: Comply with Platform Security Restrictions

Resource Compilation

  • Separate behavior (JS) from presentation (HTML)
  • Let tools help enforce this policy
    • Closure
    • jsmin
    • YUI Compressor

Packaged Apps: A Retrospective


Thank You!

Slides at