Wednesday, July 28, 2010

How to Display the Android Status Bar in Full Screen Apps

Uninstall them. It's the only way they'll learn.

Of course to be constructive, you should also leave a comment that explains how much you dislike it when an app presumes to be the most important thing on your phone.

Let's talk about user experience best practices

If my talk on Best Practices at Google I/O and Roman's OSCON session on Android UI design tips weren't enough of a hint, let me spell it out - improving the user experience of Android Apps is a big priority for many of us in Android Developer Relations.

I've already talked about the use of exit buttons, and the next time the fires of hate are stoked to a white heat I'll harness the power of my fury to tell you how I feel about modal loading dialogs and splash screens.

Do not presume to know how I use my phone

One of the deadly sins from my I/O session was hostility. A hostile app is one that tries to force me to change how I use my device.  I use the status bar a lot, so hiding it instantly gets my hackles up. I use the status bar to:
  • Switch between apps. If I had to choose between the app launcher and the status bar, I'd choose the status bar. It's how I switch to most apps.
  • Determine connectivity. I live in London, commute on the underground, and most apps are Internet connected. This is a tricky combination. Knowing if (and how) I'm connected to the Internet affects what apps I use and how I use them.
  • Tell the time. Ok, so I also wear a watch - but if I'm already looking at my phone why make we look away to my wrist?
  • Be event driven. I treat incoming messages (email, SMS, Twitter) as hardware interrupts. Any app that hides that from me is going to have a short lifespan on my phone.
  • Listen to music. Good music apps have an ongoing notification that can be used to control playback.
Every pixels of screen real-estate on a 3.5" display is valuable, so I understand the temptation to reclaim each and every one for your user interface. Doing so, however, can be incredibly hostile.

Some excellent exceptions

Now before you start flaming me in the comments, I'd like to point out that there's a good reason the ability to hide the status bar exists. Hiding the status bar is vital if you want to allow your users to be fully immersed in your app.

But what's immersive enough? Consider going fullscreen to be equivalent to disabling incoming calls.

In the following examples going full screen is not only acceptable - it's preferable (if not necessary):
  • Immersive games. Games into which you place yourself (particular 1st person racers or shooters) are a great example.
  • eLearning. The brain is a machine with limited short term memory. Studies have shown that successful learning requires focus, so notifications and alerts will actively prevent you from learning effectively.
  • Watching Video. A full audio / visual experience. 
The following examples fail this test:
  • Casual games. Casual games are designed to require minimal concentration and are often used while waiting for something else to happen. Interruptions, while not welcome, are inevitable.
  • Just about every other app. I've seen List View apps that go full screen, apps that switch to full screen view only for the settings screens, and full screen splash screens. Please. Just. Stop.
In most cases it seems the developers figured "why not?"

If you're changing default behavour, the question should always be "why?".

A good app has as little friction as possible - it quickly becomes a part of your phone that you'd miss if it were gone. The easiest way to reduce that friction is to behave in a manner consistent with other apps, and complimentary to existing user habits.

Tuesday, July 20, 2010

Mobile App Analytics (or how I stopped guessing and started measuring)

The only things as important as figuring out your app's user journey and the resulting user experience are prioritizing the list of features and deciding where best to allocate your development resources. Unfortunately, it's hard to get this right the first time as the judgements are subjective and based on how you think users will use your app.

Listen to your customers

There are many ways to get feedback from app users.  Most telling (though least instructive) are your active installs - people seldom uninstall apps they use and like. This is supported by Market feedback ("Earthquake!" has over 1600 comments and 1700 ratings to go with regular emails sent to the support address published in the market).

This feedback is invaluable but, as Chris Pruett noted when reviewing feedback for the excellent "Replica Island", user feedback can be unreliable.

Mobile app analytics packages like Google Analytics for Mobile Applications or Flurry let you measure how users actually use your app to help you make objective decisions on where to focus your attention.

I recently added Google Analytics for Mobile Applications to Earthquake

It's a fairly simple process consisting of adding a dummy site to my analytics account (from which to obtain a tracking ID), downloading the Analytics JAR file, sticking it into my project's /lib folder and adding it to the build path (full instructions here).

Within my app I simply get an instance of the tracker:

myTracker = GoogleAnalyticsTracker.getInstance();

Start tracking:

