Monday, February 21, 2011

Mobile World Congress: Slides, Smoothies, Collectable Pins, and Gadgets Galore

On the scale on which these things are measured, Mobile World Congress doesn't have a reputation for being a "fun" event. Exciting, vibrant, interesting, and worthwhile - sure. But the number of suits and ties in attendance generally precludes the sort of party atmosphere people expect at events like SXSW or Google I/O.

Less fun, that is, until now

It turns out that if you want to see serious folks in serious suits take a ride down a slide all you need to do is build it: and they will come.

By 9:30 on Monday morning the pristine environment of the Android stand - tucked away in a corner of Hall 8 - was a heaving mass of developers, CEOs, reporters, and collectable pin enthusiasts.


The Android stand (here's some more pictures) at MWC was all about openness and inclusion. The highlight for me was the 40 or so 3rd party developers who (rightly) stole the show. They worked tirelessly, demonstrating their apps and showcasing just what's possible on the Android platform. Developers take note: this could be you next year.

Typically at MWC Tuesday is the busiest day, with Wednesday tapering off and Thursday seeing the halls empty and abandoned by midday. Not this year. The stand was packed every day from 9:00 when they opened the gates to 7 when they flashed the lights. Even on Thursday when most stands are rolling up the carpet after lunch, we had a full house until the lights went off at 4pm.


Android Gurus, 3rd party developers, and a device bar with over 80 different Android powered handsets kept the crowd entertained. The obligatory slide was in constant use, and free smoothies (the Honeycomb - flavored with honey and lychee - was my pick) were on offer served by a bevy of friendly antipodean bartenders, who towards the end of the event served as the kingpins of a roaring trade in collectable Android pins.

Have you got any pins?

So it turns out that all you need to transform a clean-cut three-piece-suited CEO into a screaming fanboi is the introduction of limited edition Android collectable pins.

What started as a curiosity on day one exploded into full-blown pin-mania by Tuesday. There were 86 of these on offer at MWC - here's a few of my favorites.


Of course what we're really here for is the gadgets

And we weren't disappointed. There were some great new handsets on display this year, including LG's fascinating Optimus 3D features a 3D display that doesn't require special glasses.

The Samsung stand was a gold mine of awesome sauce with the frankly stunning Galaxy S II and the Honeycomb-sporting Galaxy Tab 10.1 tablet. As usual the screens on these devices where gorgeous - and the 10.1" Galaxy Tab was surprisingly light - I'd like to spend a little more time with both.

Tablets were the big news of the show, with the Samsung Tab 10.1 and the LG G-Slate joining the Motorola Xoom as forthcoming tablet devices running Android Honeycomb. HTC's also announced their first Android tablet (the HTC Flyer), a 7" tablet that will apparently run Gingerbread before receiving an OTA update to bring it up to Honeycomb.

I'm a fan of HTC's industrial design, so I'm excited to see what they come up with in the tablet market.

A+++ Would attend again

Any trip to Barcelona means great food and plentiful drink and this visit was no exception.

While in Barcelona I had the great pleasure of hanging out with the folks who make up the Barcelona GTUG. These guys are as awesome as they are welcoming. MWC is famous for its extravagant parties but hanging out with these guys in a crowded local bar was a definite highlight.

Between the fun of the Android stand, the excitement of getting to play with new toys, and the gluttonous pleasure of Spanish cuisine it was an incredible experience. The only question now is how do we top it next year?

Only time will tell, but I saw the designers behind this year's stand sketching plans for a two story slide...

Wednesday, February 09, 2011

Strategies for Honeycomb and Backwards Compatibility

Each new Android release heralds two things: A raft of new developer APIs, and a chorus of questions on how to use them while staying backwards compatible.

Android 3.0 (Honeycomb) is notable in that it introduces Fragments, possibly the most fundamental change to how Activity UIs are constructed since Android 1.0. To add to the excitement, Honeycomb is also the first Android platform release optimized specifically for extra-large screen (tablet) devices.

The good news is that we plan to have the same fragment APIs available as a static library for use with older versions of Android; the plan is to go right back to 1.6.

The easiest short-term fix is to create separate sets of Activities
When the static Fragments library becomes available you'll be able to skip this step entirely (or simply deprecate these Activities from your application). 
The introduction of Fragments (and to a lesser degree the Action Bar) represents a significant change to the code the lives within your Activity classes.

The following technique demonstrates how you can  create two separate sets of Activities: one set that supports Fragments and another set that is designed to work without them.

To select the right set of Activities at runtime, you need to include a launcher Activity in your manifest that detects support (or lack thereof) for Fragments and then starts the appropriate Activity.

<activity
  android:name="InitialActivity"
  android:label="@string/app_name">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>


Within InitialActivity, you can use reflection to check if Fragments are supported on the current device.

  private static boolean fragmentsSupported = false;

  private static void checkFragmentsSupported() throws NoClassDefFoundError {
    fragmentsSupported = android.app.Fragment.class != null;
  }

  static {
    try {
      checkFragmentsSupported();
    } catch (NoClassDefFoundError e) {
      fragmentsSupported = false;
    }
  }


Then within onCreate forward the application to the "real" first Activity that either uses Fragments or not depending on the capabilities of the device.

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Intent startActivityIntent = null;
    if (!fragmentsSupported)
      startActivityIntent = new Intent(this, MainNonFragmentActivity.class);
    else
      startActivityIntent = new Intent(this, MainFragmentActivity.class);

    startActivity(startActivityIntent);
    finish();
  }
}


