Showing posts with label User Interface. Show all posts
Showing posts with label User Interface. Show all posts

Friday, February 5, 2010

Live wallpapers

With the introduction of live wallpapers in Android 2.1, users can now enjoy richer, animated, interactive backgrounds on their home screen. A live wallpaper is very similar to a normal Android application and has access to all the facilities of the platform: SGL (2D drawing), OpenGL (3D drawing), GPS, accelerometers, network access, etc. The live wallpapers included on Nexus One demonstrate the use of some of these APIs to create fun and interesting user experiences. For instance, the Grass wallpaper uses the phone's location to compute sunrise and sunset times in order to display the appropriate sky.

Creating your own live wallpaper is easy, especially if you have had previous experience with SurfaceView or Canvas. To learn how to create a live wallpaper, you should check out the CubeLiveWallpaper sample provided with the Android 2.1 SDK; you will find it in the directory platforms/android-2.1/samples/CubeLiveWallpaper.

A live wallpaper is very similar to a regular Android service. The only difference is the addition of a new method, onCreateEngine() whose goal is to create a WallpaperService.Engine. The engine is responsible for handling the lifecycle and the drawing of a wallpaper. The system provides you with a surface on which you can draw, just like you would with a SurfaceView. Drawing a wallpaper can be very expensive so you should optimize your code as much as possible to avoid using too much CPU, not only for battery life but also to avoid slowing down the rest of the system. That is also why the most important part of the lifecycle of a wallpaper is when it becomes invisible. When invisible, for instance because the user launched an application that covers the home screen, a wallpaper must stop all activity.

The engine can also implement several methods to interact with the user or the home application. For instance, if you want your wallpaper to scroll along when the user swipes from one home screen to another, you can use onOffsetsChanged(). To react to touch events, simply implement onTouchEvent(MotionEvent). Finally, applications can send arbitrary commands to the live wallpaper. Currently, only the standard home application sends commands to the onCommand() method of the live wallpaper:

  • android.wallpaper.tap: When the user taps an empty space on the workspace. This command is interpreted by the Nexus and Water live wallpapers to make the wallpaper react to user interaction. For instance, if you tap an empty space on the Water live wallpaper, new ripples appear under your finger.
  • android.home.drop: When the user drops an icon or a widget on the workspace. This command is also interpreted by the Nexus and Water live wallpapers.

Please note that live wallpaper is an Android 2.1 feature. To ensure that only users with devices that support this feature can download your live wallpaper, remember to add the following to your manifest before releasing to Android Market:

  • <uses-sdk android:minSdkVersion="7" />, which lets Android Market and the platform know that your application is using the Android 2.1 version.
  • <uses-feature android:name="android.software.live_wallpaper" />, which lets the Android Market and the platform know that your application is a live wallpaper.

Many great live wallpapers are already available on Android Market and we can't wait to see more!

Thursday, December 10, 2009

Optimize your layouts



Writing user interface layouts for Android applications is easy, but it can sometimes be difficult to optimize them. Most often, heavy modifications made to existing XML layouts, like shuffling views around or changing the type of a container, lead to inefficiencies that go unnoticed.

Starting with the SDK Tools Revision 3 you can use a tool called layoutopt to automatically detect common problems. This tool is currently only available from the command line and its use is very simple - just open a terminal and launch the layoutopt command with a list of directories or XML files to analyze:


$ layoutopt samples/
samples/compound.xml
7:23 The root-level <FrameLayout/> can be replaced with <merge/>
11:21 This LinearLayout layout or its FrameLayout parent is useless samples/simple.xml
7:7 The root-level <FrameLayout/> can be replaced with <merge/>
samples/too_deep.xml
-1:-1 This layout has too many nested layouts: 13 levels, it should have <= 10!
20:81 This LinearLayout layout or its LinearLayout parent is useless
24:79 This LinearLayout layout or its LinearLayout parent is useless
28:77 This LinearLayout layout or its LinearLayout parent is useless
32:75 This LinearLayout layout or its LinearLayout parent is useless
36:73 This LinearLayout layout or its LinearLayout parent is useless
40:71 This LinearLayout layout or its LinearLayout parent is useless
44:69 This LinearLayout layout or its LinearLayout parent is useless
48:67 This LinearLayout layout or its LinearLayout parent is useless
52:65 This LinearLayout layout or its LinearLayout parent is useless
56:63 This LinearLayout layout or its LinearLayout parent is useless
samples/too_many.xml
7:413 The root-level <FrameLayout/> can be replaced with <merge/>
-1:-1 This layout has too many views: 81 views, it should have <= 80! samples/useless.xml
7:19 The root-level <FrameLayout/> can be replaced with <merge/>
11:17 This LinearLayout layout or its FrameLayout parent is useless
For each analyzed file, the tool will indicate the line numbers of each tag that could potentially be optimized. In some cases, layoutopt will also offer a possible solution.

The current version of layoutopt contains a dozen rules used to analyze your layout files and future versions will contain more. Future plans for this tool also include the ability to create and use your own analysis rules, to automatically modify the layouts with optimized XML, and to use it from within Eclipse and/or a standalone user interface.


Windows users: to start layoutopt, open the file called layoutopt.bat in the tools directory of the SDK and on the last line, replace %jarpath% with -jar %jarpath%.

Friday, October 23, 2009

UI framework changes in Android 1.6

Android 1.6 introduces numerous enhancements and bug fixes in the UI framework. Today, I'd like to highlight three two improvements in particular.

Optimized drawing

The UI toolkit introduced in Android 1.6 is aware of which views are opaque and can use this information to avoid drawing views that the user will not be able to see. Before Android 1.6, the UI toolkit would sometimes perform unnecessary operations by drawing a window background when it was obscured by a full-screen opaque view. A workaround was available to avoid this, but the technique was limited and required work on your part. With Android 1.6, the UI toolkit determines whether a view is opaque by simply querying the opacity of the background drawable. If you know that your view is going to be opaque but that information does not depend on the background drawable, you can simply override the method called isOpaque():

@Override
public boolean isOpaque() {
return true;
}

The value returned by isOpaque() does not have to be constant and can change at any time. For instance, the implementation of ListView in Android 1.6 indicates that a list is opaque only when the user is scrolling it.

Updated: Our apologies—we spoke to soon about isOpaque(). It will be available in a future update to the Android platform.

More flexible, more robust RelativeLayout

RelativeLayout is the most versatile layout offered by the Android UI toolkit and can be successfully used to reduce the number of views created by your applications. This layout used to suffer from various bugs and limitations, sometimes making it difficult to use without having some knowledge of its implementation. To make your life easier, Android 1.6 comes with a revamped RelativeLayout. This new implementation not only fixes all known bugs in RelativeLayout (let us know when you find new ones) but also addresses its major limitation: the fact that views had to be declared in a particular order. Consider the following XML layout:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="64dip"
android:padding="6dip">

<TextView
android:id="@+id/band"
android:layout_width="fill_parent"
android:layout_height="26dip"

android:layout_below="@+id/track"
android:layout_alignLeft="@id/track"
android:layout_alignParentBottom="true"

android:gravity="top"
android:text="The Airborne Toxic Event" />

<TextView
android:id="@id/track"
android:layout_marginLeft="6dip"
android:layout_width="fill_parent"
android:layout_height="26dip"

android:layout_toRightOf="@+id/artwork"

android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="bottom"
android:text="Sometime Around Midnight" />

<ImageView
android:id="@id/artwork"
android:layout_width="56dip"
android:layout_height="56dip"
android:layout_gravity="center_vertical"

android:src="@drawable/artwork" />

</RelativeLayout>

This code builds a very simple layout—an image on the left with two lines of text stacked vertically. This XML layout is perfectly fine and contains no errors. Unfortunately, Android 1.5's RelativeLayout is incapable of rendering it correctly, as shown in the screenshot below.

The problem is that this layout uses forward references. For instance, the "band" TextView is positioned below the "track" TextView but "track" is declared after "band" and, in Android 1.5, RelativeLayout does not know how to handle this case. Now look at the exact same layout running on Android 1.6:

As you can see Android 1.6 is now better able to handle forward reference. The result on screen is exactly what you would expect when writing the layout.

Easier click listeners

Setting up a click listener on a button is very common task, but it requires quite a bit of boilerplate code:

findViewById(R.id.myButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Do stuff
}
});

One way to reduce the amount of boilerplate is to share a single click listener between several buttons. While this technique reduces the number of classes, it still requires a fair amount of code and it still requires giving each button an id in your XML layout file:

View.OnClickListener handler = View.OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.myButton: // doStuff
break;
case R.id.myOtherButton: // doStuff
break;
}
}
}

findViewById(R.id.myButton).setOnClickListener(handler);
findViewById(R.id.myOtherButton).setOnClickListener(handler);

With Android 1.6, none of this is necessary. All you have to do is declare a public method in your Activity to handle the click (the method must have one View argument):

class MyActivity extends Activity {
public void myClickHandler(View target) {
// Do stuff
}
}

And then reference this method from your XML layout:

<Button android:onClick="myClickHandler" />

This new feature reduces both the amount of Java and XML you have to write, leaving you more time to concentrate on your application.

The Android team is committed to helping you write applications in the easiest and most efficient way possible. We hope you find these improvements useful and we're excited to see your applications on Android Market.

Thursday, October 8, 2009

Support for additional screen resolutions and densities in Android

You may have heard that one of the key changes introduced in Android 1.6 is support for new screen sizes. This is one of the things that has me very excited about Android 1.6 since it means Android will start becoming available on so many more devices. However, as a developer, I know this also means a bit of additional work. That's why we've spent quite a bit of time making it as easy as possible for you to update your apps to work on these new screen sizes.

To date, all Android devices (such as the T-Mobile G1 and Samsung I7500, among others) have had HVGA (320x480) screens. The essential change in Android 1.6 is that we've expanded support to include three different classes of screen sizes:

  • small: devices with a screen size smaller than the T-Mobile G1 or Samsung I7500, for example the recently announced HTC Tattoo
  • normal: devices with a screen size roughly the same as the G1 or I7500.
  • large: devices with a screen size larger than the G1 or I7500 (such as a tablet-style device.)

Any given device will fall into one of those three groups. As a developer, you can control if and how your app appears to devices in each group by using a few tools we've introduced in the Android framework APIs and SDK. The documentation at the developer site describes each of these tools in detail, but here they are in a nutshell:

  • new attributes in AndroidManifest for an application to specify what kind of screens it supports,
  • framework-level support for using image drawables/layouts correctly regardless of screen size,
  • a compatibility mode for existing applications, providing a pseudo-HVGA environment, and descriptions of compatible device resolutions and minimum diagonal sizes.

The documentation also provides a quick checklist and testing tips for developers to ensure their apps will run correctly on devices of any screen size.

Once you've upgraded your app using Android 1.6 SDK, you'll need to make sure your app is only available to users whose phones can properly run it. To help you with that, we've also added some new tools to Android Market.

Until the next time you upload a new version of your app to Android Market, we will assume that it works for normal-class screen sizes. This means users with normal-class and large-class screens will have access to these apps. Devices with "large" screens simply run these apps in a compatibility mode, which simulates an HVGA environment on the larger screen.

Devices with small-class screens, however, will only be shown apps which explicitly declare (via the AndroidManifest) that they will run properly on small screens. In our studies, we found that "squeezing" an app designed for a larger screen onto a smaller screen often produces a bad result. To prevent users with small screens from getting a bad impression of your app (and reviewing it negatively!), Android Market makes sure that they can't see it until you upload a new version that declares itself compatible.

We expect small-class screens, as well as devices with additional resolutions in Table 1 in the developer document to hit the market in time for the holiday season. Note that not all devices will be upgraded to Android 1.6 at the same time. There will be significant number of users still with Android 1.5 devices. To use the same apk to target Android 1.5 devices and Android 1.6 devices, build your apps using Android 1.5 SDK and test your apps on both Android 1.5 and 1.6 system images to make sure they continue to work well on both types of devices. If you want to target small-class devices like HTC Tattoo, please build your app using the Android 1.6 SDK. Note that if your application requires Android 1.6 features, but does not support a screen class, you need to set the appropriate attributes to false. To use optimized assets for normal-class, high density devices like WVGA, or for low density devices please use the Android 1.6 SDK.

Wednesday, June 3, 2009

Activities and Tasks Design Guidelines

For our third post in the series of Android UI, we're releasing Activity and Task Design Guidelines. This section of our guidelines aims to help you understand basic concepts of activities and tasks, how they work, and how to enrich the user experience you are creating.

We've packed a lot into this section, which is targeted at designers and developers. You'll see examples that will illustrate how to use our core principles and mechanisms, such as multitasking, activity reuse, intents, and the back stack.

Additionally, we are providing some best practices around our UI patterns such as notifications. For example, we'll show you how to design a notification so that it will take the user to the screen they expect. This behavior needs to be thought out, and doesn't necessarily just happen by default.

With helpful pointers to the API's and this documentation, we look forward to building your understanding of what it means to design and develop an Android UI.

Wednesday, May 6, 2009

Painless threading

Whenever you first start an Android application, a thread called "main" is automatically created. The main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widgets and this includes the drawing events. It is also the thread you interact with Android widgets on. For instance, if you touch the a button on screen, the UI thread dispatches the touch event to the widget which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.

This single thread model can yield poor performance in Android applications that do not consider the implications. Since everything happens on a single thread performing long operations, like network access or database queries, on this thread will block the whole user interface. No event can be dispatched, including drawing events, while the long operation is underway. From the user's perspective, the application appears hung. Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog.

