I’m doing a reddit AMA on Tuesday, September 30th

I'm doing a reddit AMA on Tuesday, September 30th

View

Nikola Tesla Dood

Nikola Tesla Dood

I teamed up with Sarah Donner to create an animated video about Tesla.

View

Allthecooks on Android Wear

By Hoi Lam, Developer Advocate, Android Wear

The best cooking companion since the apron?

Android Wear is designed for serving up useful information at just the right time and in the right place. A neat example of this is Allthecooks Recipes. It gives you the right recipe, right when you need it.

This app is a great illustration of the four creative visions for Android Wear:

  1. Launched automatically
  2. Glanceable
  3. Suggest and demand
  4. Zero or low interaction

Allthecooks also shows what developers can do by combining both the power of the mobile device and the convenience of Android Wear.

Pick the best tool for the job

One particularly well-designed aspect of Allthecooks is their approach to the multi-device experience. Allthecooks lets the user search and browse the different recipes on their Android phone or tablet. When the user is ready, there is a clearly labelled blue action link to send the recipe to the watch.

The integration is natural. Using the on-screen keyboard and the larger screen real estate, Allthecooks is using the best screen to browse through the recipes. On the wearables side, the recipe is synchronised by using the DataApi and is launched automatically, fulfilling one of the key creative visions for Android Wear.

The end result? The mobile / Wear integration is seamless.

Thoughtful navigation

Once the recipe has been sent to the Android Wear device, Allthecooks splits the steps into easily glanceable pages. At the end of that list of steps, it allows the user to jump back to the beginning with a clearly marked button.

This means if you would like to browse through the steps before starting to cook, you can effortlessly get to the beginning again without swiping through all the pages. This is a great example of two other points in the vision: glanceable and zero or low interaction.

A great (cooking) assistant

One of the key ingredients of great cooking is timing, and Allthecooks is always on hand to do all the inputs for you when you are ready to start the clock. A simple tap on the blue “1” and Allthecooks will automatically set the timer to one hour. It is a gentle suggestion that Allthecooks can set the timer for you if you want.

Alternatively, if you want to use your egg timer, why not? It is a small detail but it really demonstrates the last and final element of Android Wear’s vision of suggest and demand. It is an ever ready assistant when the user wants it. At the same time, it is respectful and does not force the user to go down a route that the user does not want.

It’s about the details

Great design is about being user-centric and paying attention to details. Allthecooks could have just shrunk their mobile app for wear. Instead the Allthecooks team put a lot of thoughts into the design and leveraged all four points of the Android Wear creative vision. The end result is that the user can get the best experience out of both their Android mobile device and their Android Wear device. So developers, what will you be cooking next on Android Wear?

For more inspiring Android Wear user experiences, check out the Android Wear collection on Google Play!

Buy a brick for the Nikola Tesla Museum

Buy a brick for the Nikola Tesla Museum

Have your name engraved and placed on the grounds of Nikola Tesla’s laboratory.

View

Strength and determination will lead to a better you

Strength and determination will lead to a better you

View

How little bees take on enormous hornets

How little bees take on enormous hornets

I wrote a comic about Japanese Honeybees and how they combat Japanese Giant Hornets.

View

The Top 3 Google Analytics Configuration Issues Impacting your Data (and How to Fix Them)

Good data is important.  How important?  Studies show that inaccurate data has a direct impact on the bottom line of 88% of companies.  In fact, the average company loses 12% of its revenue due to bad data.  As you know, Google Analytics is a powerful product with a wealth of features to help you optimize your results online. However, to unleash the power of Google Analytics’ marketing tools, you must ensure the data collected is complete and of the highest quality. The insights that fuel action in Analytics depend on good data, especially for some of our advanced algorithmic marketing functionalities like data driven attribution.
Since its release two months ago, our popular new diagnostics tool is working hard to ensure you’re getting the best results. Today, we’d like to share insights into some of the most common account errors along with likely causes and suggested solutions. In particular, we’ll look at some solutions for when our diagnostics tool is telling you the following:  “Bad Default URL,” “Clicks and Sessions Discrepancy,” and “No Goal Conversions.”  Read on to understand the impact of these issues as well as their common causes.