Because you're calling finish immediately after starting the new Activity, the back button behaviour of your application works as expected.

Within the MainNonFragmentActivity you simply inflate a layout resource that doesn't use Fragments

setContentView(R.layout.non_fragment_main);

While the MainFragmentActivity inflates a layout that does.

What about the rest of the Honeycomb APIs?

The upcoming static Fragment library means you probably won't need to implement the previous technique in order to use Fragments as the building blocks of your UI, but what about the other new Honeycomb APIs like the Action Bar and Animators?

Let's ignore the non-Fragment Activities and focus on the scenario where Fragments are available, but none of the other Honeycomb APIs are.

The first step is to determine the availability of the new APIs. You can implement the same exception catching technique I used above for each of the classes you wish to use, but I've found it simpler to bundle all the new APIs together and build only two variations:

  private static boolean shinyNewAPIsSupported = 
    android.os.Build.VERSION.SDK_INT > 10;

Maintaining two sets of Activities doesn't require a parallel set of Fragments, layouts and resources

Once again, I'm going to create a parallel set of Activities: One that uses the shiny new APIs like the Action Bar and animations, and another that uses traditional techniques to create a similar user experience.

The technique described above can be used in the same way - this time using the shinyNewAPIsSupported variable to determine which Activity to start.

Because most of the user-interface logic is contained within the Fragments rather than the Activity, these parallel Activities don't do much beyond inflate slightly different layouts. Where the Action Bar is available the Activity will handle the effect of navigation and action clicks. If the Action Bar isn't available, the layout used will likely incorporate a custom version that mimics its behavior.

Only the highlighted ActionBarFragment in the following snippet would be different between the pre- and post-Honeycomb app layout.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <fragment class="com.paad.hc_backwards.ActionBarFragment"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"/> 
  <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <fragment class="com.paad.hc_backwards.SelectionFragment"
      android:layout_weight="3"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"/>
    <fragment class="com.paad.hc_backwards.ContentFragment"
      android:layout_weight="1"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"/>
  </LinearLayout>
</LinearLayout>


The key is that both sets of Activities will use the same fragments. Interaction between and within Fragments is usually maintained within each fragment, so only code related to the Action Bar (and other missing APIs) will need to be changed within the two Activity sets.

I expect all the apps I use on my phone to be optimized for tablets

Now lets take a look at the changes inherent in the introduction of the extra-large display. Fragments are designed specifically to make it easier to create flexible layouts, so I'm going to assume the existence of either Honeycomb or the static Fragment library when considering our options.

Device independent pixels (dp) and flexible layouts (like Relative Layout and Linear Layout) let your app scale to the dimensions and orientation of tablets. However, an app running on a 10" landscape device 1280 pixels across has a hell of a lot of whitespace when it was designed for a 4" portrait display at 480 pixels.

Consider the typical app design pattern where making a selection on one Activity determines what content is displayed another. Making a selection hides the selection Activity and displays the selected content.

Using Fragments you can easily construct layout variations for different screens

On a tablet it makes sense to position the selection and content Fragments within a single Activity, while on a phone only one should be visible at a time.

You can handle this as we did pre-Honeycomb by creating a res/layout-xlarge resource folder into which we put the side-by-side layout to use on an extra-large (tablet display).

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <fragment class="com.paad.hc_backwards.SelectionFragment"
    android:id="@+id/selection_fragment"
    android:layout_weight="3"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
  />
  <fragment class="com.paad.hc_backwards.ContentFragment"
    android:id="@+id/content_fragment"
    android:layout_weight="1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
  </fragment>
</LinearLayout>


In practice, we'll usually want to define a portrait and landscape specific mode using port or land resource qualifiers:

res/layout-xlarge-port
res/layout-xlarge-land

For phones, we'll use the same Fragments, but the layout (stored in res/layout) would contain only one Fragment stored in a containing layout.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/selection_fragment_frame"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <fragment class="com.paad.hc_backwards.SelectionFragment"
    android:id="@+id/selection_fragment"
    android:tag="full_screen_fragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
  />
</FrameLayout>


Within our code this produces a dilemma