tracker.start("UA-MY_CODE-XX", this);

And add a page hit for every event I wish to track:

EApplication.getInstance().getTracker().trackPageView("/map_view");

All the hits are stored in an SQL database, so you can batch the updates and dispatch them the next time your app accesses the Internet. I do it every time I update the earthquake feed:

EApplication.getInstance().getTracker().dispatch();

The page names you're tracking are totally arbitrary - letting you create a new page for every action you want to track.

This is relevant to my interests

There are three general categories of data I can analyze:
  • User demographics. I can track the geographic locations (and language settings) of my users and the speed of their connections. I can also track their screen resolutions and if they're viewing the app in landscape or portrait modes.
  • App usage patterns. The real value comes from finding out how people used the app. What options did they enable? Which Activities do they spend most time on? Which menu options were selected? Did anyone long press anything? Did they add the widget? In short: How does their usage confirm or contradict the assumptions I made in the design?
  • Exception tracking. I also tracked every caught exception. Now I can find out which unexpected edge cases are occurring regularly, and try to figure out why.
My Findings
  • My users are based predominantly in coastal areas near fault-lines. Los Angeles, San Francisco account for nearly 25% of my active user-base (with LA nearly half of that).
  • English accounts for 85% of my user-base. Followed by German, Japanese, and Spanish.
  • Less than 2% of my users have small screens.
  • The Map View is only marginally more popular than the List View (52% vs 48%).
  • Less than 10% of my users view the app in landscape mode.
  • 4% of users switch the map type. Of those, the average is to switch it twice - suggesting my default selection is the preferred viewing mode.
  • 4% of users center the map to their current position. Very few people do it more than once.
  • Of the users who have long-pressed an earthquake in the List View, almost none do it more than once.
  • 7% of users install the widget.
  • 0.1% of users use the Live Folder.
  • The average number of refreshes is one every 3hrs. The default is once per hour.
  • 10% of users manually refresh the earthquake list, but most do so only once.
  • The app is throwing exceptions when parsing the incoming earthquake feed for 20% of users. Those users are seeing an average of 6 exceptions daily each (approximately equal to the typical number of daily refreshes). There doesn't appear to be a connection between these failures and the user's country, network, or device (pivoting on the error page against these categories reveals similar proportions to overall users). 
My new priorities
  • I need to track down the cause of those exceptions!
  • It's probably not worth creating an optimized display specifically for small screens or landscape viewing.
  • I should consider advertising the Widget within the app.
  • If I choose to localize I should prioritize German, Japanese, and Spanish.
  • Both List View and Map View seem equally popular - this is counter to an assumption I made on likely user preference.
  • Most users are refreshing less often than the default, and very few people are regularly manually refreshing. Without a distribution, the average isn't particularly helpful in figuring out if the options need changing.
  • The menu options aren't being used. Perhaps I should try moving the most popular one to the main UI to see if discoverability is affecting use.
Conclusions

In truth I've probably performed this analysis a little early. To do a more thorough study it would be smart to collect a couple of weeks of data.

I'm now all set to perform A/B testing on future releases. By tracking a unique version number page within each release I can use Analytics' pivot functionality to track changes in behavior, demographics, and exceptions based on the changes I make for each release.

I also discovered some gaps in my tracking that need to be added to the next release: 
  • How many people click an earthquake to view it on the map.
  • Exactly which exceptions are being triggered in the parsing routine.
  • I need to add extra tracking to figure out the distribution of update frequencies.

Wednesday, July 07, 2010

Android App Surgery: "Earthquake!"

This week, rather than put someone else under the microscope, I'm going to do an Android App Surgery on one of my own apps: Earthquake!

I hope you'll excuse the indulgence, the distinct advantage of  reviewing my own application is that I can find and point out some of the things I should be doing differently that are harder to spot without access to the code.

In an effort to see if I practice what I preach, I'll evaluate my own app according to the criteria I set out in my Google I/O presentation on Android best practices.

The App: Earthquake!

Earthquake is a reference app that uses the USGS 24hr earthquake feed to keep users informed of recent earthquakes.

Like most apps based on a data feed, the UI is centered around a ListView. The main screen is a vertically scrolling list of recent earthquakes each displaying their magnitude, times, and locations. This is enhanced by a map that displays each earthquake's location and which uses shaded circles to indicate the area likely to be affected by each quake.