Bad Default URL
“Data without quality is useless.”
João Correia, Analytics Strategist at Blast Analytics & Marketing
When you create a Google Analytics account for website tracking, one of the first questions we ask is for a default URL. This is generally the homepage of your website. Diagnostics ensures that you have tagged your default URL correctly for this property, and warns you if this is not the case. Having a properly tagged website is an essential step towards being able to understand consumer behavior.
This warning is generally caused by either missing or malformed tracking code installed on your default URL, or more simply a typo in the URL that was input. If the default URL is incorrect, simply login to your Google Analytics account, click the “Admin” button in the header, and click “Property Settings” to adjust your default URL. If the tracking code is flawed, you’ll want to talk to your webmaster and ask to have the tracking code correctly installed
Beyond the default URL, we also check for tracking code health across your site. We look for pages that have missing or malformed tags. And we continually run these checks, ensuring new pages you launch in the future also are properly tagged. 
Clicks / Session Discrepancies
“Diagnostics helped me identify and fix an AdWords data discrepancy in my account.  Without the tool, I may have never even realized that my data was inconsistent.  This is a great tool!”
Monika Rut-Koroglu, Digital Analytics and Optimization at FXCM
Google Analytics offers rich capabilities that help users share data with linked AdWords accounts and gain unique and powerful marketing insights. It’s common to expect the number of clicks you see in AdWords to match the number of sessions you see in Analytics; but this is not always the case. This discrepancy can slow down meaningful analysis, and is a situation that can and should be rectified.
The most common causes of this issue have to do with your configuration settings. For example, when you send ad clicks through a third party that redirects to your site; the third party will often times drop vital tagging parameters which are mandatory for Analytics and AdWords to associate clicks and sessions. Other examples are having AdWords auto-tagging disabled, and redirecting users to mobile sites while unintentionally dropping tagging parameters.
Fixes for these issues can vary; we have a detailed guide to walk users through this or you can follow prompts in Google Analytics when we identify specific actions for you to take. If you have a third party who uses redirects and drops parameters, talk to them to resolve the issue. If auto-tagging is disabled on your AdWords accounts, consider enabling it
No Goal Conversions
“[Google Analytics Diagnostics] is a great idea… Just discovered it the other day on my iPad. Helpful to let me redefine my goals better and find out what’s not working.”
Sherri Matthew, Harpist and Small Business Owner
Google Analytics goals offer valuable ways to identify, track, and help you drive more valuable outcomes. Sometimes goals can break, and stop this critical stream of insights from reaching you. We run diagnostic checks to ensure your goals continually identify a steady flow of high value customers, and we warn you if this flow breaks.
The most common cause for goal breakage is when a goal is based on a URL that changes. If your webmaster updates the URLs on your site, and the URLs in the goal settings aren’t updated accordingly, this will cause your goal to stop tracking. The second most common cause for goals breaking is if the event tracking on your site changes and the events listed in the goal aren’t updated accordingly.
If you’ve had a goal break for these reasons, visit the “Admin” section via a link in the header of your Google Analytics account, and click “Goals” to correct your goal configurations.
More About Diagnostics
Google Analytics Diagnostics scans for problems every day (with some exceptions). It inspects your site tagging, account configuration, and reporting data for potential data-quality issues.  Only users with Edit permission can see and respond to diagnostics messages. Diagnostics honors the first response to a message; for example, when a user ignores a message, it is ignored for all users.
The tool currently scans for dozens of issues, and dozens more are planned. Just keep an eye on your account over time – it will notify you if and when new issues or opportunities are detected.

- Frank Kieviet and Matt Matyas, Google Analytics Team

I will climb the highest peak

I will climb the highest peak

View

Enhanced Google Analytics Audience Capabilities Come to Apps

Good news for mobile app developers: Audience Demographics and Interests Reporting and Remarketing are now available for apps in Google Analytics.  Just one of the improvements for audience segmentation and remarketing we’re announcing today, these changes should make it even easier for all our advertisers to reach their high-value customer segments. 
In-App Audience Demographics Reporting and Remarketing
Good analytics are especially important to app developers. At Google I/O, Hovhannes Avoyan, the CEO and Founder of PicsArt , had this to say: 
“We need analytics to help us understand who our users are, how they interact with our application, how our application performs. With all that knowledge, we want to apply different monetization strategies to different kinds of users.” 
Now developers can see just how different user segments engage and monetize with In-App Audience Demographics Reporting
And it’s more than just data. Analysts and developers can blend audience demographic and behavior data into detailed audience lists to be targeted with in app remarketing campaigns. In short, all the great remarketing capabilities for Google Analytics users on the web are now available for apps as well.
New In-App Audience Demographics Reporting
Segmentation and remarketing lists get an upgrade
Creating remarketing lists for apps and web is now even easier with recent upgrades to both segmentation and audience building. A streamlined creation flow for creating audiences allows users to go from segment to audience within clicks (plus a few bonus admin features like list renaming and automatic list sizing).
New Audience Builder Experience, now supporting App lists
If you prefer to stand on the shoulders of remarketing giants, Analytics power users have developed and shared audience definitions that import via template links or from the solutions gallery. This simplifies things dramatically for new users. A process that could be complicated and time-consuming can now be done with 6 clicks in under 1 minute. Give it a try: import our Engagement Pack of Core Remarketing Lists.
On the segmentation side, users have told us they wanted segments to be more discoverable, easier to manage, and more intuitive to build. We’ve been listening, and have made interface improvements, adding a simple “Add Segment” button within reports, a new segment-selection interface, hover-over segment definitions, and a 1-click action dialogue to Share, Edit, Copy, Remove, or Remarket to a segment. 
New Segmentation Experience: fewer errors for better analysis
Measure remarketing performance with the new Display Targeting report
Once you’ve found a segment, created an audience, and activated your remarketing campaign, close the loop by measuring the performance of those audiences across all remarketing campaigns . Enter the new Adwords Display Targeting report in the Acquisition section to see all your active remarketing lists, along with impressions, spend, behavior, and conversion rates under the “Interests and Remarketing” tab.
New Remarketing List Performance in Display Targeting Report
You can learn how to update your SDK to enable these features in our Help Center or get started now by creating some remarketing lists. We hope that these improvements make your audience segmentation and remarketing– in apps and on the web– more intuitive and more effective. We’d love to hear from you! Please leave questions or feedback in the comments, and stay tuned for more audience-related improvements. 