The selection and content Fragments will interact slightly differently in phone or tablet mode. In both cases, making a selection should be reflected in the content Fragment - however in the phone layout this should also replace the selection Fragment with the newly updated content Fragment.

public void makeSelection(int i) {
  boolean extraLargeScreen = getResources().getConfiguration().screenLayout >
                            Configuration.SCREENLAYOUT_SIZE_LARGE;
  if (!extraLargeScreen) {
    FragmentTransaction ft = fragmentManager.beginTransaction();
    ft.hide(selectionFragment);
    ft.add(R.id.selection_fragment_frame, contentFragment);
    ft.addToBackStack(null);
    ft.commit();
  }
  contentFragment.setSelection(i);
}


Note that by calling addToBackStack we ensure that pressing the back button will undo this transaction, hiding the content Fragment and displaying the selection Fragment.

Fragments are a great way to componetize your UI

The new Android 3.0 (Honeycomb) SDK introduces a number of great new APIS, many of them designed to make it easier to build tablet version of your apps by providing a flexible mechanism for building different layouts depending on screen size and orientation. The availability of a static Fragment library will simplify the process of creating flexible layouts that are backwards compatible.

It is my firm belief that any app developed for mobile should be available for tablets. When I put my credentials into a shiny new tablet, I expect it to install all the apps I use on my phone - and I expect all of them to be optimized for the tablet form factor.

That's not to say you shouldn't create apps that are designed to work only on tablets, but I believe these tablet-specific editions should be made available side-by-side with phone versions that have been optimized to work on tablets.

Wednesday, February 02, 2011

Android Web Market, In App Billing, and Buyer Currency

Today during the Android Honeycomb Event we launched a couple of really exciting new features Android. As well as a closer look at what's possible with the Honeycomb SDK, we also announced:
There's more details on all three at the Android Developer Blog, and you can watch the launch event on YouTube.

Web Based Android Market

This is long awaited and seriously cool. Finally we developers have a homepage on the web for our Android apps. Not only that, but now we can install apps OTA simply by pressing install and the app of our choice will be automagically pushed to our phone.

My question to you: Have you uploaded the 512x512 alpha blended app icon and 1024x500 full bleed feature graphic? If the answer is no, then you have (at best) a 72x72 icon stretched into jaggy hell representing your app to would be users. That's probably something you want to do something about sooner rather than later.

To celebrate web landing pages for apps I've put together this list of the apps that I've been using on my Android devices.

Buyer Currency Support

You can now specify different prices for different currencies - and even more importantly, as a result users will always see the app priced in their local currency. No more "~" symbols or strange foreign currencies.

In App Billing

More ways for developers to monetize their apps can only be a good thing. A simpler purchase process for users benefits everyone.

Tuesday, February 01, 2011

Android App Surgery: Earthquake Redux (Honeycomb Tablet Edition)

If you follow me on Twitter you'll know I spent a great deal of the week before last firmly in The Zone, lost in the joyful exuberance of writing code. What I was working on? I was exploring the many and varied Android 3.0 (Honeycomb) SDK APIs.

To celebrate the Honeycomb preview SDK I'm doing an Android App Surgery that explores how I modified my existing Earthquake phone app for Honeycomb tablet devices. If you're interested in seeing more of these, nominate an app for review!


The App: Earthquake! (Tablet Edition)

I've taken the tablet redesign as an opportunity to implement many of the ideas that came up during my original Earthquake App Surgery. Chief amongst them was to improve the user experience, so I enlisted my colleague Roman Nurik to help me create a more polished design.


As well as a tasteful and distinctive red and white theme, this new UI style incorporates the Action Bar design pattern that simplifies navigation and highlights the refresh action. Small touches like the Level List Drawables used to indicate the relative size of each quake, the improved layout of each List View Item, and the introduction of the detail view work together to produce an app the is far more polished and intuitive.

Here's something I prepared earlier


The tablet design incorporates the distinctive new theme and List View Item layout, while the extra screen size lets me pull all three Activities (map, list, and details) into a single layout using Fragments.  In Honeycomb the Action Bar is a standard application component; I've customized it to use my theme and support my preferred navigation style and common actions.

 The defining feature of the tablet is its extra large screen
...or how I learned to stop worrying and love Fragments

The most pressing issue for most developers will be making effective use of an extra-large display. Fragments let you structure your Activities into separate interacting components.

You can easily rearrange, replace, show, and hide individual Fragments based on screen size, orientation, or user interaction. This is really useful for designing apps to support different screen sizes, or creating different layouts for portrait versus landscape.


Each Fragment encapsulates a piece of application UI and the associated functionality. Like Activities, the visual layout for each Fragment is defined in layout XML files. Typically the Activity layouts for landscape, portrait, and different screen sizes simply rearrange how the same Fragments are laid out.

