Tuesday 13 November 2012

Responsive Navigation: Optimizing for Touch Across Devices


I wanted to share this with people as I think it is a fantastic post and is a great read for any mobile Developers / Marketers. It is written by Jason Weaver & Luke Wroblewski. Enjoy. 
As more diverse devices embrace touch as a primary input method, it may be time to revisit navigation standards on the Web. How can a navigation menu be designed to work across a wide range of touch screen sizes? 

The Demos

Why do these navigation menus work across a wide range of touch screen sizes? Why do we care about touch across a wide range of screen sizes? Read on...

Across Screen Sizes

First, why do we care about touch across a wide range of screen sizes? Isn't touch just used on mobile devices and tablets? While it's true touch interfaces are increasingly present on small screen sizes, there's a lot of diversity even in this class of devices. Consider in the past two months smartphones ranging from 3.5" to 5.5" have been released by major manufacturers.
smartphone screen sizes from 4 to 5.5 inches
Tablets are no different. Again in the past two months alone we've seen tablets released with 7" screens, 10.1" screens, and everything in between.
tablet screen sizes from 7 to 10.1 inches
And the very notion of what defines a tablet is being challenged by laptop/tablet convertibles and touch-enabled Ultrabooks. These devices range from 11.6" to 13.3" inch screens and treat touch as a primary input method. In fact, early testing by Intel found that touch was even a preferred input method on touch enabled laptops.
convertible tablet/laptop devices ranging from 11.6 to 13.3 inches
Even beyond 13 inches, touch and gesture interfaces are possible. Consider Sony's 20" VAIO Tapor the use of a gesture interface like Leap Motion on any sized-screen and really quickly you realize touch is an input model to consider across all screen sizes.

Accounting For Touch