Posted by Dan Stone, Product Manager, and Kanu Singhal, Technical Lead from the Google Analytics Audience Team

Messaging on Android Wear

By Timothy Jordan, Developer Advocate

Sending messages on Android Wear feels as easy as it was to pass notes back in school. Remember when your friends always felt nearby? That feeling is why I love staying in touch with friends and family using my wearable.

Your messaging app likely already works on Android Wear. With just a few more lines of code you can unlock simple but powerful features that let your users communicate even more effortlessly.

Message notifications for free

If your Android app uses notifications to let the user know about new messages, these will work automatically on their wearable. That is, when you build notifications with the NotificationCompat.Builder class, the system takes care of displaying them properly, whether they appear on a handheld or wearable. Also, an “Open on phone” action will be added so it’s easy for the user to reply via the app on their handheld.

Google+ Hangouts message.

Reply like a champ

Messages on Wear get really exciting when you can reply directly from the watch with your voice. In addition to being super convenient, this always gives me a Dick Tracy thrill… but maybe that’s just me. =]

To add this functionality, it’s as simple as adding an action to the notification via WearableExtender that includes a RemoteInput to your notification. After the user replies, you’ll just grab their voice input as a string from the RemoteInput included in the Intent. You can even include text responses the user can easily select from a list by passing an array of them to the setChoices method of the RemoteInput. More details and code can be found here.

WhatsApp message with the reply by voice action.

See who is texting

Messages are more meaningful when you are connected to the sender. That’s why we recommend you include the photo of the sender as the background of the notification. As soon as the user taps into the message, they also see who it’s from, which will make it matter more (or maybe that other thing, depending on who it is).

You should add a photo with a resolution of at least 400×400, but we recommend 640×400. With the larger size, the background will be given parallax scrolling. If the background is to be included in the apk, place it in the res/drawable-nodpi directory. Then call setBackground() on your WearableExtender and add it to your notification. More details and code can be found here.

Path Talk message with a clear picture of the sender.

Custom actions

Basic notifications with reply by voice and a good background image are the most important parts to get done right away. But why stop there? It’s easy to extend the unique parts of your service to the wearable. A simple first step is adding in a custom action the way Omlet does. These are just actions defined with the WearableExtender that raise an intent on the handheld.

Omlet includes two extra actions with every message: Like and Check-In. Check-In sends along the user’s current location.

Custom Layouts

Custom interaction on the wearable, like the following example from TextMe, is straightforward to implement. They have what appears to be a simple notification with an action that allows the user to select an emoticon. However, to show this emoticon picker, they are actually issuing a notification from the wearable. The round trip looks something like this:

  1. The handheld gets a new message, issues a notification setLocalOnly(True), and sends a message to the wearable using the Data Layer API
  2. The wearable receives that message using the WearableListenerService and issues a custom notification with a PendingIntent to launch an activity when the user views the notification
  3. That activity has a custom layout defined with the Wearable UI Library
  4. Once the user selects an emoticon, the wearable sends a message back to the handheld
  5. The handheld receives that message and sends it along to the server

Custom layouts are documented in more depth here.

TextMe allows users to reply with a quick emoticon.

Next steps

Make your messaging service awesome by providing rich functionality on the user’s wearable. It’s easy to get started and easy to go further. It all starts at developer.android.com/wear.

Google Play Services 6.1

gps

Today, we’re excited to introduce the latest version of Google Play services to help you easily build on the newest features from Google and optimize your apps.

Google Play services 6.1 adds Enhanced Ecommerce analytics support from Google Tag Manager and offers new improvements to the Google Drive Android API. With the latest release, we’re also including a refresh of the Google Fit developer preview, so that you can test your fitness apps on any Android device.

Analytics

Launched in Google Play services 5.0, Enhanced Ecommerce is an analytics extension designed to provide richer insights into pre-purchase shopping behavior and into product performance. It’s a great way to gain visibility into the full customer journey, helping you understand how different user acquisition campaigns are performing at a granular level. By including support for Enhanced Ecommerce in Google Tag Manager with the latest release of Google Play services, we are supercharging your ability to regularly update and manage tags on mobile apps more easily, so that you can consistently measure product impressions, shopping funnel events, and more.

Drive

To make it easier to use Drive, we added enhancements to the Google Drive Android API. With the new Completion Events feature, you can see when actions are committed to the server and improve the response time to conflicts. Material design elements have been incorporated into the File Picker UI, along with the addition of Recent and Starred views. A new setParents() method enables you to organize files and folders, while the previous Contents class has been replaced with a simpler DriveContents class.

Google Fit

Initially introduced in August, the Google Fit Developer Preview has been refreshed to enable you to test your new fitness apps on any Android device. We expect to make additional changes to the APIs, so please check back with us on new developments.