If you want to see how bad this can look, write a simple application with a button that invokes Thread.sleep(2000) in its OnClickListener. The button will remain in its pressed state for about 2 seconds before going back to its normal state. When this happens, it is very easy for the user to perceive the application as slow.

Now that you know you must avoid lengthy operations on the UI thread, you will probably use extra threads (background or worker threads) to perform these operations, and rightly so. Let's take the example of a click listener downloading an image over the network and displaying it in an ImageView:

public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}

At first, this code seems to be a good solution to your problem, as it does not block the UI thread. Unfortunately, it violates the single thread model: the Android UI toolkit is not thread-safe and must always be manipulated on the UI thread. In this piece of code, the ImageView is manipulated on a worker thread, which can cause really weird problems. Tracking down and fixing such bugs can be difficult and time-consuming.

Android offers several ways to access the UI thread from other threads. You may already be familiar with some of them but here is a comprehensive list:

Any of these classes and methods could be used to correct our previous code example:

public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}

Unfortunately, these classes and methods also tend to make your code more complicated and more difficult to read. It becomes even worse when your implement complex operations that require frequent UI updates. To remedy this problem, Android 1.5 offers a new utility class, called AsyncTask, that simplifies the creation of long-running tasks that need to communicate with the user interface.

AsyncTask is also available for Android 1.0 and 1.1 under the name UserTask. It offers the exact same API and all you have to do is copy its source code in your application.

The goal of AsyncTask is to take care of thread management for you. Our previous example can easily be rewritten with AsyncTask:

public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}

protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}

As you can see, AsyncTask must be used by subclassing it. It is also very important to remember that an AsyncTask instance has to be created on the UI thread and can be executed only once. You can read the AsyncTask documentation for a full understanding on how to use this class, but here is a quick overview of how it works:

In addition to the official documentation, you can read several complex examples in the source code of Shelves (ShelvesActivity.java and AddBookActivity.java) and Photostream (LoginActivity.java, PhotostreamActivity.java and ViewPhotoActivity.java). I highly recommend reading the source code of Shelves to see how to persist tasks across configuration changes and how to cancel them properly when the activity is destroyed.

Regardless of whether or not you use AsyncTask, always remember these two rules about the single thread model: do not block the UI thread and make sure the Android UI toolkit is only accessed on the UI thread. AsyncTask just makes it easier to do both of these things.

If you want to learn more cool techniques, come join us at Google I/O. Members of the Android team will be there to give a series of in-depth technical sessions and answer all your questions.

Monday, May 4, 2009

Drawable mutations

Android's drawables are extremely useful to easily build applications. A Drawable is a pluggable drawing container that is usually associated with a View. For instance, a BitmapDrawable is used to display images, a ShapeDrawable to draw shapes and gradients, etc. You can even combine them to create complex renderings.

Drawables allow you to easily customize the rendering of the widgets without subclassing them. As a matter of fact, they are so convenient that most of the default Android apps and widgets are built using drawables; there are about 700 drawables used in the core Android framework. Because drawables are used so extensively throughout the system, Android optimizes them when they are loaded from resources. For instance, every time you create a Button, a new drawable is loaded from the framework resources (android.R.drawable.btn_default). This means all buttons across all the apps use a different drawable instance as their background. However, all these drawables share a common state, called the "constant state." The content of this state varies according to the type of drawable you are using, but it usually contains all the properties that can be defined by a resource. In the case of a button, the constant state contains a bitmap image. This way, all buttons across all applications share the same bitmap, which saves a lot of memory.

The following diagram shows what entities are created when you assign the same image resource as the background of two different views. As you can see, two drawables are created but they both share the same constant state, hence the same bitmap:

This state sharing feature is great to avoid wasting memory but it can cause problems when you try to modify the properties of a drawable. Imagine an application with a list of books. Each book has a star next to its name, totally opaque when the user marks the book as a favorite, and translucent when the book is not a favorite. To achieve this effect, you would probably write the following code in your list adapter's getView() method:

Book book = ...;
TextView listItem = ...;

listItem.setText(book.getTitle());

Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.setAlpha(255); // opaque
} else {
star.setAlpha(70); // translucent
}

Unfortunately, this piece of code yields a rather strange result, all the drawables have the same opacity:

This result is explained by the constant state. Even though we are getting a new drawable instance for each list item, the constant state remains the same and, in the case of BitmapDrawable, the opacity is part of the constant state. Thus, changing the opacity of one drawable instance changes the opacity of all the other instances. Even worse, working around this issue was not easy with Android 1.0 and 1.1.

Android 1.5 offers a very way to solve this issue with a the new mutate() method. When you invoke this method on a drawable, the constant state of the drawable is duplicated to allow you to change any property without affecting other drawables. Note that bitmaps are still shared, even after mutating a drawable. The diagram below shows what happens when you invoke mutate() on a drawable:

Let's update our previous piece of code to make use of mutate():

Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
star.mutate().setAlpha(255); // opaque
} else {
star. mutate().setAlpha(70); // translucent
}

For convenience, mutate() returns the drawable itself, which allows to chain method calls. It does not however create a new drawable instance. With this new piece of code, our application now behaves correctly:

If you want to learn more cool techniques, come join us at Google I/O. Members of the Android team will be there to give a series of in-depth technical sessions and answer all your questions.

Friday, April 24, 2009

Live folders

Live folders have been introduced in Android 1.5 and let you display any source of data on the Home screen without forcing the user to launch an application. A live folder is simply a real-time view of a ContentProvider. As such, a live folder can be used to display all your contacts, your bookmarks, your email, your playlists, an RSS feed, etc. The possibilities are endless! Android 1.5 ships with a few stock live folders to display your contacts. For instance, the screenshot below shows the content of the live folders that displays all my contacts with a phone number:

If a contacts sync happens in the background while I'm browsing this live folder, I will see the change happen in real-time. Live folders are not only useful but it's also very easy to modify your application to make it provider a live folder. In this article, I will show you how to add a live folder to the Shelves application. You can download its source code and modify it by following my instructions to better understand how live folders work.

To give the user the option to create a new live folder, you first need to create a new activity with an intent filter who action is android.intent.action.CREATE_LIVE_FOLDER. To do so, simply open AndroidManifest.xml and add something similar to this:

<activity
android:name=".activity.BookShelfLiveFolder"
android:label="BookShelf">
<intent-filter>
<action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

The label and icon of this activity are what the user will see on the Home screen when choosing a live folder to create:

Since you just need an intent filter, it is possible, and sometimes advised, to reuse an existing activity. In the case of Shelves, we will create a new activity, org.curiouscreature.android.shelves.activity.BookShelfLiveFolder. The role of this activity is to send an Intent result to Home containing the description of the live folder: its name, icon, display mode and content URI. The content URI is very important as it describes what ContentProvider will be used to populate the live folder. The code of the activity is very simple as you can see here:

public class BookShelfLiveFolder extends Activity {
public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books");

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

final Intent intent = getIntent();
final String action = intent.getAction();

if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI,
"Books", R.drawable.ic_live_folder));
} else {
setResult(RESULT_CANCELED);
}

finish();
}

private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) {
final Intent intent = new Intent();

intent.setData(uri);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
Intent.ShortcutIconResource.fromContext(context, icon));
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);

return intent;
}
}

This activity, when invoked with theACTION_CREATE_LIVE_FOLDER intent, returns an intent with a URI, content://shelves/live_folders/books, and three extras to describe the live folder. There are other extras and constants you can use and you should refer to the documentation of android.provider.LiveFolders for more details. When Home receives this intent, a new live folder is created on the user's desktop, with the name and icon you provided. Then, when the user clicks on the live folder to open it, Home queries the content provider referenced by the provided URI.

Live folders' content providers must obey specific naming rules. The Cursor returned by the query() method must have at least two columns named LiveFolders._ID and LiveFolders.NAME. The first one is the unique identifier of each item in the live folder and the second one is the name of the item. There are other column names you can use to specify an icon, a description, the intent to associate with the item (fired when the user clicks that item), etc. Again, refer to the documentation of android.provider.LiveFolders for more details.

In our example, all we need to do is modify the existing provider in Shelves called org.curiouscreature.android.shelves.provider.BooksProvider. First, we need to modify the URI_MATCHER to recognize our content://shelves/live_folders/books content URI:

private static final int LIVE_FOLDER_BOOKS = 4;
// ...
URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS);

Then we need to create a new projection map for the cursor. A projection map can be used to "rename" columns. In our case, we will replace BooksStore.Book._ID, BooksStore.Book.TITLE and BooksStore.Book.AUTHORS with LiveFolders._ID, LiveFolders.TITLE and LiveFolders.DESCRIPTION:

private static final HashMap LIVE_FOLDER_PROJECTION_MAP;
static {
LIVE_FOLDER_PROJECTION_MAP = new HashMap();
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID +
" AS " + LiveFolders._ID);
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE +
" AS " + LiveFolders.NAME);
LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS +
" AS " + LiveFolders.DESCRIPTION);
}

Because we are providing a title and a description for each row, Home will automatically display each item of the live folder with two lines of text. Finally, we implement the query() method by supplying our projection map to the SQL query builder:

public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

switch (URI_MATCHER.match(uri)) {
// ...
case LIVE_FOLDER_BOOKS:
qb.setTables("books");
qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}

SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER);
c.setNotificationUri(getContext().getContentResolver(), uri);

return c;
}

You can now compile and deploy the application, go to the Home screen and try to add a live folder. I added a books live folder to my Home screen and when I open it, I can see the list of all of my books, with their titles and authors, and all it took was a few lines of code:

The live folders API is extremely simple and relies only on intents and content URI. If you want to see more examples of live folders implementation, you can read the source code of the Contacts application and of the Contacts provider.

You can also download the result of our exercise, the modified version of Shelves with live folders support.


Learn about Android 1.5 and more at Google I/O. Members of the Android team will be there to give a series of in-depth technical sessions and to field your toughest questions.

Tuesday, April 21, 2009

Updating Applications for On-screen Input Methods

One of the major new features we are introducing in Android 1.5 is our Input Method Framework (IMF), which allows developers on-screen input methods such as software keyboards. This article will provide an overview of what Android input method editors (IMEs) are, and what an application developer needs to do to work well with them. The IMF allows for a new class of Android devices, such as those without a hardware keyboard, so it is important that your application work well with it to provide the users of such devices a great experience.

What is an input method?

The Android IMF is designed to support a variety of IMEs, including soft keyboard, hand-writing recognizers, and hard keyboard translators. Our focus, however, will be on soft keyboards, since this is the kind of input method that is currently part of the platform.

A user will usually access the current IME by tapping on a text view to edit, as shown here in the home screen:

The soft keyboard is positioned at the bottom of the screen over the application's window. To organize the available space between the application and IME, we use a few approaches; the one shown here is called pan and scan, and simply involves scrolling the application window around so that the currently focused view is visible. This is the default mode, since it is the safest for existing applications.

Most often the preferred screen layout is a resize, where the application's window is resized to be entirely visible. An example is shown here, when composing an e-mail message:

The size of the application window is changed so that none of it is hidden by the IME, allowing full access to both the application and IME. This of course only works for applications that have a resizeable area that can be reduced to make enough space, but the vertical space in this mode is actually no less than what is available in landscape orientation, so very often an application can already accommodate it.

The final major mode is fullscreen or extract mode. This is used when the IME is too large to reasonably share space with the underlying application. With the standard IMEs, you will only encounter this situation when the screen is in a landscape orientation, although other IMEs are free to use it whenever they desire. In this case the application window is left as-is, and the IME simply displays fullscreen on top of it, as shown here:

Because the IME is covering the application, it has its own editing area, which shows the text actually contained in the application. There are also some limited opportunities the application has to customize parts of the IME (the "done" button at the top and enter key label at the bottom) to improve the user experience.

Basic XML attributes for controlling IMEs

There are a number of things the system does to try to help existing applications work with IMEs as well as possible, such as:

  • Use pan and scan mode by default, unless it can reasonably guess that resize mode will work by the existence of lists, scroll views, etc.
  • Analyze the various existing TextView attributes to guess at the kind of content (numbers, plain text, etc) to help the soft keyboard display an appropriate key layout.
  • Assign a few default actions to the fullscreen IME, such as "next field" and "done".

There are also some simple things you can do in your application that will often greatly improve its user experience. Note that, except where explicitly mentioned, all of the things suggested here will not tie your application to Android 1.5 -- it will still work on older releases, which will simply ignore these new options.

Specifying each EditText control's input type

The most important thing for an application to do is use the new android:inputType attribute on each EditText, which provides much richer information about the text content. This attribute actually replaces many existing attributes (android:password, android:singleLine, android:numeric, android:phoneNumber, android:capitalize, android:autoText, android:editable); if you specify both, Cupcake devices will use the new android:inputType attribute and ignore the others.

The input type attribute has three pieces:

  • The class is the overall interpretation of characters. The currently supported classes are text (plain text), number (decimal number), phone (phone number), and datetime (a date or time).
  • The variation is a further refinement on the class. In the attribute you will normally specify the class and variant together, with the class as a prefix. For example, textEmailAddress is a text field where the user will enter something that is an e-mail address (foo@bar.com) so the key layout will have an '@' character in easy access, and numberSigned is a numeric field with a sign. If only the class is specified, then you get the default/generic variant.
  • Additional flags can be specified that supply further refinement. These flags are specific to a class. For example, some flags for the text class are textCapSentences, textAutoCorrect, and textMultiline.

As an example, here is the new EditText for the IM application's message text view:

    <EditText android:id="@+id/edtInput"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
android:imeOptions="actionSend|flagNoEnterAction"
android:maxLines="4"
android:maxLength="2000"
android:hint="@string/compose_hint"/>

