Showing posts with label tablets. Show all posts
Showing posts with label tablets. Show all posts

Monday, March 07, 2011

The Rise of the Tablet and the Innevitable Death of the Netbook

Last week I added a 10.1" Motorola Xoom to my gadget bag at the expense of a Netbook. As tablets grow in popularity I predict the Netbook's days are numbered.

Shortly after buying an Asus EeePC 701 in 2008 I described it to anyone who would listen as the best technology purchasing decision I'd ever made. It cost £200, was thin, light, and cheap. It booted Windows and loaded Office in under 10 seconds - only the paltry 800x600 display resolution was a legitimate cause of grief.

I used it to write most of my first book during my daily commute, and it was light and thin enough for me to throw in my bag for holidays or trips where I wasn't keen on bringing my laptop along (at the time my laptop was as 17" Vaio desktop replacement that weighed the better part of a metric fucktonne).

Light and with a full-day battery life,  Netbooks were a cheap second computer for lightweight computing tasks and surfing the web.

A one trick pony

Growing up, my parents ran a typewriter sales and repair company. I watched as the typewriter was gradually (and then very quickly) replaced with the desktop computer. For a small while "word processors" were a popular alternative - significantly cheaper than computers, and with most of the features of Word Perfect 5.1.

As PCs, laptops, and printers become cheap and ubiquitous, word processors grew more fanciful in an effort to compete. They offered more fonts and options but at a higher price. Before long, like most one-trick ponies, it was quietly covered with a sheet and put out of its misery.

I had a distinct feeling of deju-vu when late last year  I went in search of a replacement for my EeePC in the hopes of finding something cheaper, lighter, and a little faster. Instead I was presented with devices that were:
  • More expensive.
  • Thicker and heavier.
  • Slower to load and lacking SSDs.
At the same time, my new Macbook weighs around two kilograms and is no more than an inch thick. I can use it to write my book, write my code, edit photos, and pretty much anything else I could want to do.

It's true that a MBP is a lot more expensive than a Netbook - and bulkier - but it's not as though you would buy a Netbook instead of a real laptop. It's an additional device, so it's actually competing with tablets or smartphones - and a smartphone / tablet combo has a lot more to offer.

Smartphones and tablets make Netbooks a quaint irrelevancy

Modern smartphones, led by iPhone and Android, have largely filled the niche of mobile web browsing.

The arrival of the tablet is the final nail in the coffin, with a 10" tablet neatly filling the gap between smartphone and laptop.

With bright, high resolution displays, tablets offer an unparalleled experience for watching video. Games designed for tablets are created specifically for portable hardware featuring a touch screens and accelerometers. Similarly the rich ecosystem of apps is optimized specifically for smartphone and tablet platforms.

Typing on a 10.1" touchscreen is certainly no worse than typing on an undersized Netbook keyboard. Walking into meetings these days I'm increasingly finding people have left their laptops behind and are instead bringing along their tablets.

If you need to type, bring a laptop. If weight is an issue, bring your tablet

Tablets provide an optimized experience for portability, mobility, and touch-based input with a rich selection of apps and games designed with their size and power in mind.

Laptops are cheaper, lighter, and more powerful than ever before. They offer a rich ecosystem of apps and provide the perfect platform where text input is required.

Netbooks can still provide a great platform for getting online, but so can laptops and tablets. Laptops may one day give way to tablets and smartphones entirely, and apps may move entirely online, but Netbooks - like word processors in the 80's - will inevitably fall victim to competitors that offer a more dynamic ecosystem of apps, games, and features at an increasingly comparable price.

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.

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.

Monday, September 27, 2010

What's the Point of Tablets Anyway?

A couple of weeks ago I was fortunate enough to come into possession of a Samsung Galaxy Tab. It's fair to say that I've been eager to get my hands on a PADD tablet since some time around 1987.

While the utility of a portable, touch-screen, connected device was never in question on the Enterprise, their utility in the 21st century is still being determined.

So what, exactly, are tablets good for?

The Shared Communal Device

I've already found the Galaxy Tab to be the go-to device in the living room. It's perfect for shared photo-viewing, checking actors in IMDB, and adding something to the shopping basket. The large, bright screen and long battery life make it a much better viewing experience than a mobile, and simpler and more convenient than passing around a laptop.

Modern smartphones are intensely personal. They hold more private information than most people would ever willingly share. Would you hand over your phone to a friend for 30mins? What about your wife / husband / girlfriend / boyfriend?

I've created a new shared Gmail account, specifically for my Galaxy Tab (and potentially my GoogleTV), to make it easier to share. As prices come down I see a bunch of these around the house - probably replacing laptops and TVs.

The Ultimate Gaming Device

Games on tablets look incredible. A bright, sharp screen with a ton of screen real estate work superbly with touch controlled games.

The bigger screens could have been designed specifically to support multiplayer gaming. Games like Scrabble would work great with the screen becoming the game board, but that's just the start.

I grew up playing RPGs and CCGs. Imagine playing them when everyone has a tablet. Each player would have their card deck (or character sheet) on their tablet. Another device (probably at least 10") sits in the middle of the table and displays the cards in play (or character positions on a map).

The Multi-Media Entertainment Center and eBook Reader

Back in the day, I owned an Archos 320. 20Gb of audio and video on a 2.5" drive with a 4" screen. With no SSDs in sight, moving it while playing video let you feel the torque!

Today's tablets have up to 64Gb of solid-state storage, with many also including SD card slots letting you double that. A 7", 16:10 aspect ratio screen is the perfect surface for watching movies on the move, and HDMI output will let you plug your library into your giant flat screen TV.

Add an eBook reader app and you've got one device with all you music, movies, and books. That makes for an epic entertainment center.

While you'll need to pry my hardcover books out of my cold, dead, hands - I still think that within the next 5 years, most people will access all their movies, music, pictures, and books from the cloud. When that happens tablets will be the perfect portable screen on which to consume any kind of entertainment media.

The Laptop Replacement

Is the tablet set to replace the laptop? I've noticed a few iPads in meetings as people leave their laptops behind, preferring tablets for their portable computing needs. Typing on a fast, responsive 10" touch screen is actually a workable exercise, and it's the perfect platform for presenting an impromptu slide-show pitch or showing off your app / website.

I don't see tablets replacing the laptops we use at work for tasks that require significant typing (like writing code), but the future of netbooks might have just gotten a little grim.

So what's the real deal?

My gut says tablets will become increasingly popular as shareable devices that double as personal entertainment centers. The big screen and wide viewing angle of tablets makes them less private than phones. Still personal but not inherently private.

As app developers, we are uniquely positioned to both influence, and be influenced by, how people will use these new devices, so what do you think?
  1. Communal Internet Portal
  2. Ultimate Gaming Device
  3. Multi-Media Entertainment Center and eBook Reader
  4. Laptop Replacement
  5. All of the above
Any of them sound about right or am I full of it? Let me know in the comments!