So what does it mean to consider touch across all screen sizes? Two things: touch target sizesand placement of controls. Any navigation system that needs to work with touch needs to have menu options that can be comfortably used with imprecise fingers. It also needs to be positioned in a way that aligns with how people hold and use touch-enabled devices.
Touch target sizes are relatively easy: just make things big enough to prevent accidental taps and errors. Your reaction to this may be "but I have so many things to fit in my app. How can I do that if the touch targets have to be so big?" frankly you can't and quite often that's a good thing.
Designing towards touch really forces us to simplify and decide what's most important- what needs to stay on the screen. If we go through that exercise we ultimately end up with software that's easier to understand and as a result more often used. Both good things. And while big touch targets can be comfortably used with a mouse (in fact they'll be easier to hit with a mouse), small mouse size targets can't be used easily with touch. So when in doubt, optimizing for touch will make sure things are usable for both mouse and touch users.
But accounting for touch isn't just about the size of controls, the placement of controls is important as well. To understand why this matters, let's look at how people hold a smartphone. In each of these examples, the bias is toward right handed use as most people in the world are right handed.
how people hold smartphones
These common patterns of posture create easy to hit and hard to reach touch areas. The area toward the bottom of the screen is easy, whereas the upper corners are a bit of stretch. So the bottom area of a smartphone screen is where we want to put an application's most common and important interactions. Where they can be reached quickly and easily.
comfortable touch areas on smartphones
Similarly we can look at tablet postures or how people typically hold tablet computers. That is two hands along the sides, or typing over the screen in their lap. In the landscape postures we see a different series of easy, ok, and hard to hit touch areas.
how people hold tablets
comfortable touch area on tablets
With touch-enabled laptops, people get pretty close to the screen and use their two thumbs to tap which yields easy to hit areas in the bottom corner of the screen.
comfortable touch areas on touch-enabled laptops
As you've hopefully observed the common pattern here is comfortable touch surfaces toward the bottom of the screen. Looking at the ergonomics of use across devices types pushes us toward the bottom, which is where we'd ideally like to place important functionality like navigation controls.

An Adaptive Solution

Today, most Web navigation systems are designed for a mouse and keyboard world. They're placed prominently across the top of the screen or along the sides. In other words, everywhere but in easy to touch areas.
In our earlier multi-device designs, we accounted for this convention by creating a series of navigation structures that adapted from comfortable touch zones on small screen devices to the kinds of navigation structures people have come to expect on desktop and laptop computers (top of screen, etc.). You can see a number of these explorations in Off Canvas Multi-Device Layouts.
multi device navigation
But given how things are changing and touch is permeating nearly every sized screen, it may be time to revisit that structure. Specifically, rather than optimizing for touch only on small screens, optimizing for it on all screens. That means big touch targets and bottom positioning throughout.
Of course we still have to account for varying screen widths, so our navigation controls will have to change as more space becomes available. To account for this, we decided to shift from a single row navigation structure on small screens to a split row model on larger screen sizes.
multi device touch optimized navigation
You can see this technique in action in the sample pages below:
Whether or not this multi-device navigation structure is the best answer for an increasingly touch-enabled computing world remains to be seen. However, rethinking our existing conventions is exactly the kind of thing we should be doing during the kind of fundamental changes we are seeing today. New input methods and devices are challenging our long-standing assumptions and that's a good thing for Web design.
Thanks to Jason Weaver for bringing these ideas to life! Check out some of our other multi-device collaborations in:

Monday 12 November 2012

How to: Send an Android User to Another App

One of Android's most important features is an app's ability to send the user to another app based on an "action" it would like to perform. For example, if your app has the address of a business that you'd like to show on a map, you don't have to build an activity in your app that shows a map. Instead, you can create a request to view the address using an Intent. The Android system then starts an app that's able to show the address on a map.

Build an Implicit Intent


Implicit intents do not declare the class name of the component to start, but instead declare an action to perform. The action specifies the thing you want to do, such as vieweditsend, or get something. Intents often also include data associated with the action, such as the address you want to view, or the email message you want to send. Depending on the intent you want to create, the data might be a Uri, one of several other data types, or the intent might not need data at all.
If your data is a Uri, there's a simple Intent() constructor you can use define the action and data.
For example, here's how to create an intent to initiate a phone call using the Uri data to specify the telephone number:
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
When your app invokes this intent by calling startActivity(), the Phone app initiates a call to the given phone number.
Here are a couple other intents and their action and Uri data pairs:
  • View a map:
    // Map point based on address
    Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
    // Or map point based on latitude/longitude
    // Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
    Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
  • View a web page:
    Uri webpage = Uri.parse("http://www.android.com");
    Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
Other kinds of implicit intents require "extra" data that provide different data types, such as a string. You can add one or more pieces of extra data using the various putExtra() methods.
By default, the system determines the appropriate MIME type required by an intent based on the Uri data that's included. If you don't include a Uri in the intent, you should usually use setType() to specify the type of data associated with the intent. Setting the MIME type further specifies which kinds of activities should receive the intent.
Here are some more intents that add extra data to specify the desired action:
  • Send an email with an attachment:
    Intent emailIntent = new Intent(Intent.ACTION_SEND);
    // The intent does not have a URI, so declare the "text/plain" MIME type
    emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
    emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
    emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
    emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
    // You can also attach multiple items by passing an ArrayList of Uris
  • Create a calendar event:
    Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
    Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
    Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
    calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
    calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
    calendarIntent.putExtra(Events.TITLE, "Ninja class");
    calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
    Note: This intent for a calendar event is supported only with API level 14 and higher.
Note: It's important that you define your Intent to be as specific as possible. For example, if you want to display an image using the ACTION_VIEW intent, you should specify a MIME type of image/*. This prevents apps that can "view" other types of data (like a map app) from being triggered by the intent.

Verify There is an App to Receive the Intent


Although the Android platform guarantees that certain intents will resolve to one of the built-in apps (such as the Phone, Email, or Calendar app), you should always include a verification step before invoking an intent.
Caution: If you invoke an intent and there is no app available on the device that can handle the intent, your app will crash.
To verify there is an activity available that can respond to the intent, call queryIntentActivities() to get a list of activities capable of handling your Intent. If the returned List is not empty, you can safely use the intent. For example:
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
If isIntentSafe is true, then at least one app will respond to the intent. If it is false, then there aren't any apps to handle the intent.
Note: You should perform this check when your activity first starts in case you need to disable the feature that uses the intent before the user attempts to use it. If you know of a specific app that can handle the intent, you can also provide a link for the user to download the app (see how to link to your product on Google Play).

Start an Activity with the Intent



Figure 1. Example of the selection dialog that appears when more than one app can handle an intent.
Once you have created your Intent and set the extra info, callstartActivity() to send it to the system. If the system identifies more than one activity that can handle the intent, it displays a dialog for the user to select which app to use, as shown in figure 1. If there is only one activity that handles the intent, the system immediately starts it.
startActivity(intent);
Here's a complete example that shows how to create an intent to view a map, verify that an app exists to handle the intent, then start it:
// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;
  
// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent);
}

Show an App Chooser



Figure 2. Example of the chooser dialog that appears when you usecreateChooser() to ensure that the user is always shown a list of apps that respond to your intent.
Notice that when you start an activity by passing your Intent tostartActivity() and there is more than one app that responds to the intent, the user can select which app to use by default (by selecting a checkbox at the bottom of the dialog; see figure 1). This is nice when performing an action for which the user generally wants to use the same app every time, such as when opening a web page (users likely use just one web browser) or taking a photo (users likely prefer one camera). However, if the action to be performed could be handled by multiple apps and the user might prefer a different app each time—such as a "share" action, for which users might have several apps through which they might share an item—you should explicitly show a chooser dialog, which forces the user to select which app to use for the action every time (the user cannot select a default app for the action).
To show the chooser, create an Intent using createChooser() and pass it to startActivity(). For example:
Intent intent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text. This says something like "Share this photo with"
String title = getResources().getText(R.string.chooser_title);
// Create and start the chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);