Stay tuned!

We will be rolling out Google Play services 6.1 over the next few days, after which we will publish the documentation and make the SDK available.

To learn more about Google Play services and the APIs available to you through it, visit the Google Services section on the Android Developers site.

on September 16, 2014, 1:35 pm, by Android Developers, under From Around the Web.

Posted by Rich Hyndman, Developer Advocate

With the launch of Android One, more people across the world will have access to high-quality and affordable smartphones, packed with plenty of processing power and running the latest version of Android. These devices are available now in India and soon in Indonesia, the Philippines, and South Asia, so now is a good time to make sure your apps are ready for these new markets. This post highlights a few areas to consider.

These days, we often talk about smooth, 60fps transitions and keeping apps jank-free, and rightly so — performance is a critical metric for app quality. But in the user experience hierarchy of needs, an app should first and foremost do its job reliably and consistently.

If your app has search functionality, will user requests time out entirely? Do you think it is more important that a result is returned in a timely manner, or that the result is returned at all? If you’re trying to build a robust app to reach the next five billion, it might be less about returning a result immediately, and more about returning a result at all. To address this challenge, why not include an option to users to “notify me with the results” when a search query is running on a slow network? Your app can then take as long as it needs to successfully retrieve the data in the background and show a notification when complete. The difference in user experience between an app that times out on a slower network and one that caters to user-specific needs will be very impactful for driving mobile app adoption.

There are also ways to test app performance without flying around the globe. The Android Emulator has network speed and network delay emulation settings, which can become an integral part of your testing strategy. If you’re testing on physical hardware, try turning off WiFi and switching the network to 2G only; how well does your app perform? Do search pages load? Does data refresh? These issues can often be fixed with relatively minor changes to your app logic or by leveraging a SyncAdapter. Check out our blog post on sync in the Google I/O app for more ideas.


Another key area for you to be aware of is app memory utilization. As part of the KitKat launch, we added new tools to the SDK for analyzing memory use and new APIs like isLowRamDevice(). We also just added a Memory Monitor to Android Studio 0.8.10 (currently in Canary). Much of this is documented in our Best Practices for Performance guide.

Moving forward, the Android L release has a strong focus on battery usage and analysis. Project Volta introduces new tools, such as Battery Historian and new APIs like JobScheduler, that can really help optimize battery use of your app.

By ensuring your app works well on slower networks, uses minimal memory, minimizes battery usage and doesn’t have a larger-than-necessary APK, you will help the next five billion discover, use and love your app.

New Benchmarking Reports Help Twiddy Boost Email Open Rates by 500%

If you’ve ever wondered how your website is performing compared to the competition, our new Benchmarking reports in Google Analytics will help you find out.
Analytics users can now compare their results to peers in their industry, choosing from 1600 industry categories, 1250 markets and 7 size buckets. Benchmarking leverages the footprint of Google Analytics and can help you set meaningful targets, spot trends occurring across industries and answer a whole array of questions: Which channels should you be investing more in? How does your mobile engagement compare to your peers? How unique is your audience?
The new Benchmarking reports display acquisition and engagement metrics — like sessions and bounce rate — by Channel, Location, or Device Category dimensions. To ensure total data transparency, the number of properties contributing to the benchmark is displayed once you choose the industry, market and size. A helpful heat map feature makes it easy to see areas of strength and opportunity, and where to devote more resources.
Benchmarking in Action: Twiddy Finds a New Email Marketing Opportunity
Twiddy.com, a vacation rentals company in the Outer Banks– a popular summer getaway destination– has been using Benchmarking reports to help focus its marketing resources. A look at their peer benchmarks by channel showed that Twiddy was doing many things well during its peak summer booking season. Still, “it was clear we were missing a huge opportunity in email marketing,” reports CMO Ross Twiddy. His team used Google Analytics data to revamp their email marketing and improve the flow and process.
Email opportunity: Visitors from email spend nearly twice as long on site as the average, but user sessions generated from email are 82% below average and new users from the channel fall 91% below similar sites.

Twiddy even used Google Analytics to choose the best-selling messages for their email campaigns. Their analysis helped them zero in on the factors that were most consistent in repeat bookings: the price range, location, rental type, and even vacation week that would be most likely to convert with for each customer. “We launched an email last week based on our findings, and it shattered our email marketing records: a 48% average open rate and a 40% clickthrough rate,” says Ross.
Twiddy is happy with the new visibility they’ve gained: “The Benchmarking reports were powerful enough for us to reallocate time, budget and resources towards running down the deficiency. We can’t wait to start testing the reports out more broadly during the next peak booking season.”
Get Started with Benchmarking
Benchmarking reports can be found in the “Audience” section of the reporting interface and are rolling out over the next few weeks to all Google Analytics users who have opted in to share their data anonymously. If you want to join in, simply check the “Share anonymously with Google and others” box in the Account Settings tab of your account admin page. This is only the beginning for benchmarking within Google Analytics. We’ll be expanding these capabilities in the coming months, both incorporating conversion metrics and adding support for mobile apps. For more information on Benchmarking reports, check out our Help Center.

