diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index e56b8652ad0ec137eb3e2e7598ae9b54b7d32c8d..468defb0a0cf2550e89af0c2bf1b90cf495f1a76 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -6,6 +6,8 @@
 	<string name="contact_list_button">Contacts</string>
 	<string name="quit_button">Quit</string>
 	<string name="contact_list_title">Contacts</string>
+	<string name="contact_connected">Connected</string>
+	<string name="contact_last_connected">Last connected &lt;br /&gt; %s</string>
 	<string name="add_contact_button">Add a contact</string>
 	<string name="add_contact_title">Add a Contact</string>
 	<string name="same_network">Briar can add contacts via Wi-Fi or Bluetooth. For security reasons, you must be face-to-face to add someone as a contact. To use Wi-Fi you must both be connected to the same network.</string>
diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
index c6db489c9340f4e32bf8256c36f8b963c5bb0214..ee63c84bb5144bec6823ec11c1c7b8c4d9b53873 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -20,8 +20,8 @@ import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
 import android.widget.ProgressBar;
-import android.widget.RelativeLayout.LayoutParams;
 
 public class HomeScreenActivity extends BriarActivity
 implements OnClickListener {
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
index c08ecde48851b9a974f610387db6b76147b68b21..ec57d89e0d60756bbdccf9778c7b41c1b8eb3e1c 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
@@ -7,9 +7,7 @@ import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
@@ -25,6 +23,7 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.db.event.ContactAddedEvent;
+import net.sf.briar.api.db.event.ContactRemovedEvent;
 import net.sf.briar.api.db.event.DatabaseEvent;
 import net.sf.briar.api.db.event.DatabaseListener;
 import net.sf.briar.api.transport.ConnectionListener;
@@ -37,8 +36,8 @@ import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
 import android.widget.ListView;
-import android.widget.RelativeLayout.LayoutParams;
 
 import com.google.inject.Inject;
 
@@ -47,7 +46,6 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 
 	private static final Logger LOG =
 			Logger.getLogger(ContactListActivity.class.getName());
-	private static final ItemComparator COMPARATOR = new ItemComparator();
 
 	private final BriarServiceConnection serviceConnection =
 			new BriarServiceConnection();
@@ -67,10 +65,10 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 		layout.setOrientation(VERTICAL);
 		layout.setGravity(CENTER_HORIZONTAL);
 
-		adapter = new ArrayAdapter<ContactListItem>(this,
-				android.R.layout.simple_expandable_list_item_1,
-				new ArrayList<ContactListItem>());
+		adapter = new ContactListAdapter(this);
 		ListView listView = new ListView(this);
+		listView.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT,
+				1f));
 		listView.setAdapter(adapter);
 		layout.addView(listView);
 
@@ -85,14 +83,13 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 
 		setContentView(layout);
 
-		// Listen for database events and connection events
+		// Listen for contacts being added or removed
 		db.addListener(this);
+		// Listen for contacts connecting or disconnecting
 		connectionRegistry.addListener(this);
-
-		// Bind to the service
+		// Bind to the service so we can wait for the DB to be opened
 		bindService(new Intent(BriarService.class.getName()),
 				serviceConnection, 0);
-
 		// Load the contact list from the DB
 		reloadContactList();
 
@@ -105,9 +102,12 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 					IBinder binder = serviceConnection.waitForBinder();
 					((BriarBinder) binder).getService().waitForStartup();
 					if(LOG.isLoggable(INFO)) LOG.info("Service started");
-					// Insert a couple of fake contacts
-					db.addContact("Alice");
-					db.addContact("Bob");
+					Collection<Contact> contacts = db.getContacts();
+					if(contacts.isEmpty()) {
+						// Insert a couple of fake contacts
+						db.addContact("Alice");
+						db.addContact("Bob");
+					}
 				} catch(DbException e) {
 					if(LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -134,6 +134,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 
 	public void eventOccurred(DatabaseEvent e) {
 		if(e instanceof ContactAddedEvent) reloadContactList();
+		else if(e instanceof ContactRemovedEvent) reloadContactList();
 	}
 
 	private void reloadContactList() {
@@ -148,11 +149,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 					if(LOG.isLoggable(INFO))
 						LOG.info("Loaded " + contacts.size() + " contacts");
 					// Update the contact list
-					runOnUiThread(new Runnable() {
-						public void run() {
-							updateContactList(contacts);
-						}
-					});
+					updateContactList(contacts);
 				} catch(DbException e) {
 					if(LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -165,14 +162,17 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 		});
 	}
 
-	// UI thread
-	private void updateContactList(Collection<Contact> contacts) {
-		adapter.clear();
-		for(Contact c : contacts) {
-			boolean connected = connectionRegistry.isConnected(c.getId());
-			adapter.add(new ContactListItem(c, connected));
-		}
-		adapter.sort(COMPARATOR);
+	private void updateContactList(final Collection<Contact> contacts) {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				adapter.clear();
+				for(Contact c : contacts) {
+					boolean conn = connectionRegistry.isConnected(c.getId());
+					adapter.add(new ContactListItem(c, conn));
+				}
+				adapter.sort(ContactListItem.COMPARATOR);
+			}
+		});
 	}
 
 	public void contactConnected(final ContactId c) {
@@ -189,37 +189,12 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 				int count = adapter.getCount();
 				for(int i = 0; i < count; i++) {
 					ContactListItem item = adapter.getItem(i);
-					if(item.contact.getId().equals(c)) {
-						item.connected = connected;
+					if(item.getContactId().equals(c)) {
+						item.setConnected(connected);
 						return;
 					}
 				}
 			}
 		});
 	}