I've used three Fragments plus the Action Bar. One to display the list of earthquakes, another to show the map, and a third to display the selected details.
For many tablet devices landscape will be the default orientation, so my primary design for Earthquake is landscape, but it's important to also create a compelling portrait mode.
Like Activities, each Fragment has its own lifecycle. You use the life cycle events to to save state and connect/disconnect listeners and receivers just as you used to do within Activities.

Each fragment can access its parent Activity by calling getActivity, and each Activity can find any of its Fragments with findFragmentById. This lets Fragments interact with each other regardless of their visibility or how they're laid out within an Activity.

Fragment Transactions let you modify the screen layout in real-time in response to user actions

You can show, hide, or replace individual Fragments at run time to create dynamic, interactive displays. In Earthquake I use Fragment Transactions to replace the details Fragment whenever a new quake is selected, and to hide the list and details fragments when the app switches to full screen.

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.hide(listFragment);
ft.commit();


The Fragment framework also lets you set breadcrumbs as you show, hide, or replace Fragments that allow cause the back button to revert the last transaction. In many cases your application will now contain a single Activity with a number of Fragments that are displayed, hidden, or replaced based on user navigation.
In Earthquake, for example, the normal (phone sized) UI layout would have a single Activity with the list Fragment visible at launch. Clicking a quake would replace the list with the with this transaction being added to the back stack so that a user pressing back returns then to the list view. I'd probably also use Tab Navigation in the Action Bar to let users switch between the map and list views.
The New Navigation: Introducing the Action Bar

The Action Bar component is a navigation panel that replaces the old title bar at the top of every Activity which neatly formalizes the emerging "Action Bar" design pattern. It's possible to hide the Action Bar, but best practice is to keep it and customize it to suit the style and navigation requirements of your app.


I started by applying a custom gradient to the background.

final ActionBar ab = getActionBar();
final Resources r = getResources();
final Drawable myDrawable = r.getDrawable(R.drawable.gradient_header);
ab.setBackgroundDrawable(myDrawable);


Next is navigation. There's a number of options for navigating your application - the two most common are tabs and drop down lists. I've used a drop down so users can choose the minimum magnitude of quakes to display. I might add a second drop down to also view quakes based on distance.

Here's how I create the drop down list and set the navigation mode on the Action Bar to display the drop down list.

ArrayAdapter mSpinnerAdapter;
mSpinnerAdapter = ArrayAdapter.createFromResource(this,
  R.array.magnitude_options,
  android.R.layout.simple_list_item_multiple_choice);
ab.setListNavigationCallbacks(mSpinnerAdapter, mOnNavigationListener);

ab.setNavigationMode(ActionBar.NAVIGATION_MODE_DROPDOWN_LIST);


The standard menu button has been deprecated in Honeycomb, in it's place is the on-screen menu icon at the far right of the Action Bar. The icons to its left are Menu Items that represent common actions.

To make them appear as Action Bar icons, you just flag them as SHOW_AS_ACTION, SHOW_AS_IF_SPACE, or SHOW_AS_ACTION_WITH_TEXT which will make their icons visible, visible only if there is enough space, and/or with the menu text visible respectively.

fullScreenMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

Animations that are smooth like butter

One of my favourite Honeycomb APIs is the new Animation framework. It boldly promises nothing less than the ability to animate any property on any object, and it delivers on that promise spectacularly.

The original idea for Earthquake was based on an inspiring exhibit at the New York Natural History Museum. It used animated expanding circles to dramatically illustrate the size and location of earthquakes and their relative timing.

I can now achieve the same effect by creating an Object Animator that animates the Image Level property of the Scale Drawable objects used to illustrate the felt radius of each quake.

final ObjectAnimator oa = new ObjectAnimator();
oa.setDuration(3*1000);
oa.setIntValues(0, 10000);
oa.setTarget(eachExandingCircle);
oa.setPropertyName("ImageLevel");
oa.start();


The silky smooth transition in and out of full-screen mode is also animated using an Object Animator. This time I'm animating the Layout Parameters of the Activity layout to adjust the relative weight of the list and map Fragments.

The animated transitions between detail Fragments are managed by a Fragment Transaction. I simply specify the fragment to replace, what to replace it with, and what animation to use for the transition.

DetailsFragment newFragment = DetailsFragment.newInstance(quake_id);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");
ft.commit();

Still to do...

I'm pretty happy with the styling and user experience so far, the next step is to incorporate the significant improvements to the Widget and Notification APIs.

Before launch I'll create a new list-based widget of recent quakes and an enhanced notification layout.

Get Your App Reviewed!

If you'd like to see how your app might look and work on a Honeycomb tablet, you can self-nominate at the moderator site. You can also go there to vote for which app you'd like to see reviewed! If you've got questions about developing for Honeycomb, head to StackOverflow and mark your questions with the Android and Honeycomb tags.