Halloween Costume ideas 2015

Digital archives contain as usually understood by professional archivists and historians.

Articles by "Intents"
2009 accessibility Aconcagua Administration Adventure Racing Adventure Travel Adventurists Advice Afghanistan Africa Alaska Alberto Contador Aleutian Islands Alex Honnold Alps Amazon Amherst Amherst Destinations Amherst Hikes Andes Android 1.5 Android 1.6 Android 2.0 Android 2.1 Android 2.2 Android 2.3 Android 2.3.3 Android 3.0 Android 3.2 Android 4.0 Android Design Android Developer Challenge Android Developer Phone Android Market Animals Animation and Graphics Annapurna Announcements Antarctic App Components App Resources Apps Archeology Arctic Arctic Ocean Argentina Art Asia Atacama Desert Atlantic Ocean August Australia Authentication Autumn Aviation Backpacking Backyard Nature Badwater Ultra Baffin Island Baltic Sea BASE Jumping Beach Belchertown Belchertown Destinations Belchertown Hikes Berkshires Best Practices Bhutan Blogging Tips Blogs Book Review Boots Boston Botswana Brazil Broad Peak California Camping Canada Canyoneering Carstensz Pyramid Catatan Puspitasari Central America Central Massachusetts Checkpoint Tracker Children Chile China Cho Oyu Cinta Wanita Circumnavigation Clay Climate Change Climbing Clothing Code Day Colorado Colrain Congo River Connecticut Connectivity Conservation Area Contests Cool Stuff Craft Cycling Dashboard Dave Cornthwaite Death Valley Debugging Denali Developer Console Developer Days Developer Labs Developer profiles Dhaulagiri Dinosaurs Discovery Channel Dolomites Earth Day Easter Island Easthampton Ed Viesturs Educational Eiger El Capitan Endurance Sports Environmental Erving Europe Events Everest Expedition Exploration Explorers Club Fair Fairy House Farm Film Festival Finland Fireworks Fish Hatchery Fitz Roy Food Fourth of July France Free Games Gasherbrum Gaya Hidup Wanita Gear General Adventure Gestures Giro d'Italia Gobi Desert Google I/O Google Play Google Play services Goshen GPS Granby Grand Canyon Greater Boston Greenland Grossology Exhibit Guidelines Hadley Hadley 350th Half Dome Hang Gliding Hawaii Health Hikes Under One Mile Hiking Himalaya History Holyoke Honduras Horse How-to Hubungan Hunting Ice Cream IME impossible2Possible Independence Day India Indoor info Info Seminar Input methods Intents Internet Interview io2010 Italy Japan JNI John Muir Trail Jordan July June Jungfrau K2 K7 Kalahari Kangchenjunga Karakoram Kayaking Kilimanjaro Lake Michigan Lance Armstrong Layout Leadville 100 Leverett Lhotse Libraries Lintas Peristiwa Location Location and Sensors London Long Riders Ludlow Maine Makalu Manaslu Maple Massachusetts Matterhorn Media and Camera Mendon Meru Peak Mexico Mini Golf Mississippi River Missouri River Mongolia Monson Mont Blanc Motivasi Mount Elbrus Mount Everest Mount Rainier Mountain Biking Mountain View Mountaineering Movies Mt. Shasta Munich Museums Music Nameless Tower Namibia Nanga Parbat NASA National Geographic Nature Navigation NDK Nepal New Hampshire New Zealand Newburyport North America North Pole Northampton Northfield Norway Novelet Nuptse Nusantara Nutrition Ocean Okavango Delta Olympics Open source OpenGL ES Optimization Oregon Orizaba Outdoor Outdoor Retailer Outside Magazine Pacific Ocean Packs Paddling Pakistan Palmer Panduan SEO Parade Paragliding Patagonia Pelham Peru Petting Zoo Photography Playground Plum Island Poland Pool Pottery Pumpkins Quabbin Reservoir Quality Quick Search Box Rafting Rahasia Wanita Ray Zahab Reggio Emilia Research Resources Review Road Rally Rowing Roz Savage Running Sailing Sample code Sandbox School Science Scuba Diving SDK updates Sensors September Seven Summits Shelburne Falls Shisha Pangma Shutesbury Silk Road Site News Skateboarding skiing Skydiving Slacklining Sleeping Bags Snowboarding Solstice South Africa South America South Deerfield South Georgia South Hadley South Natick South Pacific South Pole Southern Ocean Space Speech Input Springfield Stand Up Paddling Storytime Strawberries Sturbridge Summer Summer Camp Summit Sunderland Survival Sutton Swimming Switzerland Tanzania Technology Tel Aviv Tents Testing Teva Mountain Games Text and Input Text-to-Speech Thrifty Tibet Torres Del Paine Touch Tour d'Afrique Tour de France Tour Divide Tower Trail Running Train Trango Towers TransRockies Travel Trekking Triathlon Turkey Turner's Falls Tutorial Ueli Steck Ultra Running Ultramarathon UMass United States USA Pro Cycling Challenge User Interface Utah Vancouver Vermont Video Wadi Rum Wakhan Wanita dan Bisnis Water Websites Western Massachusetts Westhampton Widgets Wildlife Williamstown Wingsuits Winter Wisconsin Worcester World Championship Wyoming Yemen Yosemite Zoo