Sloth and Gluttony

First the good news. All non-trivial processing is done using ASyncTasks. There are no modal "loading..." dialogs, but incremental refreshes are indicated using the default indeterminate progress indicator. Changes to the quake list are handled dynamically at runtime with the list updated with new data as it's acquired.

The earthquake feed lookup and parsing is handled within a background Service that kills itself on completion.

On the flip side, the Service uses the pre-2.0 onStart method rather than onStartCommand (here's how to support both). Because of this the Service will restart as soon as sufficient resources become available. Instead, onStartCommand should return START_NOT_STICKY, knowing that the Service will be restarted within a reasonable period of time.

Updates are handled via regular background polling - with battery impact minimized through setInexactRepeating. There is scope for using C2DM to replace this polling approach with an event driven update approach.

Hostility and Arrogance

I know several of the engineers working on the Android framework; it didn't take long to decide that second guessing their decisions was likely to have a low ROI. Similarly, watching my friends suggested that some people actually use their phones for making calls and sending SMS message (who knew?!) .

In an effort to make this app seem as native as possible and allow the system to manage as much as possible it:
  • Uses the dialog mechanism to display dialogs.
  • Application preferences are handled using Preference Screens.
  • System icons are used (where possible) for menu items.
  • The back button behaves consistently and inline with user expectations.
That said, there are a couple of areas that annoy me as a user:
Discrimination

Arguably this app's biggest sin.

The manifest doesn't declare a target SDK, nor does it explicitly declare which screen sizes are supported. As a result it's unavailable to users of small screens (such as HTC Wildfire and Sony Ericsson X10 mini/pro users). Worse, it doesn't include assets for low or high resolution displays.

There's no internationalization support, which isn't great, what's worse is that I've gotten lazy with externalizing the strings. About half are defined in XML, the rest are string literals. There's no excuse for that.

The manifest doesn't declare which hardware features are mandatory, or which are used but optional. It uses (but doesn't require) both Location-based services and the vibrator, so to ensure it's available on the largest subset of devices both should be specified as optional in uses-feature nodes.

Beauty and User Experience

I am not a designer. If I were serious about turning this app into something I could charge for, I'd do well to seek out someone with skillz.

Even so, there's some simple improvements that would help:
  • The map is probably its most appealing aspect so it makes sense to make this more obvious. A Tab Layout might be a better option, together with the ability to horizontally swipe between views similar to the Calendar or News and Weather apps.
  • The list view lacks "sparkle" - replacing the standard header bar with something that includes the logo might improve this, as would a dynamic background for each quake. A LevelListDrawable that adjusts the background based on  the magnitude of each quake would be simple to achieve.
  • Long-pressing earthquakes should display a context menu that provides a wider range of alternative actions: such as viewing quake details (via a dialog or USGS.com), sharing a quake, or 'pinning' it to prevent it from being removed when it falls out of the 24 hour feed.
  • The map display has some unnecessary padding around the edges, and the quality of the map markers needs to be improved. Clicking on a quake marker should display an info window with actions (show details, etc.).
Generosity and Ubiquity

The app includes a Widget and a Live Folder for the home-screen, and it uses Notifications to announce new quakes. Search integration is missing though. Given that the quakes are stored in a Content Provider, it would be relatively simple to include it, both within the app and surfaced to the Quick Search Box.

It's worth considering using the send intent to let users share quake details with friends using other apps like email, SMS, Twitter, Facebook, etc.

Similarly, Earthquake doesn't expose and data or Intent Receivers, nor does it leverage Intents available from other apps. It might be worth exposing an Intent Receiver to allow other apps to show the earthquakes at a given location, or even plot the size of an earthquake on the map.

Utility

The utility of this app is likely to be in direct proportion with your distance from a significant fault line. If knowing when and where earthquake strike is useful to you, then so is this app.

Epicness

Epic is a high bar to aspire to, it's fair to say that this app does not reach such lofty heights.

Imagine your app was written by a competitor - what would you do to steal their users?

App developers take note: the easiest way to improve your app is to apply a critical and objective eye to it. I'm going to leave Earthquake as it is for a couple of weeks so that you can evaluate the app based on this review. I'll then look to implement the improvements I've suggested here.