Posted by: Nikhil Roy, Product Manager, Google Analytics

New Benchmarking Reports Help Twiddy Boost Email Open Rates by 500%

If you’ve ever wondered how your website is performing compared to the competition, our new Benchmarking reports in Google Analytics will help you find out.
Analytics users can now compare their results to peers in their industry, choosing from 1600 industry categories, 1250 markets and 7 size buckets. Benchmarking leverages the footprint of Google Analytics and can help you set meaningful targets, spot trends occurring across industries and answer a whole array of questions: Which channels should you be investing more in? How does your mobile engagement compare to your peers? How unique is your audience?
The new Benchmarking reports display acquisition and engagement metrics — like sessions and bounce rate — by Channel, Location, or Device Category dimensions. To ensure total data transparency, the number of properties contributing to the benchmark is displayed once you choose the industry, market and size. A helpful heat map feature makes it easy to see areas of strength and opportunity, and where to devote more resources.
Benchmarking in Action: Twiddy Finds a New Email Marketing Opportunity
Twiddy.com, a vacation rentals company in the Outer Banks– a popular summer getaway destination– has been using Benchmarking reports to help focus its marketing resources. A look at their peer benchmarks by channel showed that Twiddy was doing many things well during its peak summer booking season. Still, “it was clear we were missing a huge opportunity in email marketing,” reports CMO Ross Twiddy. His team used Google Analytics data to revamp their email marketing and improve the flow and process.
Email opportunity: Visitors from email spend nearly twice as long on site as the average, but user sessions generated from email are 82% below average and new users from the channel fall 91% below similar sites.

Twiddy even used Google Analytics to choose the best-selling messages for their email campaigns. Their analysis helped them zero in on the factors that were most consistent in repeat bookings: the price range, location, rental type, and even vacation week that would be most likely to convert with for each customer. “We launched an email last week based on our findings, and it shattered our email marketing records: a 48% average open rate and a 40% clickthrough rate,” says Ross.
Twiddy is happy with the new visibility they’ve gained: “The Benchmarking reports were powerful enough for us to reallocate time, budget and resources towards running down the deficiency. We can’t wait to start testing the reports out more broadly during the next peak booking season.”
Get Started with Benchmarking
Benchmarking reports can be found in the “Audience” section of the reporting interface and are rolling out over the next few weeks to all Google Analytics users who have opted in to share their data anonymously. If you want to join in, simply check the “Share anonymously with Google and others” box in the Account Settings tab of your account admin page. This is only the beginning for benchmarking within Google Analytics. We’ll be expanding these capabilities in the coming months, both incorporating conversion metrics and adding support for mobile apps. For more information on Benchmarking reports, check out our Help Center.

Posted by: Nikhil Roy, Product Manager, Google Analytics

Conference Data Sync and GCM in the Google I/O App

By Bruno Oliveira, tech lead of the 2014 Google I/O mobile app

Keeping data in sync with the cloud is an important part of many applications, and the Google I/O App is no exception. To do this, we leverage the standard Android mechanism for this purpose: a Sync Adapter. Using a Sync Adapter has many benefits over using a more rudimentary mechanism such as setting up recurring alarms, because the system automatically handles the scheduling of Sync Adapters to optimize battery life.

We store the data in a local SQLite database. However, rather than having the whole application access that database directly, the application employs another standard Android mechanism to control and organize access to that data. This structure is, naturally, a Content Provider. Only the content provider’s implementation has direct access to the SQLite database. All other parts of the app can only access data through the Content Resolver. This allows for a very flexible decoupling between the representation of the data in the database and the more abstract view of that data that is used throughout the app.

The I/O app maintains with two main kinds of data: conference data (sessions, speakers, rooms, etc) and user data (the user’s personalized schedule). Conference data is kept up to date with a one-way sync from a set of JSON files stored in Google Cloud Storage, whereas user data goes through a two-way sync with a file stored in the user’s Google Drive AppData folder.

Downloading Conference Data Efficiently

For a conference like Google I/O, conference data can be somewhat large. It consists of information about all the sessions, rooms, speakers, map locations, social hashtags, video library items and others. Downloading the whole data set repeatedly would be wasteful both in terms of battery and bandwidth, so we adopt a strategy to minimize the amount of data we download and process.

This strategy is separating the data into several different JSON files, and having them be referenced by a central master JSON file called the manifest file. The URL of the manifest file is the only URL that is hard-coded into the app (it is defined by the MANIFEST_URL constant in Config.java). Note that the I/O app uses Google Cloud Storage to store and serve these files, but any robust hosting service accessible via HTTP can be used for the same purpose.

The first part of the sync process is checking if the manifest file was changed since the app last downloaded it, and processing it only if it’s newer. This logic is implemented by the fetchConfenceDataIfNewer method in RemoteConferenceDataFetcher.

public class RemoteConferenceDataFetcher {
    // (...)
    public String[] fetchConferenceDataIfNewer(String refTimestamp) throws IOException {
        BasicHttpClient httpClient = new BasicHttpClient();
        httpClient.setRequestLogger(mQuietLogger);
        // (...)

        // Only download if data is newer than refTimestamp
        if (!TextUtils.isEmpty(refTimestamp) && TimeUtils
            .isValidFormatForIfModifiedSinceHeader(refTimestamp)) {
                httpClient.addHeader("If-Modified-Since", refTimestamp);
            }
        }