Written in collaboration with Michael Burton, Mob.ly; Ivan Mitrovic, uLocate; and Josh Garnier, OpenTable.

OpenTable, uLocate, and Mob.ly worked together to create a great user experience on Android. We saw an opportunity to enable WHERE and GoodFood users to make reservations on OpenTable easily and seamlessly. This is a situation where everyone wins — OpenTable gets more traffic, WHERE and GoodFood gain functionality to make their applications stickier, and users benefit because they can make reservations with only a few taps of a finger. We were able to achieve this deep integration between our applications by using Android's Intent mechanism. Intents are perhaps one of Android's coolest, most unique, and under-appreciated features. Here's how we exploited them to compose a new user experience from parts each of us have.

Designing

One of the first steps is to design your Intent interface, or API. The main public Intent that OpenTable exposes is the RESERVE Intent, which lets you make a reservation at a specific restaurant and optionally specify the date, time, and party size.

Hereʼs an example of how to make a reservation using the RESERVE Intent:

startActivity(new Intent("com.opentable.action.RESERVE",
Uri.parse("reserve://opentable.com/2947?partySize=3")));

Our objective was to make it simple and clear to the developer using the Intent. So how did we decide what it would look like?

First, we needed an Action. We considered using Intent.ACTION_VIEW, but decided this didn't map well to making a reservation, so we made up a new action. Following the conventions of the Android platform (roughly <package-name>.action.<action-name>), we chose "com.opentable.action.RESERVE". Actions really are just strings, so it's important to namespace them. Not all applications will need to define their own actions. In fact, common actions such as Intent.ACTION_VIEW (aka "android.intent.action.VIEW") are often a better choice if youʼre not doing something unusual.

Next we needed to determine how data would be sent in our Intent. We decided to have the data encoded in a URI, although you might choose to receive your data as a collection of items in the Intent's data Bundle. We used a scheme of "reserve:" to be consistent with our action. We then put our domain authority and the restaurant ID into the URI path since it was required, and we shunted off all of the other, optional inputs to URI query parameters.

Exposing

Once we knew what we wanted the Intent to look like, we needed to register the Intent with the system so Android would know to start up the OpenTable application. This is done by inserting an Intent filter into the appropriate Activity declaration in AndroidManifest.xml:

<activity android:name=".activity.Splash" ... >
...
<intent-filter>
<action android:name="com.opentable.action.RESERVE"/>
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="reserve" android:host="opentable.com"/>
</intent-filter>
...
</activity>

In our case, we wanted users to see a brief OpenTable splash screen as we loaded up details about their restaurant selection, so we put the Intent Filter in the splash Activity definition. We set our category to be DEFAULT. This will ensure our application is launched without asking the user what application to use, as long as no other Activities also list themselves as default for this action.

Notice that things like the URI query parameter ("partySize" in our example) are not specified by the Intent filter. This is why documentation is key when defining your Intents, which weʼll talk about a bit later.

Processing

Now the only thing left to do was write the code to handle the intent.

    protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Uri uri;
final int restaurantId;
try {
uri = getIntent().getData();
restaurantId = Integer.parseInt( uri.getPathSegments().get(0));
} catch(Exception e) {
// Restaurant ID is required
Log.e(e);
startActivity( FindTable.start(FindTablePublic.this));
finish();
return;
}
final String partySize = uri.getQueryParameter("partySize");
...
}

Although this is not quite all the code, you get the idea. The hardest part here was the error handling. OpenTable wanted to be able to gracefully handle erroneous Intents that might be sent by partner applications, so if we have any problem parsing the restaurant ID, we pass the user off to another Activity where they can find the restaurant manually. It's important to verify the input just as you would in a desktop or web application to protect against injection attacks that might harm your app or your users.