A full description of all of the input types can be found in the documentation. It is important to make use of the correct input types that are available, so that the soft keyboard can use the optimal keyboard layout for the text the user will be entering.

Enabling resize mode and other window features

The next most important thing for you to do is specify the overall behavior of your window in relation to the input method. The most visible aspect of this is controlling resize vs. pan and scan mode, but there are other things you can do as well to improve your user experience.

You will usually control this behavior through the android:windowSoftInputMode attribute on each <activity> definition in your AndroidManifest.xml. Like the input type, there are a couple different pieces of data that can be specified here by combining them together:

  • The window adjustment mode is specified with either adjustResize or adjustPan. It is highly recommended that you always specify one or the other.
  • You can further control whether the IME will be shown automatically when your activity is displayed and other situations where the user moves to it. The system won't automatically show an IME by default, but in some cases it can be convenient for the user if an application enables this behavior. You can request this with stateVisible. There are also a number of other state options for finer-grained control that you can find in the documentation.

A typical example of this field can be see in the edit contact activity, which ensures it is resized and automatically displays the IME for the user:

    <activity name="EditContactActivity"
android:windowSoftInputMode="stateVisible|adjustResize">
...
</activity>

For non-activity windows, there is a new Window.setSoftInputMode() method that can be used to control their behavior. Note that calling this API will make your application incompatible with previous Android platforms.

Controlling the action buttons

The final customization we will look at is the "action" buttons in the IME. There are currently two types of actions:

  • The enter key on a soft keyboard is typically bound to an action when not operating on a mult-line edit text. For example, on the G1 pressing the hard enter key will typically move to the next field or the application will intercept it to execute an action; with a soft keyboard, this overloading of the enter key remains, since the enter button just sends an enter key event.
  • When in fullscreen mode, an IME may also put an additional action button to the right of the text being edited, giving the user quick access to a common application operation.

These options are controlled with the android:imeOptions attribute on TextView. The value you supply here can be any combination of:

  • One of the pre-defined action constants (actionGo, actionSearch, actionSend, actionNext, actionDone). If none of these are specified, the system will infer either actionNext or actionDone depending on whether there is a focusable field after this one; you can explicitly force no action with actionNone.
  • The flagNoEnterAction option tells the IME that the action should not be available on the enter key, even if the text itself is not multi-line. This avoids having unrecoverable actions like (send) that can be accidentally touched by the user while typing.
  • The flagNoAccessoryAction removes the action button from the text area, leaving more room for text.
  • The flagNoExtractUi completely removes the text area, allowing the application to be seen behind it.

The previous IM application message view also provides an example of an interesting use of imeOptions, to specify the send action but not let it be shown on the enter key:

 android:imeOptions="actionSend|flagNoEnterAction"

APIs for controlling IMEs

For more advanced control over the IME, there are a variety of new APIs you can use. Unless special care is taken (such as by using reflection), using these APIs will cause your application to be incompatible with previous versions of Android, and you should make sure you specify android:minSdkVersion="3" in your manifest.

The primary API is the new android.view.inputmethod.InputMethodManager class, which you can retrieve with Context.getSystemService(). It allows you to interact with the global input method state, such as explicitly hiding or showing the current IME's input area.

There are also new window flags controlling input method interaction, which you can control through the existing Window.addFlags() method and new Window.setSoftInputMode() method. The PopupWindow class has grown corresponding methods to control these options on its window. One thing in particular to be aware of is the new WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM constant, which is used to control whether a window is on top of or behind the current IME.

Most of the interaction between an active IME and application is done through the android.view.inputmethod.InputConnection class. This is the API an application implement, which an IME calls to perform the appropriate edit operations on the application. You won't normally need to worry about this, since TextView provides its own implementation for itself.

There are also a handful of new View APIs, the most important of these being onCreateInputConnection() which creates a new InputConnection for an IME (and fills in an android.view.inputmethod.EditorInfo structure with your input type, IME options, and other data); again, most developers won't need to worry about this, since TextView takes care of it for you.


Learn about Android 1.5 and more at Google I/O. Members of the Android team will be there to give a series of in-depth technical sessions and to field your toughest questions.

Tuesday, April 14, 2009

UI framework changes in Android 1.5

On Monday, we released an early look at the Android 1.5 SDK. Not only does this platform update contain numerous new features, APIs, and bug fixes, but Android 1.5 also brings a new default look for the Android UI framework. After Android 1.0 and 1.1, our designers worked hard to refine and polish the appearance of the system. The screenshots below show the same activity (creating a new contact) on Android 1.1 and Android 1.5:

You can see in this example that the buttons and checkboxes have a new appearance. Even though these changes do not affect binary nor source compatibility, they might still break the UI of your apps. As part of the UI refresh, the minimum size of some of the widgets has changed. For instance, Android 1.1 buttons have a minimum size of 44x48 pixels whereas Android 1.5 buttons now have a minimum size of 24x48 pixels. The image below compares the sizes of Android 1.1 buttons with Android 1.5 buttons:

If you rely on the button's minimum size, then the layout of your application may not be the same in Android 1.5 as it was in Android 1.1 because of this change. This would happen for instance if you created a grid of buttons using LinearLayout and relying on the minimum size yielded by wrap_content to align the buttons properly:

This layout could easily be fixed by using the android:layout_weight attribute or by replacing the LinearLayout containers with a TableLayout.

This example is probably the worst-case UI issue you may encounter when running your application on Android 1.5. Other changes introduced in Android 1.5, especially bug fixes in the layout views, may also impact your application—especially if it is relying on faulty/buggy behavior of the UI framework.

If you encounter issues when running your application on Android 1.5, please join us on the Google groups or IRC so that we and the Android community can help you fix your application.

Happy coding!

Monday, March 30, 2009

Android Layout Tricks #3: Optimize with stubs

Sharing and reusing layouts is very easy with Android thanks to the <include /> tag, sometimes even too easy and you might end up with user interfaces that contain a large number of views, some of which are rarely used. Thankfully, Android offers a very special widget called ViewStub, which brings you all the benefits of the <include /> without polluting your user interface with rarely used views.

A ViewStub is a dumb and lightweight view. It has no dimension, it does not draw anything and does not participate in the layout in any way. This means a ViewStub is very cheap to inflate and very cheap to keep in a view hierarchy. A ViewStub can be best described as a lazy include. The layout referenced by a ViewStub is inflated and added to the user interface only when you decide so.

The following screenshot comes from the Shelves application. The main purpose of the activity shown in the screenshot is to present the user with a browsable list of books:

The same activity is also used when the user adds or imports new books. During such an operation, Shelves shows extra bits of user interface. The screenshot below shows the progress bar and cancel button that appear at the bottom of the screen during an import:

Because importing books is not a common operation, at least when compared to browsing the list of books, the import panel is originally represented by a ViewStub:

When the user initiates the import process, the ViewStub is inflated and replaced by the content of the layout file it references:

To use a ViewStub all you need is to specify an android:id attribute, to later inflate the stub, and an android:layout attribute, to reference what layout file to include and inflate. A stub lets you use a third attribute, android:inflatedId, which can be used to override the id of the root of the included file. Finally, the layout parameters specified on the stub will be applied to the roof of the included layout. Here is an example:

<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"

android:layout="@layout/progress_overlay"

android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />

When you are ready to inflate the stub, simply invoke the inflate() method. You can also simply change the visibility of the stub to VISIBLE or INVISIBLE and the stub will inflate. Note however that the inflate() method has the benefit of returning the root View of the inflate layout:

((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

It is very important to remember that after the stub is inflated, the stub is removed from the view hierarchy. As such, it is unnecessary to keep a long-lived reference, for instance in an class instance field, to a ViewStub.

A ViewStub is a great compromise between ease of programming and efficiency. Instead of inflating views manually and adding them at runtime to your view hierarchy, simply use a ViewStub. It's cheap and easy. The only drawback of ViewStub is that it currently does not support the <merge /> tag.

Happy coding!

Thursday, March 5, 2009

Window Backgrounds & UI Speed

Some Android applications require to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both these techniques rely on a single feature, the window's background drawable.

The term window background is a bit misleading however. When you setup your user interface by calling setContentView() on an Activity, Android adds your views to the Activity's window. The window however does not contain only your views, but a few others created for you. The most important one is, in the current implementation used on the T-Mobile G1, the DecorView, highlighted in the view hierarchy below:

A typical Android view hierarchy

The DecorView is the view that actually holds the window's background drawable. Calling getWindow().setBackgroundDrawable() from your Activity changes the background of the window by changing the DecorView's background drawable. As mentioned before, this setup is very specific to the current implementation of Android and can change in a future version or even on another device.

If you are using the standard Android themes, a default background drawable is set on your activities. The standard theme currently used on the T-Mobile G1 uses for instance a ColorDrawable. For most applications, this background drawable works just fine and can be left alone. It can however impacts your application's drawing performance. Let's take the example of an application that always draws a full screen opaque picture:

An opaque user interface doesn't need a window background

You can see on this screenshot that the window's background is invisible, entirely covered by an ImageView. This application is setup to redraw as fast as it can and draws at about 44 frames per second, or 22 milliseconds per frame (note: the number of frames per second used in this article were obtained on a T-Mobile G1 with my finger on the screen so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An easy way to make such an application draw faster is to remove the background drawable. Since the user interface is entirely opaque, drawing the background is simply wasteful. Removing the background improves the performance quite nicely:

Remove the background for faster drawing

In this new version of the application, the drawing speed went up to 51 frames per second, or 19 milliseconds per frame. The difference of 3 milliseconds per is easily explained by the speed of the memory bus on the T-Mobile G1: it is exactly the time it takes to move the equivalent of a screenful of pixels on the bus. The difference could be even greater if the default background was using a more expensive drawable.

Removing the window's background can be achieved very easily by using a custom theme. To do so, first create a file called res/values/theme.xml containing the following:

<resources>
<style name="Theme.NoBackground" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>

You then need to apply the theme to your activity by adding the attribute android:theme="@style/Theme.NoBackground" to your <activity /> or <application /> tag. This trick comes in very handy for any app that uses a MapView, a WebView or any other full screen opaque view.

Opaque views and Android: this optimization is currently necessary because the Android UI toolkit is not smart enough to prevent the drawing of views hidden by opaque children. The main reason why this optimization was not implemented is simply because there are usually very few opaque views in Android applications. This is however something that I definitely plan on implementing as soon as possible and I can only apologize for not having been able to do this earlier.

Using a theme to change the window's background is also a fantastic way to improve the perceived startup performance of some of your activities. This particular trick can only be applied to activities that use a custom background, like a texture or a logo. The Shelves application is a good example:

Textured backgrounds are good candidates for window's background

If this application simply set the wooden background in the XML layout or in onCreate() the user would see the application startup with the default theme and its dark background. The wooden texture would only appear after the inflation of the content view and the first layout/drawing pass. This causes a jarring effect and gives the user the impression that the application takes time to load (which can actually be the case.) Instead, the application defines the wooden background in a theme, picked up by the system as soon as the application starts. The user never sees the default theme and gets the impression that the application is up and running right away. To limit the memory and disk usage, the background is a tiled texture defined in res/drawable/background_shelf.xml:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/shelf_panel"
android:tileMode="repeat" />

This drawable is simply referenced by the theme:

<resources>
<style name="Theme.Shelves" parent="android:Theme">
<item name="android:windowBackground">@drawable/background_shelf</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>

The same exact trick is used in the Google Maps application that ships with the T-Mobile G1. When the application is launched, the user immediately sees the loading tiles of MapView. This is only a trick, the theme is simply using a tiled background that looks exactly like the loading tiles of MapView.

Sometimes the best tricks are also the simplest so the next time you create an activity with an opaque UI or a custom background, remember to change the window's background.

Download the source code of the first example.

Download the source code of Shelves.

Tuesday, March 3, 2009

Android Layout Tricks #3: Optimize by merging

In the previous installment of Android Layout Tricks, I showed you how to use the <include /> tag in XML layout to reuse and share your layout code. I also mentioned the <merge /> and it's now time to learn how to use it.

The <merge /> was created for the purpose of optimizing Android layouts by reducing the number of levels in view trees. It's easier to understand the problem this tag solves by looking at an example. The following XML layout declares a layout that shows an image with its title on top of it. The structure is fairly simple; a FrameLayout is used to stack a TextView on top of an ImageView:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"

android:scaleType="center"
android:src="@drawable/golden_gate" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"

android:padding="12dip"

android:background="#AA000000"
android:textColor="#ffffffff"

android:text="Golden Gate" />

</FrameLayout>

This layout renders nicely as we expected and nothing seems wrong with this layout:



A FrameLayout is used to overlay a title on top of an image


Things get more interesting when you inspect the result with HierarchyViewer. If you look closely at the resulting tree you will notice that the FrameLayout defined in our XML file (highlighted in blue below) is the sole child of another FrameLayout:

A layout with only one child of same dimensions can be removed

Since our FrameLayout has the same dimension as its parent, by the virtue of using the fill_parent constraints, and does not define any background, extra padding or a gravity, it is totally useless. We only made the UI more complex for no good reason. But how could we get rid of this FrameLayout? After all, XML documents require a root tag and tags in XML layouts always represent view instances.

That's where the <merge /> tag comes in handy. When the LayoutInflater encounters this tag, it skips it and adds the <merge /> children to the <merge /> parent. Confused? Let's rewrite our previous XML layout by replacing the FrameLayout with <merge />:

<merge xmlns:android="http://schemas.android.com/apk/res/android">

<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"

android:scaleType="center"
android:src="@drawable/golden_gate" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"

android:padding="12dip"

android:background="#AA000000"
android:textColor="#ffffffff"

android:text="Golden Gate" />

</merge>

With this new version, both the TextView and the ImageView will be added directly to the top-level FrameLayout. The result will be visually the same but the view hierarchy is simpler:

Optimized view hierarchy using the merge tag

Obviously, using <merge /> works in this case because the parent of an activity's content view is always a FrameLayout. You could not apply this trick if your layout was using a LinearLayout as its root tag for instance. The <merge /> can be useful in other situations though. For instance, it works perfectly when combined with the <include /> tag. You can also use <merge /> when you create a custom composite view. Let's see how we can use this tag to create a new view called OkCancelBar which simply shows two buttons with customizable labels. You can also download the complete source code of this example. Here is the XML used to display this custom view on top of an image:

<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">

<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"

android:scaleType="center"
android:src="@drawable/golden_gate" />

<com.example.android.merge.OkCancelBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"

android:paddingTop="8dip"
android:gravity="center_horizontal"

android:background="#AA000000"

okCancelBar:okLabel="Save"
okCancelBar:cancelLabel="Don't save" />

</merge>

This new layout produces the following result on a device:

Creating a custom view with the merge tag

The source code of OkCancelBar is very simple because the two buttons are defined in an external XML file, loaded using a LayoutInflate. As you can see in the following snippet, the XML layout R.layout.okcancelbar is inflated with the OkCancelBar as the parent:

public class OkCancelBar extends LinearLayout {
public OkCancelBar(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER);
setWeightSum(1.0f);

LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);

String text = array.getString(R.styleable.OkCancelBar_okLabel);
if (text == null) text = "Ok";
((Button) findViewById(R.id.okcancelbar_ok)).setText(text);

text = array.getString(R.styleable.OkCancelBar_cancelLabel);
if (text == null) text = "Cancel";
((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);

array.recycle();
}
}

The two buttons are defined in the following XML layout. As you can see, we use the <merge /> tag to add the two buttons directly to the OkCancelBar. Each button is included from the same external XML layout file to make them easier to maintain; we simply override their id:

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_ok" />

<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_cancel" />
</merge>

We have created a flexible and easy to maintain custom view that generates an efficient view hierarchy:

The resulting hierarchy is simple and efficient

The <merge /> tag is extremely useful and can do wonders in your code. However, it suffers from a couple of limitation:

  • <merge /> can only be used as the root tag of an XML layout

  • When inflating a layout starting with a <merge />, you must specify a parent ViewGroup and you must set attachToRoot to true (see the documentation of the inflate() method)

In the next installment of Android Layout Tricks you will learn about ViewStub, a powerful variation of <include /> that can help you further optimize your layouts without sacrificing features.

Download the complete source code of this example.

Wednesday, February 25, 2009

Android Layout Tricks #2: Reusing layouts

Android comes with a wide variety of widgets, small visual construction blocks you can glue together to present the users with complex and useful interfaces. However applications often need higher level visual components. A component can be seen as a complex widget made of several simple stock widgets. You could for instance reuse a panel containing a progress bar and a cancel button, a panel containing two buttons (positive and negative actions), a panel with an icon, a title and a description, etc. Creating new components can be done easily by writing a custom View but it can be done even more easily using only XML.

In Android XML layout files, each tag is mapped to an actual class instance (the class is always a subclass of View.) The UI toolkit lets you also use three special tags that are not mapped to a View instance: <requestFocus />, <merge /> and <include />. The latter, <include />, can be used to create pure XML visual components. (Note: I will present the <merge /> tag in the next installment of Android Layout Tricks.)

The <include /> does exactly what its name suggests; it includes another XML layout. Using this tag is straightforward as shown in the following example, taken straight from the source code of the Home application that currently ships with Android:

<com.android.launcher.Workspace
android:id="@+id/workspace"
android:layout_width="fill_parent"
android:layout_height="fill_parent"

launcher:defaultScreen="1">

<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
<include android:id="@+id/cell3" layout="@layout/workspace_screen" />

</com.android.launcher.Workspace>

In the <include /> only the layout attribute is required. This attribute, without the android namespace prefix, is a reference to the layout file you wish to include. In this example, the same layout is included three times in a row. This tag also lets you override a few attributes of the included layout. The above example shows that you can use android:id to specify the id of the root view of the included layout; it will also override the id of the included layout if one is defined. Similarly, you can override all the layout parameters. This means that any android:layout_* attribute can be used with the <include /> tag. Here is an example:

<include android:layout_width="fill_parent" layout="@layout/image_holder" />
<include android:layout_width="256dip" layout="@layout/image_holder" />

This tag is particularly useful when you need to customize only part of your UI depending on the device's configuration. For instance, the main layout of your activity can be placed in the layout/ directory and can include another layout which exists in two flavors, in layout-land/ and layout-port/. This allows you to share most of the UI in portrait and landscape.

Like I mentioned earlier, my next post will explain the <merge />, which can be particularly powerful when combined with <include />.

Tuesday, February 24, 2009

Android Layout Tricks #1

The Android UI toolkit offers several layout managers that are rather easy to use and, most of the time, you only need the basic features of these layout managers to implement a user interface. Sticking to the basic features is unfortunately not the most efficient way to create user interfaces. A common example is the abuse of LinearLayout, which leads to a proliferation of views in the view hierarchy. Every view, or worse every layout manager, you add to your application comes at a cost: initialization, layout and drawing become slower. The layout pass can be especially expensive when you nest several LinearLayout that use the weight parameter, which requires the child to be measured twice.

Let's consider a very simple and common example of a layout: a list item with an icon on the left, a title at the top and an optional description underneath the title. Here is what such an item looks like:

Simple list item

To clearly understand how the views, one ImageView and two TexView, are positioned with respect to each other, here is the wireframe of the layout as captured by HierarchyViewer:

Wireframe of the simple list item

Implementing this layout is straightforward with LinearLayout. The item itself is a horizontal LinearLayout with an ImageView and a vertical LinearLayout, which contains the two TextViews. The source code of this layout is the following:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"

android:padding="6dip">

<ImageView
android:id="@+id/icon"

android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"

android:src="@drawable/icon" />

<LinearLayout
android:orientation="vertical"

android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">

<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"

android:gravity="center_vertical"
android:text="My Application" />

<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"

android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application that shows how to use RelativeLayout" />

</LinearLayout>

</LinearLayout>

This layout works but can be wasteful if you instantiate it for every list item of a ListView. The same layout can be rewritten using a single RelativeLayout, thus saving one view, and even better one level in view hierarchy, per list item. The implementation of the layout with a RelativeLayout remains simple:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"

android:padding="6dip">

<ImageView
android:id="@+id/icon"

android:layout_width="wrap_content"
android:layout_height="fill_parent"

android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="6dip"

android:src="@drawable/icon" />

<TextView
android:id="@+id/secondLine"

android:layout_width="fill_parent"
android:layout_height="26dip"

android:layout_toRightOf="@id/icon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"

android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application that shows how to use RelativeLayout" />

<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"

android:layout_toRightOf="@id/icon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="@id/secondLine"
android:layout_alignWithParentIfMissing="true"

android:gravity="center_vertical"
android:text="My Application" />

</RelativeLayout>

This new implementation behaves exactly the same way as the previous implementation, except in one case. The list item we want to display has two lines of text: the title and an optional description. When a description is not available for a given list item, the application would simply set the visibility of the second TextView to GONE. This works perfectly with the LinearLayout implementation but not with the RelativeLayout version:

RelativeLayout and description GONE

RelativeLayout and description GONE

In a RelativeLayout, views are aligned either with their parent, the RelativeLayout itself, or other views. For instance, we declared that the description is aligned with the bottom of the RelativeLayout and that the title is positioned above the description and anchored to the parent's top. With the description GONE, RelativeLayout doesn't know where to position the title's bottom edge. To solve this problem, you can use a very special layout parameter called alignWithParentIfMissing.

This boolean parameter simply tells RelativeLayout to use its own edges as anchors when a constraint target is missing. For instance, if you position a view to the right of a GONE view and set alignWithParentIfMissing to true, RelativeLayout will instead anchor the view to its left edge. In our case, using alignWithParentIfMissing will cause RelativeLayout to align the title's bottom with its own bottom. The result is the following:

RelativeLayout, description GONE and alignWithParentIfMissing
RelativeLayout, description GONE and alignWithParentIfMissing

The behavior of our layout is now perfect, even when the description is GONE. Even better, the hierarchy is simpler and because we are not using LinearLayout's weights it's also more efficient. The difference between the two implementations becomes obvious when comparing the view hierarchies in HierarchyViewer:

LinearLayout vs RelativeLayout

Again, the difference will be much more important when you use such a layout for every item in a ListView for instance. Hopefully this simple example showed you that getting to know your layouts is the best way to learn how to optimize your UI.

Labels

'hungry' (1) "O" (1) (press (1) [N8/C7/C6/E7]apps (140) [N8/C7/C6/E7]games (169) $10 Off (1) $15 Rush Tickets (1) $50 Million (1) 1110V (1) 12 Days of Christmas (1) 12 seconds (1) 148apps (1) 1490LMT (1) 1950s. vintage advertising (1) 1955 (1) 2008 (1) 2009 Season (1) 2011 (1) 24/7 Wall Street (1) 3-D (1) 30th Anniversary (1) 319 Bowery (1) 3d checkers (1) 3D Compass Plus (1) 3G iPhone (30) 40cozy (1) 4445 Bash (1) 4ft12m (1) 4th of July (1) 50s (2) 5Inch (1) 6Volt (1) 70s (1) 7200mAh (1) 802.11n (1) 80s (4) 8Ounce (1) A Delicate Balance (1) A Long and Winding Road (1) A R Gurney (2) A Raisin in the Sun (1) A Rural Tragedy (1) A Stripper's History (1) A1185 (2) Aaron Copland (1) Aaron Tveit (1) ABC (5) About Last Night (1) about.com (1) academy awards (1) Academy of Music (1) Access Copyright (2) Accessories (12) Accordian Orchestra (1) ACE Awards (1) Ace Tennis (1) Aceh Recipes (3) acquire (1) acquisition (1) acquisitions (7) across (1) Acrylic (1) action (214) actor scholarship (1) ad sales (9) ad:edit (3) Adam Feldman (1) Adam Monley (1) address labels (1) Adjustable (1) Administration (1) AdMob (1) adobe (3) Adriana Lima (1) Adults (1) advance (1) adventure (247) advertisers (5) Advertising (17) affortable clothing (1) afp (1) Africa (1) ageekspot (1) Agnes De Mille (1) aim (1) Airport (1) Al Hirschfeld Theatre (1) Alan Ziter (1) alarm (2) Alberta (1) alert (1) Algerian Recipes (14) Ali (1) Alice Ripley (1) Alina Vacariu (1) all iphone wallpapers (2) all natural (1) all weird news (1) alliphonewallpapers (4) Allison Schulnik (1) AllLocking (1) allrecipes (1) almond bark (1) almond toffee (1) Almonds (1) alphabet blocks (1) AluminumSteel (1) Alvin Epstein (1) Amato Opera (1) amazon (3) AMC (1) america (1) American Symphony Orchestras (1) American Voices New Play Institute (1) Amherst (1) Amy Freed (1) Amy J. Carle (1) Anatomy (1) Ancestral Voices (1) anchor free (1) anchovies porridge (1) Ancient (1) Anders Cato (1) Andres (1) Android (126) Android 1.5 (15) Android 1.6 (10) Android 2.0 (3) Android 2.1 (2) Android 2.2 (2) Android 2.3 (1) Android 2.3.3 (1) Android 3.0 (2) Android Central (1) Android Developer Challenge (19) Android Developer Phone (2) Android Market (8) Angela Lansbury (1) angelina jolie (1) Angels in America (1) Animal Crackers (1) Anna Kournikova (1) Anna Russell (1) Anne Gottleb (1) Anne Undeland (1) Annie Get Your Gun (2) anniversaries (6) Anniversary (1) Announcements (39) announces (1) Antec (1) Anthony Amato (1) Antiques (1) Anton Kuerti (1) aposTouch (1) app craver (3) app shopper (1) app store (16) Appetizer (2) Appetizers (148) apple (515) apple apple iphone school (2) apple case (1) apple cider (1) apple crisp (1) apple insider (2) Apple iPhone Developer Conference (1) apple muffins (1) apple orchards (1) apple picking (1) apple tell (3) appleinsider (1) apples (2) application (277) Applications (201) applique shirts (1) Applying (1) appointed (1) appointment (23) appointments (11) appoints (1) Apps (26) apps for samsung wave (3) appstore (6) appulous (1) appventcalendar (1) aquacalendar.sisx (1) archives (1) Area Stage (1) arena (1) Arena Stage (10) around me (1) ars technica (6) Art (5) Art Basel Miami Beach (1) art collector (1) art direction (12) Art Miami (1) art of the iphone (1) Arthur Fiedler (1) Articles (28) artistic statistics (2) artists (2) arts (6) Arts amendment (1) Arts America (3) arts and crafts (3) Arts Boston (2) arts funding (2) Arts Grants (1) Arts Journal (2) Arts Journal Poll (1) Artstix (1) artwork (3) ashlees boutique (2) ashley simpson (1) ashley tisdale (1) ASME (2) association publishing (1) associtations. Canadian Press (1) AT T (2) Atlanta (2) Atlanta Performs (1) Atlantic Canada (1) Atlantic Journalism Awards (1) Atlantic Magazines Association (1) ATT (26) ATXmATX (1) ATXmATXITX (1) audience (2) audience development (2) audiences (2) audio (20) Audra Blazer (1) August Wilson (1) August: Osage County (1) Austin (1) AusTIX (1) autism (1) Automatic (1) autumn (1) Auxiliary (1) Auxin (1) Avatar (1) Avril Lavigne (1) Awakening (1) awards (23) awards. Western Magazine Awards (1) Awl (1) Ayaan (1) ayam kalasan singapore (1) b-to-b (1) B.C. (1) b2b (2) babes (2) babies (7) babo botanicals (2) baby (3) baby announcements (1) baby care (1) baby clothes (1) baby clothing (4) baby gifts (6) baby items (1) baby names (1) baby products (1) baby shower gift (1) baby showers (4) baby skin care (1) baby toys (1) baby wash (1) back to school (2) back to school lunch box (1) back to school promo (1) background iphone apps (2) Bad Dates (2) Bada (1) Bada Games (1) Bahraini Recipes (10) baked goods (1) baking (2) Baklava (10) Baliwick Repertory (1) ballet trocadero Mass MoCA (3) ballot question (1) Baltimore (1) Banana (3) banana crapes recipe (1) banners (1) Bar Refaeli (1) Barack and Michelle (1) Barack Obama (1) Barbecue (40) barefoot books (10) barefoot in portland (1) bark (1) Barrington Stage (7) Barrington Stage Company (6) Barrymore Theatre (1) Batteries (2) battery (10) BBC (2) beamme (1) bean bags (1) Bean Curd (2) Beatles Love (1) Beckett Estate (1) Beef (9) Beef Recipe (11) beer (1) beer glasses (1) beerbutton (1) Belasco Theatre (1) Belkin (4) Bench (1) Benefit (1) bento boxes (1) bento lunch box (1) Berkshire (2) Berkshire Beat (1) Berkshire Eagle (1) Berkshire Fine Arts (10) Berkshire on Stage (2) Berkshire Theaters (1) Berkshire Theatre Festival (15) Berkshire Theatre Openings (1) Berkshires (7) Berlin Metro (1) bestt free iphone games (2) beta (1) Betsy Dorfman (1) bible (2) Biblica (1) bibs (3) big top (1) Bill Irwin (1) Bill's Casino (1) Billion (1) billion dollar movies (1) Billy Holiday (1) bing (1) birds (1) birthday (1) birthday parties (1) birthdays (1) Biscuit (1) bivinteractive (1) bizjournals (1) Black (5) black eyed peas (1) black friday (1) black pepper (1) black pepper beef saos fried chicken (1) black pepper chicken cook (1) black pepper sauce seafood (1) Blackberry (39) Blackout (1) Blades (1) Blithe Spirit (1) Blockbuster (2) blocks (1) bloggers (1) Blogging (10) blogs (5) blorge (4) Blue Man Group (1) Bluegrass (1) bluetooth (8) Bluray (2) Bob Dylan (1) Bob Marley (1) Bob Merrill (1) Bog of Cats (1) bolt (1) bon cherry (1) Bon Jovi (1) bonjour family (1) books (5) Bosch (1) Bostix (1) Boston (6) Boston Ballet (1) Boston Center for the Arts (2) Boston MA (1) Boston Pops (2) Boston Symphony Orchestra (2) Boston theatre scene (1) Boston.com (1) boutique (1) boutique clothing (1) box.net (1) boy clothing (1) Brad Steele (1) Brand (1) Brandeis trustees (1) Brandeis University (4) branding (5) Braodway (1) bread (1) bread making (1) Bread recipes (4) Breakfast (2) breakfast for dinner (1) breakfast menu (1) breakfast recipes (1) Brian Dennehy (3) brian hogan (1) Brief (1) Britain (1) British artist (1) Broadway (17) Broadway discount (2) Broadway Discounts (1) Broadway League (1) Broadway revival (2) Broadway show (1) Broccoli (3) broken sculpture (1) Brooklyn (1) Brooklyn Museum (1) brought (1) brownies n butterflies (5) browser (19) Browsing (1) Bruce Jordan (1) Bruce Springsteen (1) BSO (4) BTF PLAYS (1) bubur gurih (1) bubur kacang ijo (1) bubur sukabumi (1) Bucheel (1) Buchel (2) budget (1) budget eating (1) budget recipes (1) burp cloths (2) business (1) business apps (1) business cards (1) Business Info (11) business insider (2) business week (1) business wire (1) busy (1) butterflies (1) Butterfly (1) butterfly mobiles (2) butterfly orb (3) butterfly wings (1) Buxton (1) c (1) C-R Productions (1) Cabaret (2) Cabaret Grimm (1) Cabbage (3) Cable (1) cadiwompus (2) Cake Traditional Fermentation (1) Calabarock (1) calculator (2) Caleb Hiliadis (1) Calling (2) Calvin Gentry (1) Camelot (1) camera (12) Canada Post (2) Canada Council (1) Canada Magazine Fund (1) Canada Periodical Fund (5) Canadian Geographic (1) Canadian Heritage (2) Canadian Journalism Foundation (1) Canadian Online Publishing Awards (1) Canadian Writers Group (2) Cancellation (1) canning (1) cardigans (1) Caretaker (1) Carla Gugino (2) Carnegie (1) Carnegie Hall (2) Carnival (1) Carolann Patterson (1) Carole Feuerman (1) Carole King (1) Caroline or Change (1) Carousel (1) Carrot (2) carrot juice (1) carrot puree (1) Carter (1) cartoon wallpapers (1) cartoons (1) Cashew nut (1) cats (2) cbc (2) cbs (1) cbs4 (1) CD (2) celebrities (1) Cell Phone (1) Cell Phone blocker (1) Cell Phone News (31) Center (1) CenterHTPC (1) Chad Allen (3) Challenge (1) Chandra Wilson (1) Change (1) channel web (1) Charger (1) Charity (1) Charles Giuliano (3) Charles Playhouse (1) Charles Randolph-Wright (1) Charlie Ergen (1) charlie's soap (1) charlotte con mahlsdorf (1) Charlotte St. Martin (1) chat (56) chat rooms (1) cheap iphone (1) Cheese (1) Cherish the Ladies (1) Cheryl Tweedy (2) chess with friends (1) Chicago (4) Chicago Musical (2) Chicken (35) Chicken Recipe (33) chicken tomato sauce (1) Chickory (1) childhood (34) children (17) children's shows (2) childrens art (1) Childrens books (2) childrens clothing (2) childrens cooking (1) childrens toys (1) chili dipping chicken (1) chili sauce fried chicken (1) Chinese Food (3) chinese worker (1) chocolate (5) Chris Anderson (1) chris pirillo (1) Chris Thile (1) Christine Ebersole (1) christmas (6) Christmas Carol (1) Christmas Desserts (30) christmas eve (1) Christmas Mains (8) Christmas Show (1) Christmas Sides (12) christmas specials (1) Christmas trees (1) Christopher (1) Chronicle (1) cio (1) Circle of theatres (2) Circulation (15) Cirebon Recipes (1) Cirque bug show (1) Cirque du Soleil (6) Citroen Osee (1) City of Pittsfield (1) Civilization (1) Clark Art Institute (2) classical music (2) CLB Media (1) cleaning (1) Cleveland (2) Clock (1) clocks (1) closes (1) closures (8) clothes (2) cnet (10) cnn money (1) Code Day (4) coffee (2) Cohoes (1) Cohoes Music Hall NY (1) cold (1) Colin Lane (1) Collection (1) collective bargaining (1) Collectors (1) Colonial Theatre (4) Colonial Theatre Pittsfield (6) color splash (1) colorful ecosystem (1) colour (1) CoMA (1) comfort food (3) comics (1) Commonwealth Opera Northampton (1) company (1) compatible (1) competitions (1) completes (1) components (1) Computer (2) Computer and Accessories (34) computer world (1) computers (1) Concepts (1) concert halls (1) Conde Nast (2) Cond� Nast (1) Conference Shakespeare Theatre Association (3) conferences (2) congress (1) Connect (1) Connecticut (1) consolidation (1) consumer reports (1) consumerist (1) Consumers (1) contemporary art (2) content-sharing (1) contests (2) contract-free (4) controlling diet (1) controversy (1) Cookbook (1) cooked meat (1) cookies (6) cooking (4) cooking for kids (7) Cool Stuff (1) cool tricks (4) Copley Square (1) copy paste (1) copyright (5) Coriander (1) coriander salad (1) Corn (3) cost of cable satellite (1) costs (1) costumes (2) coupons (3) courtesans (1) Couscous (2) covers (6) cowgirl chocolates (4) Crab (2) craft fairs (1) craft finds (1) crafts (5) crape (1) crayon wallets (1) crazy mike apps (1) Creamy Carrot and Orange Soup (1) create (1) creative clusters (1) creativity (2) Criss Angel Believe (1) crochet hats (1) crocheting (1) Crowns (1) crunch deal (1) crunch gear (1) csas (1) CSME (3) csn office furniture (1) csn stores (2) CT Ovo (1) Cucumber (5) Cucumber Recipe (1) cucumber salad (1) cucumber salmon salad (1) Cucumber with Chili Shrimp Paste (1) cultofmac (1) Cultural Alliance (1) cultural magazines (1) cultural nonprofits (1) Cultural Workforce Forum (1) culture (3) cupcakes (1) Curry (2) custom clothing (1) custom painting (1) custom publishing (1) customer service (1) cydia (2) dailytech (73) dali decals (2) Dame Edna tickets (1) Damien Hirst (1) Damn Yankees (1) dance (2) danica patrick (1) Daniel (1) Daniel Radcliffe (1) Danielle Lloyd (1) Dashboard (1) data (3) David A. Ross (1) David Adkins (1) David Alan Anderson (1) David Beditz (1) David Bryan (1) David Finkle (1) David Mamet (1) David Morse (1) David Rabe (1) David Shapira (1) Dayton (1) deal or no deal (1) deals (2) death (1) debuts (1) decade (1) deception (1) declaration (1) decorating (1) Delay (1) deluxe designs (2) demographics (1) denise milani (1) Dennis Hopper (1) departures (5) design (17) designer (1) designer fabrics (1) Desire Under Elms (1) Desire Under the Elms (2) Desmond Nani Reese (1) Dessert (7) Desserts (106) desserts on the cheap (1) Developer Days (1) Developer Labs (3) Developer profiles (4) developers (2) Developmental (1) deviant art (1) Diagnosed (1) Diane Paulus (1) dictionary (5) Did You Know 3.0 (1) diet recipe (1) digital (23) dinner recipes (1) direct mail (2) Dirty Dancing (1) discount seats (1) Discount tickets (26) discounted tickets (3) discounts (1) Disease (1) disease outbreaks (1) Dish (2) Dish Network (2) dishonest Ticketmaster (1) disney (6) distribution (1) do it yourself (1) documentaries (1) documentary filmmaker (1) dogs (1) DollHouse (1) Donal McCann (1) Donald Strachey (1) Donizetti (1) Doug McLenna (1) Doug Wright (1) doughnut muffins (1) downeast basics (1) downgrading (1) download music hutch (1) downloads (3) Downtown (1) dragon ball z (1) drawing (1) DREAM Act (1) dress up (1) drinking (1) drivetrain (1) dropbox (2) Duracell (1) dv2000 (1) dv2200 (1) dv6000 (1) dv6100 (1) DVD (1) DVDs (1) e entertainment (1) e-book (12) e-books (3) e-media (1) e-readers (2) Ear (1) East Berlin (1) East Haddam (2) East Java Recipes (4) easter (1) Easter candy (1) easy cheezy (1) easy cooking porridge (1) ebay (2) Ebb (1) eco friendly baby (1) Economy (1) econsultancy (1) ECTACO (1) Edition (2) editorial (10) Edmonton (1) education (1) Edward Albee (1) Egg Recipe (5) Eggplant (1) Eggs (5) Egyptian Recipes (68) Einstein (1) El Bosco (1) Elayne P. Bernstein Theatre (1) Elisha Cuthbert (2) Elizabeth Aspenlieder (3) Elyse Sommer (1) email (1) Employing Hope (1) emulator (1) en travesti (1) endowment (2) Eneloop (1) Engines (1) English (1) Entertaining Mr. Sloane (1) entertainment (3) environmental art (1) Equinux (1) Equus (2) Eric Hill (2) erichegwer (1) Ericsson (41) Estragon (1) Etch a Sketch Lite (1) etiquette (1) etsy (19) etsy shops (2) Etty Hillesum (1) Eugene Ionesco (1) Eugene O'Neil (1) European (1) eva longoria (1) eva mendes (1) events (13) Everything (1) Examiner (4) excessive commercials (1) Exit the King (1) expenses (2) experimental film (1) explorer (10) extend (1) Extended (1) Extreme Shepherding (1) eye tricks (1) fabric (1) facebook (3) fact checking (2) fairies (1) fairy house (1) fairy wings (1) Faith (1) Faith Healer (1) Falafel (26) Fall (11) fall clothing (1) family (2) Fandango (1) Faneuil Hall Marketplace (1) Faraday Cage (1) farm baby (1) farmers markets (1) farming (1) farms (1) Fascism (2) Fascist (1) fashion (6) fashion shoot (1) Fashion Show Mall (1) fatboy slim (1) fcc (1) felt (1) felt food (1) fergie (1) ferrari (1) festival (1) feta (1) Fettucine (4) fido (1) fierce mobile content (1) File (1) filipino food recipes (32) film (1) finalists (1) finance (5) FinancePLRcom (1) Financial (4) Fine Art Shipping (1) FINISH (1) Fiona Shaw (1) FIPP (1) firefly confections (2) Firmware (2) firmwares for samsung wave (1) Fish (6) Fish Balls (1) fish dive (1) Fish or Seafood Recipe (21) fish paste dipping (1) FisherPrice (1) flash (16) flashing (1) Flashing Method (1) flashing samsung wave (1) Flasing Tutorial (1) Flea (1) flower backpack (1) flowers (1) flu (1) fm radio (2) fm transmitter (2) fonts (3) football (1) Force (2) forcing (1) format Nokia 6600 (1) fortune magazine (1) Forty Magnolias (1) foxconn (1) Fragmented Orchestra (1) Frame (1) France (2) Franchelle Stewart Dorn (1) Francis X. Curley (1) Francisco (1) Frank Galati (1) Frank Theater (1) fre iphone video recorder (1) Free Beer Glasses Wallpaper (1) Free Ebook (1) free iphone (499) free iPhone 3GS (166) free iphone 4 (15) free iphone applications (12) free iphone apps (154) free iphone coding class (1) free iphone developer university (2) free iphone dock (1) free iphone games (26) free iphone kindle (2) free iphone porn (3) free iphone ringtones (7) free iphone skin (1) Free iPhone Synthesizer (1) Free iPhone tethering (5) Free iPhone Theme (1) free iphone unlock (2) free iphone video recorder (1) free iphone wallpapers (59) free ipod touch (2) free ipod touch apps (3) free mobile video (2) Free Nokia Unlock Codes (1) free phone calls (1) Free Preview Weekend (1) free satellite radio (1) free shipping (2) free sms (3) Free Stuff Online (1) free tv (3) free voice guidance (1) freeappalert (1) freebies (1) freedom (1) freelancers (6) freezer installer (1) Freida Pinto (1) Friction (1) friends (2) Front (1) full house (1) fun with magazines (1) funding (7) fundraising (1) fussy britches (1) future (2) futureshop (1) Fuzzies (1) Gabe Askew (1) Gail Burns (2) Gail Nelson (1) Gail Sez (1) Gala (1) gallery (1) Gallery 51 (1) Galt MacDermot (1) game salad (1) Games (549) games radar (1) Gaming (1) Garden (1) Garden of Earthly Delights (1) gardening (2) Garmin (2) Garmin n�vifone (2) Gary Sinese (1) Gay (1) gearlog (1) gecko (1) geek (1) geek sugar (1) Gendai Games (1) General (13) Gennady Rozhdestvensky (1) genome (1) Geoffrey Rush (1) George Bailey (1) George Hotz (2) Gerald Schoenfeld Theatre (1) Gestures (1) ggiphone (1) Ghosts (1) gift giving (2) gift guide (1) gift sets (1) gifts (5) gigaom (1) Gigotron (1) Gilbert and George (1) Gilbert and Sullivan (1) gilded age (1) Ginger (1) gingerbread house (1) girls (3) Girls Gone Weill (1) Gisele Bundchen (1) giveaway (13) giveaway winner (17) giveaway winners (1) giveaways (98) giveawys (1) giveways (1) gizards fried rice (1) gizmag (2) gizmodo (3) glee gum (4) global (1) Globe and Mail (1) glow iPod (1) go graham go (1) goats (1) Goeff Edgars (1) Goggle (1) Golden Globe (1) Goldstar (1) gonzo (1) good gravy (1) good gravy designs (1) Goodman Theatre (4) Goodspeed Musicals (2) Goodspeed Opera (2) google (14) Google Android (12) google app (1) google books (1) google earth (1) Google I/O (4) google latitude (1) google maps (1) google voice (3) gourds (1) GP952 (1) gps (3) GPS Nokia N9 (1) GPS Nokia N95 (5) Gr?vMe (1) grants (1) Graphic Mania (1) graphics (1) Great (1) Great Quesadilla (1) Greater Washington (1) Greater Washington DC (1) Green Beans (1) green cucumber (1) green pepper sauce chicken (1) Greylock Arts (1) Grilled Quesadillas (1) Grilled Salmon On Naan Bread with Lemon Yogurt (2) Grilling method (1) Grizzly Bear (2) Grocery (1) groundhog day (1) Grouper (1) growing up (4) growth (1) Growth (1) growth charts (1) guacamole (2) guest blogger (3) Guidelines (3) gummies (1) Guthrie Theatre (7) Guys and Dolls (1) gveaways (1) gyanin (1) Hair (1) hair accessories (3) hair clips (1) Hairspray (1) half price tickets (20) halftix (1) halloween (8) halloween 2010 (1) halloween apparel (1) halloween candy (1) halloween recipes (3) handmade (7) handmade toys (3) Happy Days (2) Happy Merry Jolly (1) Harold Pinter (1) Harris Burdick (1) Hartford (1) Hartford CT (1) harvest (2) hate tourists (1) have2p (1) Hawaiian Marketplace (1) Hayden Panettiere (1) HazelMail (1) HD (1) Headset (2) Health (3) Health and Fitness Software (12) health care (1) Healthy (1) healthy snacks (1) healthy cooking (1) healthy eating (6) Healthy Living (22) healthy recipes (2) Heart (1) Heather Robison and Hamish Linklater (1) Heather Woodbury (1) Help for Haiti (2) here films (1) hide and seek (1) Hieronymus Bosch (1) HighLine Ballroom (1) hindi movies (1) hiphone (1) Hirsi (1) History (1) Hitchens (1) hitler (1) hiya luv (1) Hmmm (1) Hmmm... (5) Holiday (5) holiday baking (1) holiday decor (1) holiday fairs (1) holiday feature (2) holiday gift guide (3) holiday gifts (3) Holiday music (2) holiday shopping (1) holidays (8) Holistic (1) Holmes (1) Holocaust (1) Holzer (1) home media magazine (1) home school teacher (1) HomeOffice (1) homeschooling (2) homoerotic (1) horses (1) hospital (1) Hot and Spicy Chicory Recipe (1) hot chili sauce (1) hot cocoa (1) hot fried rice (1) Hot Tix (1) Hotels (32) hotspots (1) Hours (1) hours watching ads (1) hours watching tv (1) Houston (1) how stuff works (1) how to (1) how to cook porridge (1) how to lose weight (1) How-to (22) HP (3) HTC (51) Huawei (14) Hubble (1) Hubbub (1) huffington post (2) Hugh Jackman (1) Hugo Bass (1) hulu (2) Hummus (32) Hundred (1) Hunter Center (1) Hunter Thompson (1) hup (1) hutch mp3 (1) hutch player (1) I Drink the Air Before Me (1) i4u (3) i8910HD/5800/N97/Mini/X6 (435) iad (1) iafrica (1) Ian McKellan (1) Ibsen (1) ice cream (2) ICFC318 (1) iGirl (1) ihound (1) ijiggles (1) illegal (1) illumina (1) illustration (5) ilounge (2) image processing (1) images (1) Imax (1) immigration (1) Imperial Theatre (1) Impressionism (1) In The Heights (1) Inauguration Quartet (1) InCarCables (1) included (1) Included (1) income tax (1) Incredibles (1) independence (1) independent (1) Indexes (1) India (14) Indiaaposs (1) Indian Recipe (3) Indigo (1) Indonesian Food (32) industry associations (4) indy bookstores (2) indy mags (3) infections (1) Inflation (1) info world (2) ingredient of pasta lasagna (1) Inherent Vice (1) innovation (2) Innovators (1) Input (1) Input methods (2) Insect (1) Inside (1) INsight Venture Partners (1) inspiration (1) Inspiron (1) installation (1) installous (1) intel (1) Intents (2) international editions (1) Internet (19) internet news (1) internet radio iphone (1) internships (3) into mobile (2) investigative journalism (2) invitations (1) io2010 (2) Ion blog (1) iPad (10) ipad sdk (1) iphone (519) iphone 21 (1) iphone 3.0 (10) iphone 3g (6) iphone 3g speeds (1) iphone 3gs (7) iphone 3gs problems (3) iphone 3gs video (1) iphone 4 antenna (1) iphone 4 jaialbreak (1) iphone 4 mock (1) iphone 4 problems (1) iphone 4 reactions (1) iphone 4 reception (1) iphone 4g (1) iphone ads (4) iphone alley (2) iphone app demo (1) iphone app review (2) iphone apps (4) iphone apps for parents (1) iphone battery life (1) iphone browser (2) iphone business (1) iphone buzz (1) iphone calendar (1) iphone camera (3) iphone canada (2) iphone carriers (1) iphone class (1) iphone commercial (1) iphone concepts (1) iphone contest (4) iphone contract (1) iphone costume (1) iphone daily (1) iphone data usage (1) iphone delay (1) iphone dev team (4) iphone developer (5) iphone download blog (1) iphone exclusive (1) iphone explode (1) iphone fail (1) iphone fake (1) iphone faq (1) iphone firmware (3) iphone footprint (1) iphone freak (3) iphone games (2) iphone girls (1) iphone gui (2) iphone hack (11) iphone hacks (6) iphone hardware upgrade (1) iphone hosting (1) iphone icons (1) iphone in canada (6) iphone japan (3) iphone joystick (1) iphone kindle (1) iphone language (1) iphone launch (2) iphone leak (3) iphone legal (1) iphone marketing (1) iphone memory (1) iphone mms (5) iphone mod (1) iphone modem (2) iphone monitor (1) iphone movies (1) iphone music apps (2) iphone nano (1) iphone os (11) iphone os 4.0 (1) iphone overheat (1) iphone patent (1) iphone platform (1) iphone predictions (1) iphone problems (2) iphone programming (2) iphone prototype (1) iphone psd (3) iphone radio (2) iphone rumour (7) iphone sales (2) iphone scam (1) iphone sdk (3) iphone security (4) iphone seo (1) iphone sms (1) iphone storage (1) iphone study (1) iphone suicide (1) iphone tethering (2) iphone theme for samsung wave (1) iphone time lapse test (1) iphone tips (1) iphone tracking (1) iphone traffic (1) iphone tv (3) iphone unlock (2) iphone video conferencing (1) iphone wallpapers (2) iphone warranty (1) iphone world (2) iphone worm (2) iphones talk (1) ipod touch (1) ipod touch firmware (1) Ipodmp3 (1) ipodnn (1) ipodtouchfans (1) iporn (2) Iraqi Recipes (14) Islam (2) Islamic (2) iSmashPhone (2) isteam (1) it world (1) It's a Wonderful Life (1) Italian Food (11) italkphone (1) itbusiness (1) iTRAVL (1) itunes (6) iTunes Store (5) itv (1) itwire (1) Itzhak Perlman (1) iZel (1) J Tormey (1) J.S. Bach mandolin (1) Jack Cutmore-Scott (2) Jacob's Pillow Dance (1) jailbreak (14) James and Kim Taylor (1) James Barry (2) James Cameron (1) James Michael Curley (1) James Taylor (2) Jane Hudson (1) Jane Jacobs prize (1) Japan (1) Japanese phones (5) jason chen (1) java (426) Java Apps For Samsung Wave (3) Jay Goode (1) Jaybirds (1) Jayne Atkinson (1) Jcobs Piillow (1) Jean Shepherd (1) Jeffery Self (1) Jehane Noujaim (1) Jehuda Reinharz (2) Jen Davis (1) Jenn Gambatese (1) jenna jameson (1) Jennifer Ellison (1) jennifer lopez (1) Jenny (1) Jepara Recipes (1) Jeremy Irons (1) Jerry Springer (1) Jerry Christakos (1) Jersey Boys (1) jessica alba (2) Jessica Biel (1) jessica simpson (1) jewelry (1) Ji Lee (1) Jim Charles (1) jkontherun (1) Joan Allen (1) Jobathan Epstein (1) Joe Hewitt (1) Joe Thompson (2) Joe Turner's Come and Gone (1) John Barrett (1) John Carmack (1) John Glover (1) John Goodman (1) John Rando (2) John Williams (1) joint ventures (1) Jones (1) joose box (2) joost (2) Jordanian Recipes (124) Joseph Jeffries (1) Joshua Bell (1) Joshua Dean (1) journalism (3) journalismdegree (1) journalist (1) Joyce Theatre (1) Jujamcyn Theatres (1) jukebox musicals (1) Julian Kuerti (2) Juliane Hiam (1) Julianne Boyd (3) July 4th (1) jvc (1) KA (1) Kander (1) kansas city (1) Karen Zacarias (1) Kate Maguire (3) katharine hepburn (1) Katie Johnson Cabaret (1) Katori Hall (1) Katrina Kaif (1) Katy Hill (1) Keeley Hazell (1) Keira Naughton (1) Keith Lockhart (1) Kevin Earley (1) Kevin Duda (1) kevin rose (1) keyboard (8) keylock (13) Kidder Smith (1) kids (10) kids activities (1) kids clothing (2) kids recipes (13) kids room (1) kindergarten (1) Kindle (1) Kingdom (1) Kirk Lynn (1) Kitchens (8) Knickerbocker (1) Knighthood (1) knit hats (1) Know Your Mobile (4) Knowliz (1) Kofta (16) Kooza (2) kristen kruek (1) Kuwaiti Recipes (10) kvj bible audiobook (1) Kweekies (1) LA Stage Allliance (1) la times (1) labels (1) labor day (1) labour-management dispute (2) Lake George Opera (2) Lake Shore Limited (1) Lamb (3) Lamb Recipe (3) Lampung Recipes (1) Language (1) Laptop (4) Larry (1) Larry Murray (10) Las Vegas (2) lasagna (2) latest (1) launches (28) Lauren Worsham (1) le Monde (1) league (1) Leap Year (1) learning toys (1) LEATHER (1) Lebanese Recipes (276) LED Sheep (1) Lee Breuer (1) legal (4) Lenox (4) Lenox MA (1) Les Liaisons Dangereuses (1) LesLiaisons Dangereuses (1) Lets golf 2 (1) Lettuce (3) Lever (1) LG (69) Lie Cheat Steal Fake It (1) life hacker (3) Lifetime (1) light (2) Liion (1) lindsey lohan (1) line extensions (2) Links (1) Lion King (3) Lisa Kron (1) literacy (2) literary journalism (2) Literature (1) Lithium (1) Lithiumion (1) Little Mermaid (3) little princess pea (4) liver fried rice (1) Living (1) Liz Canner (1) local food (1) Local Stations (1) locationbased (1) locker gnome (1) lockout (1) London (2) Long Island (1) Looped (3) Looped Broadway (1) Lorraine Hansberry (1) Los Angeles (1) lose weight article (1) lose weight seminar (1) Lost (1) love (1) loving shop (5) Lowell (1) Lucia di Lammermoor (1) luggage (1) Lumens (1) luna and larrys organic coconut bliss (2) Lunchbox (1) Lunchtime Theatre (1) lux dlx (1) Lyceum Theatre (1) Lynn Harrell (1) Lyric Stage (1) Lyric Stage Company (1) MA (1) MA Ovo (1) Ma561ga (2) Ma561lla (2) mabels labels (2) Mabou Mines (1) mac and cheese (1) mac daddy world (1) mac daily news (1) Mac Haydn Theatre (1) mac mega site (1) mac rumors (2) mac user (1) mac world (1) macapper (1) Macbook (2) Maccarone (1) Maclean's (8) macmost (1) Macsimum News (1) macworld (2) Mad Men (1) Madama Butterfly (1) made in the usa (1) Magawards (1) magazine business (1) magazine industry (2) magazine profiles (1) Magazine Publishers of America (1) magazines (1) Magazines Canada (8) magens bay designs (4) MagNet (2) MagsBC (2) Mahaiwe Performing Arts Center (3) Mail (1) mailing rates (1) Main Course (37) Main Dishes (312) Main Squeeze Orchestra (1) Mainboards (1) Majestic Theatre (1) make money (3) make stable money (1) make use of (1) make your own kits (1) Malay Food (2) Maluku Recipes (2) Mamma Mia (1) management (3) Manitoba magazines (2) manolo blahnik (1) mapquest (1) Marceau (1) Marcel (1) Marco Brambilla (1) Margaret Gibson (1) Margot Kidder (1) Marilyn Abrams (1) Marisa Jara (1) Marissa Miller (1) Mark Favermann (1) market watch (2) Marketing (1) marketing 101 (1) marketing pilgrim (1) Marsha Mason (1) Martha Clarke (1) Martin Lawrence (1) Mary Poppins (2) masakan itali (1) mashable (6) Mass Moca (5) Mass Moca and Jacobs Pillow (1) Mass MoCA Film Series (1) Massachusetts (1) match.com (1) Matt Wade (1) Matte (1) Matthew Lombardo (1) Maude Mitchell (1) Maureen McGovern (1) Maverick Arts (1) May Poppins (1) Mayor (1) mcafee (1) mccain (1) MCLA (1) Measure for Measure (1) meat sauce (1) Media (3) media planners (1) Media Post Group (1) Meego (1) megaapp (1) megafart (1) megan fox (1) Melbourne Australia (1) Meltdown (1) memory (8) Men Fake Foreplay (1) Meredith Corporation (1) Merrimack Repertory Theatre (1) Mesothelioma (1) messenger (5) Met Player (1) metrics (1) Metropolitan Opera (2) mexican (2) mexican food (2) Micahael Greif (1) Michael Arden (1) michael jackson (1) Michael Patrick Thornton (1) Michael Rush (2) Michelle Candice (1) mickey mouse (1) Micro (1) Microsoft (10) microsoft office (1) Midnight (1) MidTower (1) Mike Dugan (1) million (1) mime (1) Minetta Lane (1) mini shopper clutch (1) Minneapolis (2) mint (2) Miranda Hope Shea (1) miranda im (1) Miranda Kerr (1) Miscellaneous (72) ML03B (1) MLM Films (1) mobile (3) mobile appy (1) Mobile Browsers (1) mobile crunch (1) mobile devices (1) mobile entertainment (2) mobile flash (2) Mobile games (5) Mobile Internet (2) Mobile operators (39) Mobile phone Tips (1) Mobile Phone Tricks (1) mobile phones tricks (1) mobile wire (1) mobiles (1) moconews (1) Mohawk Theatre (1) Molly Smith (2) mom's group (1) Momix (1) Monica Bellucci (1) Month (1) Moonwalking (1) Moroccan Recipes (194) mossberg (1) Most Expensive (26) Most Expensive Foods (14) most wanted app (1) Motally (2) motherhood (3) mothering (1) mothers (3) motion sensitive ad (1) Motorola (96) Motorola Unlock (1) Motorola Unlock code (1) Mount (1) Mountain View (1) Mouse King (1) Movie Gallery (1) movies (1) MP3 (1) MPA (1) MS500BLK (1) muffins (3) Mullins Center (1) Multi;oader (1) Multilingual (1) multimedia (1) multitasking (1) Munich (1) Murray (1) Museum (1) Mushroom (2) music (37) music video (2) Musical (2) Muslims (1) my artsy baby (2) MYOPENPC (1) MySpace (1) Mystere (1) N8/C7/C6/E7 (330) Naan Bread (1) Naional Summit on Arts Journalism (1) names (1) Nancy Coyne (1) naptime (1) Nashville (1) nasi goreng ati (1) nasi goreng kampung (1) nasi goreng lezat (1) nasi goreng panas (1) nasi sambal goreng (1) natasha thomas (1) Nathan Lane (1) National Endowment Arts (3) national film board of canada (1) National Magazine Awards (1) National Post (1) National Summit Arts Journalism (1) natural baby (1) natural gum (1) Navigation (1) navigation app (1) Navigator (1) nbc (2) nbc bay area (1) NDK (6) NDrive (1) NDrive Germany (1) NDrive Italy (1) NDrive Poland (1) NDrive Portugal (1) NEA (3) Nearly (1) NEH (1) neowin (2) nes (1) Netflix (3) New York City (1) new england (1) new hampshire (6) new iphone (5) New Jersey (1) New Nokia (3) New Orleans (1) New Rep (1) New Victory Theatre. String ensemble (1) New Year (1) New York (1) New YOrk City Ballet (2) New York Drama Critics Circle (1) New York Times (1) newborn skin care (1) Newly (1) News (13) newsoxy (2) newspapers (7) newsstand (3) newsstands (1) Nexflix (1) Next Issue Media (1) Next to Normal (3) Nexus One (2) nic (1) nice porridge (2) Nicholas (1) Nicholas Martin (1) Nicholas Nickleby (1) Nick Cordero (1) nicole richie (1) Nicole Scherzinger (1) nielson survey (1) Night Cries (1) Nikki Sanderson (1) Nimbuzz (2) no contracts (1) no credit card (1) No on 1 (1) Noel Coward (1) nokia (440) Nokia 5230 (1) Nokia 5530 (496) Nokia 5800 (499) Nokia C2-01 (1) Nokia C3 (2) Nokia C7 (1) Nokia E5 (1) Nokia E63 (12) Nokia E7 (5) Nokia E71 (1) Nokia E90 (2) Nokia N8 (53) Nokia N9 (1) Nokia N900 (4) Nokia N95 8GB (2) Nokia N96 (1) Nokia N97 (495) Nokia Siemens Networks (25) Nokia WP7 (1) Nokia X2-01 (1) Nokia X6 (495) Nokia X7-00 (2) Noodles (5) Nora (1) North Adams (8) North Adams Transcript (1) North Strip (1) North Sumatra (3) northeast (2) Northern (1) Not enough memory (1) Notebook (1) Notebook/laptop (3) notecards (5) NOW (1) NTT DoCoMo (1) nude (1) nursery (2) nursery art (5) Nutcracker (1) ny times (1) obama (3) obituary (4) Obopay (1) octopus (1) Of Mice and Men (1) office (7) Ohio (1) Oklahoma (1) Olympia Dukakis (1) OMDC (2) OMMA (1) On the Other Hand Death (1) onesies (2) online (8) ootunes (1) open mic (1) Open source (1) OpenGL ES (2) Opera (11) opera mini (2) Optimization (10) orabelle baby (3) Orange (16) orange puree (1) organic bath products (1) organic coconut bliss (1) organic foods (2) Organization (1) organizers (1) Orgasm Inc (1) Oriental Recipe (4) Original Cast Recording (1) original painting (1) Orion Society (1) oscar (1) oscars (1) Other mobile phone brands (37) Other Recipes (43) others (4) Out at Arena (1) Ovo (2) Ovo review (1) PA3534U1BRS (1) Pablo Schreiber (2) pac man (1) packaging (1) Packs (1) paddington bear (1) Pagagninni (1) Pageant (1) paid iphone apps (7) painting (1) paintings (1) Palestinian Recipes (116) Palm (1) Pam McKinnon (1) Pamela Anderson (1) Pamela Kurstin (1) pandora (1) Pangea Day (2) Pantech (6) PAPA Center (1) paper (3) paper collage (1) paper goods (5) paper products (2) paperwhites (1) Paprika (1) parenting (1) Paris 1890 Unlaced (1) paris hilton (1) parties (1) partnerships (1) Party (1) party planning (1) Pasta (13) pasta fagioli soup (1) pasta lasagna (1) Pasta Recipe (19) Pastries (20) patent infringement (2) patterns (1) Patti LuPone (1) Pavilion (1) Pay What You Can (1) pay-for-use (3) Paypal (1) pc magazine (2) pc world (4) PCEverything (1) pcmag (2) pcworld (4) PDA (1) PDA / Pocket PC (47) PDQ Bach (1) peach crisp (1) peaches (1) peeps (1) Penne (7) Pennsylvania arts cultural tax (1) pepsi (1) Performance Lab (1) performances (1) performing arts (2) Peter Gil-Sheridan (1) Peter Pan (1) Peter Schaeffer (1) pets (1) PetSafe (1) Phantom of the Opera (1) Pharos (1) Philadelphia Cltural Alliance (1) Philadelphia Cultural Alliance (1) Philadelphia Orchestra (2) Philip LaPointe (1) Philip Sneed (1) Philips (8) Phone (1) Phone App (25) Phone cell (9) Phone cell;Bluetooth (1) Phone Schematics and Service (2) Phone Theme (7) PhoneEthernetCoaxial (1) phones review (1) photo (16) photographs (2) photography (5) photos (1) photoshop (1) PIB (1) Pierre Boulez (1) pillow pets (1) Pineapple (1) pink (1) Pinocchio (1) Pinterland (1) Pipes (1) piracy (1) pitch engine (1) Pittsburgh Arts Council (1) Pittsfield (2) PivotPlug (1) Pizza (1) Platinum (1) play (1) play.com (1) player (24) playing with fiber (2) PMB (1) Poached Salmon - Green Been with Cheesy Dills Sauce (1) Pocket (1) pocket gamer (8) Pocket Mime (1) policy (1) pom wonderful (1) pomegranate juice (1) ponche (1) pop culture (1) Popcorn (1) PopSci (2) porn star (1) Portable (2) Portfolio (1) Portion (1) position (1) Potatoes (3) Power (2) power lines (1) powerful (1) Prairie Home Companion (1) Prawn (1) PreCharged (1) preschool (1) presents (1) President (1) President Broadway (1) President Obama (2) press conference (1) press freedom (1) pricing (1) primakow (1) print-to-web (6) printing (4) privacy (1) Privacy Policy (1) Private Lives (1) Prize (1) Proactiv (1) problems (1) product reviews (1) production (2) professional development (13) programming (2) projections (1) promo codes (1) promotion (11) promotions (16) proseo (1) Protection (1) Protector (1) ProtectorDual (1) Protectors (1) Protest (1) Protests (1) prweb (2) Psychiatric (1) Psychiatry (1) ptmoney (1) Public (1) Public Theatre (1) Publick Theatre (2) publishers (2) publishing (1) publishing models (2) Pudding (1) pumpkin chocolate chip cookies (1) pumpkin soup (1) pumpkins (4) puppies (1) Purplera1n (1) pussycat dolls (1) puzzle (161) Pwn2Own (1) pwnage (2) Qatar Recipes (8) Qatayef (4) Quebecor (2) Quebecor Media (1) Queer as Folk (1) quesadillas (1) quick online tips (1) Quick Search Box (1) quicken (1) quickpwn (2) quilting (1) quilts (2) quiz (1) quote (43) R (1) Racine's (1) racing (21) Radio (1) Radio City (1) Ralph Fiennes (1) Ramadan Desserts (12) Ramadan Recipes (46) Randy Harrison (6) Rangers (2) rapid (1) raspberry (1) raspberry cream cheese heart tarts (1) Rattle (1) Reaching (1) reader-written content (1) Reader's Digest (1) readership (2) reading (5) readwriteweb (1) real business (1) reasons (1) Rechargeable (1) recipe to lose weight (1) recipes (13) Recovery Act (1) Red Bull (1) Red Chamber (1) redesigns (7) redeyechicago (1) redmond pie (1) reference books (1) relaunches (5) release (5) release) (1) religion (1) Remembering (1) Remote (1) remote car start (1) remove app (1) Rental (1) replace (1) Replacement (1) research (17) resep mushroom (1) resep pasta (1) Resolution (1) Resources (1) restaurant food (1) Restaurants (14) retro (2) reveals (1) Reviews (8) Rice (12) rice porridge (1) rice recipe (2) Richard Box (1) Richard Griffiths (1) Richard Kornberg (1) Richard Ooms (1) Richie DuPont (1) Rickrolled (1) rights (3) rim (1) ringtone (6) Ringtones (1) RN873 (1) RNC (1) Rob Melrose (1) Rob Ruggiero (4) Robert Belushi (1) Robert Falls (1) Robert Frost (1) Robertson case (3) Rodgers and Hammerstein (1) Roger Rees (1) rogers (2) Rogers Consumer Publishing (1) Rolling Stone (1) room decor (1) Rose Art Museum (4) roselyn sanchez (1) Roundabout Theatre (1) rpg (66) rujak manis (1) rujak pedas (1) rujak pengantin (1) rujak ulek (1) Rupert Everett (1) Rush PR News (1) Rushdie (2) RV02BW (1) Ryan Lammer (1) S60v3 (111) s8500XXJID (1) s8500XXJK1 (1) safari (2) Salad (52) salaries (1) Sally Wingert (1) Salman (2) Salmon (4) salmon yogurt (1) Salsa Fresca (1) Salted Fish (1) Saltimbanco (1) Sam Worthington (1) sambel ayam goreng (1) sambel goreng ayam (1) sambel terasi (1) Sample code (1) samsung (119) Samsung Omnia HD (21) Samsung Wave Apps (4) Samsung Wave Free Apps And Games (1) Samsung Wave Games (1) Samsung wave theme (3) Samuel Beckett (3) San Diego Theatre League (1) Sandisk (3) Sandwiches (10) sandys baking memories (3) santa claus (2) Sanyo (2) sara jean underwood (1) Sarah Taylor (1) Saratoga (1) Sasha Anawalt (1) Sassy (1) Satanic (2) satwaves (2) Sauce - Relish - Dressing (12) sauce for fried chicken (1) Saudi Recipes (64) Save Me (1) saving money (4) Scale (1) scare machine (1) Scarlett Johansson (1) school (2) science (2) scones (1) Scopes Trial (1) scott tissue (1) scrapbooking (2) screensaver (29) SDK updates (19) second (1) Secondstage (1) Secret (1) security (9) sepia (1) September (1) Serena (1) Series (3) Serrano (1) services (1) Sesame (1) sew-fantastic (2) sewing (2) sexy iphone app (1) sexy iphone wallpaper (29) Shaker Hymn (1) Shakespeare (2) Shakespeare and Company (7) Shakespeare Company (3) Shakespeare Theatre Association of America (1) Sharp (1) Shawarma (6) Shazam (3) Shear Madness Boston (1) Sheath (1) Sherlock (1) shipments (1) shipping (1) shoes (1) shooting (97) shop feature (1) shopping (2) shopping handmade (1) Shorts (1) shotgun house (1) shout me loud (1) show closings (1) showcase (1) Showcase Mall (1) shows (2) Shrek the Musical (1) Shrimp (2) Shubert Theatre (1) siblings (1) sickness (1) Side Dish (4) sidelines (1) Silly (1) silly bands (1) SilverStone (1) SILVERSTONE (1) sim card (1) sim-free iphone 3gs (1) simon blog (1) simple fried rice (1) simple making porridge (1) simple salmon yogurt (1) simple sauce chicken (1) single copies (5) sirius buzz (1) sirius radio (4) Sirloin (1) sisters (3) skincare (1) skype (5) slacker radio (1) slash gear (1) Slate (1) sling box (1) sling player (2) slumdog millionaire (1) SMART (1) smart canuck (1) smart house (1) smart phones (1) Smarter (1) smartphone (4) smartphones (1) Smithereens (1) smoking (1) smoothies (1) sms chat 3rd (1) sms chat download (1) sms messenger (1) Snack (5) Snafu (1) Snapper (2) Snapshots (1) snaptell (1) snow (3) snowday (1) snowman (1) snowstorms (1) snuggie (1) soap (1) soccer (1) Social (2) social gaming (1) social media (3) social networking (1) Sofia Vergara (1) softpedia (5) Software (25) Solid Sound Festival Tickets (1) Solo Recipes (1) Solution (1) song (1) Sonim (2) sonos (1) Sony Ericsson (90) Sony Ericsson Satio (26) sorry (1) Sounds (1) Soup (5) South Kalimantan (1) south park (1) South Sulawesi (1) Southwest Night (1) SPAC (1) Spaghetti (4) SpeakEasy Stage (2) Special (1) special effects (1) special interest publications (1) Spectacular (1) Speech Input (1) speeddate (1) Spelling Bee (1) Spike Jones (1) Spinach (5) Spirituality (1) sponsors (1) Sport (1) sports (65) sports theatre (1) spotify (3) Spring (3) Sprint (2) squarespace (1) Squid (5) St. Ann's Warehouse (1) STAA (2) Stage (1) Stage West (1) stagehands (2) Stainless (1) Standard (3) stanford (5) starbucks (1) started (1) stay at home moms (1) Steak Recipe (3) Steel (2) Stephen (2) Stephen Petronio Dance (1) Steppenwolf (5) Stereo (1) Sterling and Francine Clark Art Institute (1) steve jobs (3) Steven Wright (1) still (1) stimulus bill (1) Stir-fry (8) Stock (2) Stockbridge (2) stocking stuffers (2) Story (1) Stratford Shakespeare Festival (1) strawberries (1) stream games (1) stream videos (1) Street (1) strike (3) student class 2009 (1) subscriptions (4) subscriptons (1) summer (8) Summer 2009 (1) sun (1) Superhero (1) superman (1) Supply (1) Surefire (1) Surge (3) SURGE (1) Survival of Serena (1) Susan Sarandon (1) sustainable (1) swap (1) sweaters (1) sweet chili dipping (1) sweet grass farm (1) sweet orange soup (1) Sweet Potatoes (2) symantec (1) symbian (321) symbian music player (1) symbian^3 (341) Symphony Hall (1) Symphony Orchestra (1) sync iphone (1) synthtopia (2) Syrian Recipes (150) System (1) T Mobile (11) T-Mobile (8) T. Rowe Price Group (1) tables (1) tablets (4) Tag Sale (1) Tagines (32) Take Me Out (1) Takeovers (2) Tallulah Bankhead (2) Tanglewood (3) tap tap revenge (4) tarts (1) Tate (1) Taylor (1) Taylors North Adams (1) tea (1) tech crunch (3) tech dirt (1) tech flash (1) tech mixer (1) tech radar (1) tech worlds (1) techburgh (1) techeblog (1) Technical (2) Technical Requirements (1) technology (7) TED Conference (2) Teehan+lax (1) Tehra Dark Warrior (1) Tel Aviv (1) television (2) television watching (1) Tenderloin (1) Tennessee (1) tent (1) terminal (1) terrible twos (1) Terry Teachout (1) tethering (1) Texas (1) text messaging (1) Text-to-Speech (1) texting (1) tg daily (1) Thaindian News (1) thank you cards (1) thanksgiving (1) The Acting Company Romeo and Juliet (4) the actor (1) The Bach Project (1) The Colonial Theatre (1) the grand horizontals (1) the guardian (1) The Intelligent Homosexual�s Guide to Capitalism and Socialism with a Key to the Scriptures (1) The Intelligent Homosexual�s Guide to Capitalism and Socialism with Key to the Scriptures (1) the iphone blog (12) The Ladies Man (1) The Lt Dan Band (1) The Metropolitan Opera (2) The Mikado (1) The Performanace Lab (1) The Producers (2) the register (1) The Salon (1) the standard (1) the story tree (1) The Tempest (2) The Waypoint (1) The Wrestling Patient (1) the www blog (1) theater (2) Theater Collective (1) Theater Development Fund (1) Theaters (1) Theatre (3) Theatre Bay Area (1) theatre dance music (3) theatre district (1) Theatre Etiquette (1) theatre music dance (1) theatres and concert halls (1) TheatreWorks (1) Theme / Wallpapers (10) Themes (66) theremin (1) Theresa Reebeck (2) third (1) third-party iphone applications (1) This Wonderful Life (1) Thomas (1) Thomas Pynchon (1) Thosiba (1) Three (1) Ticket Agents (1) ticket brokers (1) ticket buying iPhone (1) ticket discounts (3) ticket prices (1) ticket sales (1) ticket scalpers (1) Ticketmaster (2) Ticketplace (1) Ticketron (1) tickets (4) tila tequila (2) Tim O'Brien (1) Time Out New York (1) times of india (1) Tina Landau (1) Tina Packer (3) Tips (13) Tix 4 Tonight (1) Tix Bay Area (1) TKTS (3) TL2EW6 (1) tmc net (1) To Kill a Mockingbird (1) toddler clothing (1) toddlers (3) toffee (1) Tofu (1) Tom Coburn (1) Tom Morris (1) Tomato (4) tomtom iphone app (1) Tony Kushner (2) Tony Kushner premiere (1) Tony Kushner quotes (1) Tony Simotes (1) Toonwarz (1) top 10 (1) top iphone apps (2) top iphone news (2) Topics (3) Toronto (1) Toronto Life (1) toronto star (1) torrent freak (4) torrents (2) Tortilla (1) Toshiba (5) touch (464) touch arcade (1) touchterm (1) toward (1) Tower (1) Toxic Avenger the Musical (1) Toxie (1) toys (4) Tracey Moffatt (1) tractor (1) Tracy Jan (1) trade (2) Traffic (1) train timetable (1) Training Ground for Democracy (1) transactions (2) Transcontinental (5) Transcontinental Media (1) Translator (1) Transparent (1) transvestite (1) trash talk (1) travel diary (1) traveling with kids (2) treats (2) Trent (1) Treo | Centro (14) trick or treat (1) trips (2) trocks (2) truffles (1) Trusted (1) trusted reviews (1) trustees (1) tuaw (2) tubestick (1) tunecast (1) Tunisian Recipes (2) Tupelo Press (1) Turkey (1) Tutorials (12) tuttles barn (1) tutu (1) tutus (2) tv (2) tv.com (1) Tweet (1) tweet baby designs (2) tweetdeck (1) Twilight (1) twilight movie (1) Twitpay (1) twitter (7) Two Keys (1) two little tots (1) Two Weeks (1) TwoDisc (2) Typeapos (1) UAE Recipes (12) ubergizmo (1) Uiq (6) Uiq3 (32) ultrasn0w (2) Underground Atlanta (1) union (2) Union Square (1) unions (1) United (1) Universal (1) universe (1) unlimited data (1) Unlock code for mobile phones (1) unlocked iphone (1) Updates (1) upgrading samsung (1) Ursula Mayes (1) US Senate (1) USA (1) usa today (2) USC (1) User Interface (17) ustream (1) utorrent (2) vacations (1) valentines day (7) valentines day recipes (1) Valerie Harper (3) vandalism (1) vanessa hudgens (1) Vanessa Redgrave (1) vator (1) vcard (1) Veckatimest (1) Vegetable Recipe (9) vegetarian (1) Ventfort Hall (1) Venture (1) verisign (1) Verizon (20) Verses (2) Version (1) Vertu (1) Veterans (1) Victims (1) video (11) videoegg (1) Videos (152) Vietnam Plays (1) Vince Gatton (2) Vincent Delaney (1) vintage (2) vintage clothing (1) vintage living (1) vintage pearl (1) violin (1) viral video (1) Virgin Mobile (1) viruses (1) vision (1) visual (1) visual arts (2) Vivian Matalon (1) Vladimir (1) vlingo (1) Vodafone (4) voicemail (1) voip (1) Vonage (1) vote (2) Waiting for Godot (5) Waiting for Godot Opera (1) wal-mart (1) Wales (1) wall decals (1) wall decor (1) wall street journal (6) Wallet (1) wallpaper (1) Wallpapers (3) Wallpapers for samsung wave (1) wallswitch (5) WalMart (2) WalMart Economy (1) War on Terror (2) Washington (2) Washington DC (1) washington post (2) wayback (1) weather (1) web (3) web and print (45) web burning (1) web date info (1) web resources depot (1) wedding apps (1) wedding invites (1) weekends (1) weelicious (1) Weigh (1) West Java (3) West Kalimantan (1) West Nusa Tenggara (1) West Sumatra (2) Western Magazine Awards (2) Weston Playhouse (1) wett giggles (1) What May Fall (1) WhatTheFont (1) White (2) White House (1) white iphone (1) white noise (1) whole grain (1) Why Buy Used Cars (1) Widget (26) Widgets (43) wifi (25) Wilco Mass MoCA Tickets (1) William Coe Bigelow (1) William Finn (1) William Gibson (1) Williamstown Theatre (2) Williamstown Theatre Festival (3) windows 98 (1) Windows Mobile (13) windows mobile 7 theme (2) Windows phone 7 theme (2) winners (3) winnie the pooh (1) Winter (2) wired (6) wirless and mobile news (1) wirless week (1) Wolfenstein (1) Women of Will (1) women's clothing (1) wool (2) word of mouth (1) Word on the Street (1) World (2) world view (23) World Wide Developer Conference (5) worldaposs (1) Writer 1272 (1) writers (2) Writers' Union (1) writing (1) WTEN (2) WWDC (5) X284G (1) xbiznewswire (1) xltblog (1) xm radio (4) xmas (1) XPERIA (43) xscale (1) Yahoo (6) Yasmnina Reza (1) year in review (1) yellowsnow (1) Yo Yo Ma (1) yoga (1) yogurt (2) Yogyakarta Recipes (3) You Tube (1) youmail (1) Young Frankenstein (1) youtube (4) yowza (1) zdnet (4) Zeitgeist (1) zoss designs (3) Zumanity (1) ZumoDrive (1) Zurin Villlanueva (1)