        HttpResponse response = httpClient.get(mManifestUrl, null);
        int status = response.getStatus();
        if (status == HttpURLConnection.HTTP_OK) {
            // Data modified since we last checked -- process it!
        } else if (status == HttpURLConnection.HTTP_NOT_MODIFIED) {
            // data on the server is not newer than our data - no work to do!
            return null;
        } else {
            // (handle error)
        }
    }
    // (...)
}

Notice that we submit the HTTP If-Modified-Since header with our request, so that if the manifest hasn’t changed since we last checked it, we will get an HTTP response code of HTTP_NOT_MODIFIED rather than HTTP_OK, we will react by skipping the download and parsing process. This means that unless the manifest has changed since we last saw it, the sync process is very economical: it consists only of a single HTTP request and a short response.

The manifest file’s format is straightforward: it consists of references to other JSON files that contain the relevant pieces of the conference data:

{
  "format": "iosched-json-v1",
  "data_files": [
    "past_io_videolibrary_v5.json",
    "experts_v11.json",
    "hashtags_v8.json",
    "blocks_v10.json",
    "map_v11.json",
    "keynote_v10.json",
    "partners_v2.json",
    "session_data_v2.681.json"
  ]
}

The sync process then proceeds to process each of the listed data files in order. This part is also implemented to be as economical as possible: if we detect that we already have a cached version of a specific data file, we skip it entirely and use our local cache instead. This task is done by the processManifest method.

Then, each JSON file is parsed and the entities present in each one are accumulated in memory. At the end of this process, the data is written to the Content Provider.

Issuing Content Provider Operations Efficiently

The conference data sync needs to be efficient not only in the amount of data it downloads, but also in the amount of operations it performs on the database. This must be done as economically as possible, so this step is also optimized: instead of overwriting the whole database with the new data, the Sync Adapter attempts to preserve the existing entities and only update the ones that have changed. In our tests, this optimization step reduced the total sync time from 16 seconds to around 2 seconds on our test devices.

In order to accomplish this important third layer of optimization, the application needs to know, given an entity in memory and its version in the Content Provider, whether or not we need to issue content provider operations to update that entity. Comparing the entity in memory to the entity in the database field by field is one option, but is cumbersome and slow, since it would require us to read every field. Instead, we add a field to each entity called the import hashcode. The import hashcode is a weak hash value generated from its data. For example, here is how the import hashcode for a speaker is computed:

public class Speaker {
    public String id;
    public String publicPlusId;
    public String bio;
    public String name;
    public String company;
    public String plusoneUrl;
    public String thumbnailUrl;

    public String getImportHashcode() {
        StringBuilder sb = new StringBuilder();
        sb.append("id").append(id == null ? "" : id)
                .append("publicPlusId")
                .append(publicPlusId == null ? "" : publicPlusId)
                .append("bio")
                .append(bio == null ? "" : bio)
                .append("name")
                .append(name == null ? "" : name)
                .append("company")
                .append(company== null ? "" : company)
                .append("plusoneUrl")
                .append(plusoneUrl == null ? "" : plusoneUrl)
                .append("thumbnailUrl")
                .append(thumbnailUrl == null ? "" : thumbnailUrl);
        String result = sb.toString();
        return String.format(Locale.US, "%08x%08x", 
            result.hashCode(), result.length());
    }
}

Every time an entity is updated in the database, its import hashcode is saved with it as a database column. Later, when we have a candidate for an updated version of that entity, all we need to do is compute the import hashcode of the candidate and compare it to the import hashcode of the entity in the database. If they differ, then we issue Content Provider operations to update the entity in the database. If they are the same, we skip that entity. This incremental update logic can be seen, for example, in the makeContentProviderOperations method of the SpeakersHandler class:

public class SpeakersHandler extends JSONHandler {
    private HashMap mSpeakers = new HashMap();

    // (...)
    @Override
    public void makeContentProviderOperations(ArrayList list) {
        // (...)
        int updatedSpeakers = 0;
        for (Speaker speaker : mSpeakers.values()) {
            String hashCode = speaker.getImportHashcode();
            speakersToKeep.add(speaker.id);

            if (!isIncrementalUpdate || !speakerHashcodes.containsKey(speaker.id) ||
                    !speakerHashcodes.get(speaker.id).equals(hashCode)) {
                // speaker is new/updated, so issue content provider operations
                ++updatedSpeakers;
                boolean isNew = !isIncrementalUpdate || 
                    !speakerHashcodes.containsKey(speaker.id);
                buildSpeaker(isNew, speaker, list);
            }
        }

        // delete obsolete speakers
        int deletedSpeakers = 0;
        if (isIncrementalUpdate) {
            for (String speakerId : speakerHashcodes.keySet()) {
                if (!speakersToKeep.contains(speakerId)) {
                    buildDeleteOperation(speakerId, list);
                    ++deletedSpeakers;
                }
            }
        }
    }
}