-
-	private static class ItemComparator implements Comparator<ContactListItem> {
-
-		@Override
-		public int compare(ContactListItem a, ContactListItem b) {
-			return String.CASE_INSENSITIVE_ORDER.compare(a.contact.getName(),
-					b.contact.getName());
-		}
-	}
-
-	private static class ContactListItem {
-
-		private final Contact contact;
-		private boolean connected; // UI thread
-
-		private ContactListItem(Contact contact, boolean connected) {
-			this.contact = contact;
-			this.connected = connected;
-		}
-
-		@Override
-		public String toString() {
-			return contact.getName() + " (" + connected + ")";
-		}
-	}
 }
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9720ad7710fd7fa4d82680f6ca61a81e8212587
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
@@ -0,0 +1,64 @@
+package net.sf.briar.android.contact;
+
+import static android.view.Gravity.CENTER;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.widget.LinearLayout.HORIZONTAL;
+
+import java.util.ArrayList;
+
+import net.sf.briar.R;
+import android.content.Context;
+import android.text.Html;
+import android.text.format.DateUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+public class ContactListAdapter extends ArrayAdapter<ContactListItem> {
+
+	public ContactListAdapter(Context context) {
+		super(context, android.R.layout.simple_expandable_list_item_1,
+				new ArrayList<ContactListItem>());
+	}
+
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent) {
+		ContactListItem item = getItem(position);
+		Context ctx = getContext();
+		LinearLayout layout = new LinearLayout(ctx);
+		layout.setOrientation(HORIZONTAL);
+		layout.setGravity(CENTER);
+
+		ImageView bulb = new ImageView(ctx);
+		if(item.getConnected()) bulb.setImageResource(R.drawable.green_bulb);
+		else bulb.setImageResource(R.drawable.grey_bulb);
+		bulb.setPadding(5, 0, 5, 0);
+		layout.addView(bulb);
+
+		TextView name = new TextView(ctx);
+		name.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1f));
+		name.setTextSize(18);
+		name.setText(item.getName());
+		layout.addView(name);
+
+		TextView connected = new TextView(ctx);
+		connected.setTextSize(12);
+		connected.setPadding(5, 0, 5, 0);
+		if(item.getConnected()) {
+			connected.setText(R.string.contact_connected);
+		} else {
+			String format = ctx.getResources().getString(
+					R.string.contact_last_connected);
+			long then = item.getLastConnected();
+			CharSequence ago = DateUtils.getRelativeTimeSpanString(then);
+			connected.setText(Html.fromHtml(String.format(format, ago)));
+		}
+		layout.addView(connected);
+
+		return layout;
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..99d2a79fcc707dfc4b6be43eaf24ee4d86f44eac
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
@@ -0,0 +1,49 @@
+package net.sf.briar.android.contact;
+
+import java.util.Comparator;
+
+import net.sf.briar.api.Contact;
+import net.sf.briar.api.ContactId;
+
+// This class is not thread-safe
+class ContactListItem {
+
+	static Comparator<ContactListItem> COMPARATOR = new ItemComparator();
+
+	private final Contact contact;
+	private boolean connected;
+
+	ContactListItem(Contact contact, boolean connected) {
+		this.contact = contact;
+		this.connected = connected;
+	}
+
+	ContactId getContactId() {
+		return contact.getId();
+	}
+
+	String getName() {
+		return contact.getName();
+	}
+
+	long getLastConnected() {
+		return contact.getLastConnected();
+	}
+
+	boolean getConnected() {
+		return connected;
+	}
+
+	void setConnected(boolean connected) {
+		this.connected = connected;
+	}
+
+	private static class ItemComparator implements Comparator<ContactListItem> {
+
+		@Override
+		public int compare(ContactListItem a, ContactListItem b) {
+			return String.CASE_INSENSITIVE_ORDER.compare(a.contact.getName(),
+					b.contact.getName());
+		}
+	}
+}
\ No newline at end of file