Calling and Handling Uncertainty with Grace

Actually invoking the target application from within the requester is quite straight-forward, but there are a few cases we need to handle. What if OpenTable isn't installed? What if WHERE or GoodFood doesn't know the restaurant ID?



Restaurant ID knownRestaurant ID unknown
User has OpenTableCall OpenTable IntentDon't show reserve button
User doesn't have OpenTableCall Market IntentDon't show reserve button

You'll probably wish to work with your partner to decide exactly what to do if the user doesn't have the target application installed. In this case, we decided we would take the user to Android Market to download OpenTable if s/he wished to do so.

    public void showReserveButton() {

// setup the Intent to call OpenTable
Uri reserveUri = Uri.parse(String.format( "reserve://opentable.com/%s?refId=5449",
opentableId));
Intent opentableIntent = new Intent("com.opentable.action.RESERVE", reserveUri);

// setup the Intent to deep link into Android Market
Uri marketUri = Uri.parse("market://search?q=pname:com.opentable");
Intent marketIntent = new Intent(Intent.ACTION_VIEW).setData(marketUri);

opentableButton.setVisibility(opentableId > 0 ? View.VISIBLE : View.GONE);
opentableButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
PackageManager pm = getPackageManager();
startActivity(pm.queryIntentActivities(opentableIntent, 0).size() == 0 ?
opentableIntent : marketIntent);
}
});
}

In the case where the ID for the restaurant is unavailable, whether because they don't take reservations or they aren't part of the OpenTable network, we simply hide the reserve button.



Publishing the Intent Specification

Now that all the technical work is done, how can you get other developers to use your Intent-based API besides 1:1 outreach? The answer is simple: publish documentation on your website. This makes it more likely that other applications will link to your functionality and also makes your application available to a wider community than you might otherwise reach.

If there's an application that you'd like to tap into that doesn't have any published information, try contacting the developer. It's often in their best interest to encourage third parties to use their APIs, and if they already have an API sitting around, it might be simple to get you the documentation for it.

Summary

It's really just this simple. Now when any of us is in a new city or just around the neighborhood its easy to check which place is the new hot spot and immediately grab an available table. Its great to not need to find a restaurant in one application, launch OpenTable to see if there's a table, find out there isn't, launch the first application again, and on and on. We hope you'll find this write-up useful as you develop your own public intents and that you'll consider sharing them with the greater Android community.

Android offers a very powerful and yet easy to use tool called intents. An intent can be use to turn applications into high-level libraries and make code re-use something even better than before. The Android Home screen and AnyCut use intents extensively to create shortcuts for instance. While it is nice to be able to make use of a loosely coupled API, there is no guarantee that the intent you send will be received by another application. This happens in particular with 3rd party apps, like Panoramio and its RADAR intent.


While working on a new application, I came up with a very simple way to find out whether the system contains any application capable of responding to the intent you want to use. I implemented this technique in my application to gray out the menu item that the user would normally click to trigger the intent. The code is pretty simple and easy to follow:



/**
* Indicates whether the specified action can be used as an intent. This
* method queries the package manager for installed packages that can
* respond to an intent with the specified action. If no suitable package is
* found, this method returns false.
*
* @param context The application's environment.
* @param action The Intent action to check for availability.
*
* @return True if an Intent with the specified action can be sent and
* responded to, false otherwise.
*/
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list =
packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}

Here is how I use it:



@Override
public boolean onPrepareOptionsMenu(Menu menu) {
final boolean scanAvailable = isIntentAvailable(this,
"com.google.zxing.client.android.SCAN");

MenuItem item;
item = menu.findItem(R.id.menu_item_add);
item.setEnabled(scanAvailable);

return super.onPrepareOptionsMenu(menu);
}

In this example, the menu is grayed out if the Barcode Scanner application is not installed. Another, simpler, way to do this is to catch the ActivityNotFoundException when calling startActivity() but it only lets you react to the problem, you cannot predict it and update the UI accordingly to prevent the user from doing something that won't work. The technique described here can also be used at startup time to ask the user whether he'd like to install the missing package, you can then simply redirect him to the Android Market by using the appropriate URI.


Note: this article was originally posted on my personal blog.

MKRdezign

Contact Form

Name

Email *

Message *

Powered by Blogger.
Javascript DisablePlease Enable Javascript To See All Widget