The buildSpeaker and buildDeleteOperation methods (omitted here for brevity) simply build the Content Provider operations necessary to, respectively, insert/update a speaker or delete a speaker from the Content Provider. Notice that this approach means we only issue Content Provider operations to update a speaker if the import hashcode has changed. We also deal with obsolete speakers, that is, speakers that were in the database but were not referenced by the incoming data, and we issue delete operations for those speakers.

Making Sync Robust

The sync adapter in the I/O app is responsible for several tasks, amongst which are the remote conference data sync, the user schedule sync and also the user feedback sync. Failures can happen in any of them because of network conditions and other factors. However, a failure in one of the tasks should not impact the execution of the other tasks. This is why we structure the sync process as a series of independent tasks, each protected by a try/catch block, as can be seen in the performSync method of the SyncHelper class:

// remote sync consists of these operations, which we try one by one (and
// tolerate individual failures on each)
final int OP_REMOTE_SYNC = 0;
final int OP_USER_SCHEDULE_SYNC = 1;
final int OP_USER_FEEDBACK_SYNC = 2;

int[] opsToPerform = userDataOnly ?
        new int[] { OP_USER_SCHEDULE_SYNC } :
        new int[] { OP_REMOTE_SYNC, OP_USER_SCHEDULE_SYNC, OP_USER_FEEDBACK_SYNC};

for (int op : opsToPerform) {
    try {
        switch (op) {
            case OP_REMOTE_SYNC:
                dataChanged |= doRemoteSync();
                break;
            case OP_USER_SCHEDULE_SYNC:
                dataChanged |= doUserScheduleSync(account.name);
                break;
            case OP_USER_FEEDBACK_SYNC:
                doUserFeedbackSync();
                break;
        }
    } catch (AuthException ex) {
        // (... handle auth error...)
    } catch (Throwable throwable) {
        // (... handle other error...)

        // Let system know an exception happened:
        if (syncResult != null && syncResult.stats != null) {
            ++syncResult.stats.numIoExceptions;
        }
    }
}

When one particular part of the sync process fails, we let the system know about it by increasing syncResult.stats.numIoExceptions. This will cause the system to retry the sync at a later time, using exponential backoff.

When Should We Sync? Enter GCM.

It’s very important for users to be able to get updates about conference data in a timely manner, especially during (and in the few days leading up to) Google I/O. A naïve way to solve this problem is simply making the app poll the server repeatedly for updates. Naturally, this causes problems with bandwidth and battery consumption.

To solve this problem in a more elegant way, we use GCM (Google Cloud Messaging). Whenever there is an update to the data on the server side, the server sends a GCM message to all registered devices. Upon receipt of this GCM message, the device performs a sync to download the new conference data. The GCMIntentService class handles the incoming GCM messages:

Update (23 September 2014): Since this blog post was first published, the GCMBaseIntentService class has been deprecated. Please use the GoogleCloudMessaging API instead.

public class GCMIntentService extends GCMBaseIntentService {
    private static final String TAG = makeLogTag("GCM");

    private static final Map MESSAGE_RECEIVERS;
    static {
        // Known messages and their GCM message receivers
        Map  receivers = new HashMap();
        receivers.put("test", new TestCommand());
        receivers.put("announcement", new AnnouncementCommand());
        receivers.put("sync_schedule", new SyncCommand());
        receivers.put("sync_user", new SyncUserCommand());
        receivers.put("notification", new NotificationCommand());
        MESSAGE_RECEIVERS = Collections.unmodifiableMap(receivers);
    }

    // (...)

    @Override
    protected void onMessage(Context context, Intent intent) {
        String action = intent.getStringExtra("action");
        String extraData = intent.getStringExtra("extraData");
        LOGD(TAG, "Got GCM message, action=" + action + ", extraData=" + extraData);

        if (action == null) {
            LOGE(TAG, "Message received without command action");
            return;
        }

        action = action.toLowerCase();
        GCMCommand command = MESSAGE_RECEIVERS.get(action);
        if (command == null) {
            LOGE(TAG, "Unknown command received: " + action);
        } else {
            command.execute(this, action, extraData);
        }

    }
    // (...)
}

Notice that the onMessage method delivers the message to the appropriate handler depending on the GCM message’s “action” field. If the action field is “sync_schedule”, the application delivers the message to an instance of the SyncCommand class, which causes a sync to happen. Incidentally, notice that the implementation of the SyncCommand class allows the GCM message to specify a jitter parameter, which causes it to trigger a sync not immediately but at a random time in the future within the jitter interval. This spreads out the syncs evenly over a period of time rather than forcing all clients to sync simultaneously, and thus prevents a sudden peak in requests on the server side.

Syncing User Data

The I/O app allows the user to build their own personalized schedule by choosing which sessions they are interested in attending. This data must be shared across the user’s Android devices, and also between the I/O website and Android. This means this data has to be stored in the cloud, in the user’s Google account. We chose to use the Google Drive AppData folder for this task.

