Text of my Summer of Tech Android talk

Here is the text of my Talk about Android at the Summer of Tech Mobile Developers Panel tonight.

I skipped the section telling businesses to think twice before deciding they needed a mobile application however, as there didn’t appear to be any business people in the audience. I was interested to find that during the panel discussion it was suggested to build mobile websites instead of mobile applications, and in discussion with individuals afterwards, the theme came up again. It’s clear that a number of developers in attendance agreed with me that mobile applications are looked at too readily, instead of options such as the mobile web or SMS.

Representing Android on SoT Mobile Panel, 8th Feb in Wellington

I’m going to be talking about Android for the Summer of Tech Mobile Developers Panel on the 8th of February. This is going to be my first public speaking engagement, and I’m really looking forward to it. Come and support, the discussion should be interesting and informative, and there’s pizza and beer! You need to RSVP on Lil’ Regie. All the Summer of Tech events I’ve attending have been great. Hope to see you there.

I’ll be busy preparing for the next week, a new blog post will be forthcoming sometime after the panel.

Android is the mobile platform of the moment

If you’re going to choose a single mobile platform to develop for in the next year, there are three main alternatives: Android; iPhone; and Windows Phone 7. It’s my belief Android is the platform for developers new to mobile.

Colleagues I talk to are surprised about my opinion. iPhone has the Apple design x-factor, and appears to still be the in thing around my office. And Windows mobile has a new, effective and quite unique design aesthetic applied to its user interface.

However there are reasons that Android looks like the best of the bunch.

The most immediately important reason is price. The cheapest Android phone I can find on Pricespy is an LG GT540 Optimus at NZ$281. The HTC Tattoo and Sony Ericsson Xperia X10 Mini are similar prices. The cheapest iPhone on there is an iPhone 3G 8GB for NZ$599. Whilst I can’t find any pricing for Windows Phone 7 at the moment, the high minimum specifications lead me to conclude it’s prices will be in the iPhone price range.

Gadget fetishists will spend a lot of money to have a really nice piece of kit that’s well designed. But Android phones are starting to get cheap enough to appeal to consumers who are looking for just a little more than a vanilla mobile. As consumers start to realise that smartphones are finally priced within their reach, a whole new audience is going to be available to Android developers.

But longer term there’s another important factor. As an open platform, Android is going to be used as the basis of more and more non-phone devices. I can’t make my points more eloquently than this article: Tipping Points and The Future of Electronics. But I’ll leave you with a quote from it: “But that’s beside the point, which is this: saying that Android is fragmented as a phone platform by comparing it to the iPhone is like saying the iPhone App Store is closed by comparing it to the PC. It’s the wrong comparison. Instead, think of it this way: Android is the most unified electronics device platform in the industry’s history.”.

I think Android is going to become a bigger market than the other two platforms, both for applications, and for skills. Android is a great platform to be involved in for a software engineer. I’m excited to be learning it.

Android and multiple Intents for an Activity

Android’s Intent resolution can find Activities to act on a datatype. But using this resolution, a single activity can’t consume a datatype in multiple ways.

An application I’m working on has an activity that can consume a datatype in multiple ways. When you think about it, this isn’t an uncommon scenario. For example, within a Twitter application, when an imaginary ComposeTweetActivity is called for a twitter user, you may wish to either send a direct tweet to the user, or a reply to the user. Assuming that our imaginary Twitter application uses the URI structure twitter-user://username to describe a user, putting the following into your AndroidManifest.xml would make sense:

<activity android:name=".ui.ComposeTweetActivity">
    <intent-filter>
        <action android:name="com.sample.twitter.action.TWEET_DIRECT" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        <data android:scheme="twitter-user" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.sample.twitter.action.TWEET_REPLY" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        <data android:scheme="twitter-user" />
    </intent-filter>
</activity>

It would be nice to be able to form a query which would find you both intent-filters so, for example, when a user bought up the context menu of a twitter user, you could show the Direct Message and Reply options.

However, there is no way to do this with the Android API to do this that I know of.

I had hoped originally to use ContextMenu.addIntentOptions() to populate my context menus. Underneath it, this call uses PackageManager.queryIntentActivityOptions() to get the list of intents. However queryIntentActivityOptions() doesn’t find intent-filters, it finds activities with at least one matching intent-filter. Meaning you only get one result per activity. The result also provides no information about the intent-filter that matched your intent.

This is a coherent behaviour – the method finds activities. However, I do think it would have been sensible to support scenarios such as mine, and provide a way to search for intent-filters.

My workaround is to create fake activities for any activity with more than one action, that then hand off to the real activity. The sample manifest I included in the question becomes

<activity android:name=".ui.ComposeTweetActivity" />
<activity android:name=".ui.ComposeTweetActivityDirect">
    <intent-filter>
        <action android:name="com.sample.twitter.action.TWEET_DIRECT" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        <data android:scheme="twitter-user" />
    </intent-filter>
</activity> 
<activity android:name=".ui.ComposeTweetActivityReply">
    <intent-filter>
        <action android:name="com.sample.twitter.action.TWEET_REPLY" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.ALTERNATIVE" />
        <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
        <data android:scheme="twitter-user" />
    </intent-filter>
</activity>

With ComposeTweetActivityDirect and ComposeTweetActivityReply simply handing off to ComposeTweetActivity with the appropriate action and data.

So you can see how the code works, here’s the onCreateContextMenu code that you’d use on the twitter user list page.

@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, view, menuInfo);
	AdapterView.AdapterContextMenuInfo info =
			(AdapterView.AdapterContextMenuInfo) menuInfo;
	Intent intent = new Intent(null, getUriOfSelectedUser(info.targetView));
	intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE);

	// Search and populate the menu with acceptable offering applications.
	menu.addIntentOptions(
			0, // Menu group to which new items will be added
			0, // Unique item ID (none)
			0, // Order for the items (none)
			this.getComponentName(), // The current Activity name
			null, // Specific items to place first (none)
			intent, // Intent created above that describes our requirements
			0, // Additional flags to control items (none)
			null); // Array of MenuItems that correlate to specific items
					// (none)
}

And here’s the code of ComposeTweetActivityDirect (ComposeTweetActivityReply is obviously almost identical).

public class ComposeTweetActivityDirect extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// TODO: No error handling
		Intent sourceIntent = getIntent();		
		Intent newIntent = new Intent(this, ComposeTweetActivity.class);
		newIntent.setAction(ComposeTweetActivity.DIRECT_ACTION_NAME);
		newIntent.setData(sourceIntent.getData());
		startActivity(newIntent);
		finish();
	}
}

And the code in ComposeTweetActivity to receive the intent

Intent intent = getIntent();
String action = intent.getAction();
if (DIRECT_ACTION_NAME.equals(action))
	StartDirectTweetForIntent(intent);
else if (REPLY_ACTION_NAME.equals(action))
	StartReplyForIntent(intent);

At some stage I’d like to deal with in a more elegant fashion, probably by building myself a library, but until that point, I’ll be using this workaround.

The seeds for this post were planted by my Stack Overflow question.