User data is synced to Google Drive by the doUserScheduleSync method of the SyncHelper class. If you dive into the source code, you will notice that this method essentially accesses the Google Drive AppData folder through the Google Drive HTTP API, then reconciles the set of sessions in the data with the set of sessions starred by the user on the device, and issues the necessary modifications to the cloud if there are locally updated sessions.

This means that if the user selects one session on their Android device and then selects another session on the I/O website, the result should be that both the Android device and the I/O website will show that both sessions are in the user’s schedule.

Also, whenever the user adds or removes a session on the I/O website, the data on all their Android devices should be updated, and vice versa. To accomplish that, the I/O website sends our GCM server a notification every time the user makes a change to their schedule; the GCM server, in turn, sends a GCM message to all the devices owned by that user in order to cause them to sync their user data. The same mechanism works across the user’s devices as well: when one device updates the data, it issues a GCM message to all other devices.

Conclusion

Serving fresh data is a key component of many Android apps. This article showed how the I/O app deals with the challenges of keeping the data up-to-date while minimizing network traffic and database changes, and also keeping this data in sync across different platforms and devices through the use of Google Cloud Storage, Google Drive and Google Cloud Messaging.

The Beautiful Design Summer 2014 Collection on Google Play

Posted by Marco Paglia, Android Design Team

It’s that time again! Last summer, we published the first Beautiful Design collection on Google Play, and updated it in the winter with a fresh set of beautifully crafted apps.

Since then, developers have been hard at work updating their existing apps with new design ideas, and many new apps targeted to phones and tablets have launched on Google Play sporting exquisite detail in their UIs. Some apps are even starting to incorporate elements from material design, which is great to see. We’re on the lookout for even more material design concepts applied across the Google Play ecosystem!

Today, we’re refreshing the Beautiful Design collection with our latest favorite specimens of delightful design from Google Play. As a reminder, the goal of this collection is to highlight beautiful apps with masterfully crafted design details such as beautiful presentation of photos, crisp and meaningful layout and typography, and delightful yet intuitive gestures and transitions.

The newly updated Beautiful Design Summer 2014 collection includes:

Flight Track 5, whose gorgeously detailed flight info, full of maps and interactive charts, stylishly keeps you in the know.

Oyster, a book-reading app whose clean, focused reading experience and delightful discovery makes it a joy to take your library with you, wherever you go.

Gogobot, an app whose bright colors and big images make exploring your next city delightful and fun.

Lumosity,
Vivino,
FIFA,
Duolingo,
SeriesGuide,
Spotify,
Runtastic,
Yahoo News Digest… each with delightful design details.

Airbnb, a veteran of the collection from this past winter, remains as they continue to finesse their app.

If you’re an Android designer or developer, make sure to play with some of these apps to get a sense for the types of design details that can separate good apps from great ones. And remember to review the material design spec for ideas on how to design your next beautiful Android app!.

I drew Spider-Man like the new Spider-Woman (NSFW)

I drew Spider-Man like the new Spider-Woman (NSFW)

View

Powerful New Messaging Features with GCM

By Subir Jhanb, Google Cloud Messaging team

Developers from all segments are increasingly relying on Google Cloud Messaging (GCM) to handle their messaging needs and make sure that their apps stay battery-friendly. GCM has been experiencing incredible momentum, with more than 100,000 apps registered, 700,000 QPS, and 300% QPS growth over the past year.

At Google I/O we announced the general availability of several GCM capabilities, including the GCM Cloud Connection Server, User Notifications, and a new API called Delivery Receipt. This post highlights the new features and how you can use them in your apps. You can watch these and other GCM announcements at our I/O presentation.

Two-way XMPP messaging with Cloud Connection Server

XMPP-based Cloud Connection Server (CCS) provides a persistent, asynchronous, bidirectional connection to Google servers. You can use the connection to send and receive messages between your server and your users’ GCM-connected devices. Apps can now send upstream messages using CCS, without needing to manage network connections. This helps keep battery and data usage to a minimum. You can establish up to 100 XMPP connections and have up to 100 outstanding messages per connection. CCS is available for both Android and Chrome.

User notifications managed across multiple devices

Nowadays users have multiple devices and hence receive notifications multiple times. This can reduce notifications from being a useful feature to being an annoyance. Thankfully, the GCM User Notifications API provides a convenient way to reach all devices for a user and help you synchronise notifications including dismissals – when the user dismisses a notification on one device, the notification disappears automatically from all the other devices. User Notifications is available on both HTTP and XMPP.

Insight into message status through delivery receipts

When sending messages to a device, a common request from developers is to get more insight on the state of the message and to know if it was delivered. This is now available using CCS with the new Delivery Receipt API. A receipt is sent as soon as the message is sent to the endpoint, and you can also use upstream for app level delivery receipt.

How to get started

If you’re already using GCM, you can take advantage of these new features right away. If you haven’t used GCM yet, you’ll be surprised at how easy it is to set up — get started today! And remember, GCM is completely free no matter how big your messaging needs are.

To learn more about GCM and its new features — CCS, user notifications, and Delivery Receipt — take a look at the I/O Bytes video below and read our developer documentation.

Why haven’t you had kids yet?

Why haven't you had kids yet?

View

Tuesday night doodle.

Tuesday night doodle.

View