diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 8dcdb7163d7ee18e4a19a2b196d4175e7ebc96f4..ba01be5bfcd1ad5e5581f9f0089c6eb7aaed7674 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -40,6 +40,10 @@
 			android:name=".android.invitation.AddContactActivity"
 			android:label="@string/add_contact_title" >
 		</activity>
+		<activity
+			android:name=".android.messages.ConversationActivity"
+			android:label="@string/messages_title" >
+		</activity>
 		<activity
 			android:name=".android.messages.ConversationListActivity"
 			android:label="@string/messages_title" >
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 79236a39603272358460928e4e20ae5da0d13a27..df481efc4dd7d18c1cdef0b7fddb741de288109a 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -11,8 +11,9 @@
 	<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="contact_last_connected">Last connected &lt;br /&gt; %1$s</string>
 	<string name="add_contact_button">New Contact</string>
+	<string name="search_button">Search</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>
 	<string name="wifi_not_available">Wi-Fi is not available on this device</string>
@@ -39,7 +40,7 @@
 	<string name="interfering">This could mean that someone is trying to interfere with your connection.</string>
 	<string name="contact_added">Contact added</string>
 	<string name="enter_nickname">Please enter a nickname for this contact:</string>
+	<string name="done_button">Done</string>
 	<string name="messages_title">Messages</string>
 	<string name="compose_button">New Message</string>
-	<string name="done_button">Done</string>
 </resources>
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactComparator.java b/briar-android/src/net/sf/briar/android/contact/ContactComparator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6495bf631051e67b2e2f1d23f5e77da4844c8735
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/contact/ContactComparator.java
@@ -0,0 +1,13 @@
+package net.sf.briar.android.contact;
+
+import java.util.Comparator;
+
+class ContactComparator implements Comparator<ContactListItem> {
+
+	static final ContactComparator INSTANCE = new ContactComparator();
+
+	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
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 c1c00ad104d34f4a92a6225a589e210d357681b2..a6e7e3f32133dbf091c4b20b71f13534e019b6e1 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
@@ -31,7 +31,6 @@ import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout.LayoutParams;
@@ -52,7 +51,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 	@Inject @DatabaseExecutor private Executor dbExecutor;
 	@Inject private ConnectionRegistry connectionRegistry;
 
-	private ArrayAdapter<ContactListItem> adapter = null;
+	private ContactListAdapter adapter = null;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -67,6 +66,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 		// Give me all the width and all the unused height
 		list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f));
 		list.setAdapter(adapter);
+		list.setOnItemClickListener(adapter);
 		layout.addView(list);
 
 		Button addContactButton = new Button(this);
@@ -167,7 +167,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 					boolean conn = connectionRegistry.isConnected(c.getId());
 					adapter.add(new ContactListItem(c, conn));
 				}
-				adapter.sort(ContactListItem.COMPARATOR);
+				adapter.sort(ContactComparator.INSTANCE);
 			}
 		});
 	}
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
index 1849d60ede19774a6eab6c344d97a04a568bcd9f..1521492c9360d2e3ab9f9433c74a2eb36633f578 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
@@ -8,17 +8,21 @@ import java.util.ArrayList;
 
 import net.sf.briar.R;
 import android.content.Context;
+import android.content.res.Resources;
 import android.text.Html;
 import android.text.format.DateUtils;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
 
-class ContactListAdapter extends ArrayAdapter<ContactListItem> {
+class ContactListAdapter extends ArrayAdapter<ContactListItem>
+implements OnItemClickListener {
 
 	ContactListAdapter(Context ctx) {
 		super(ctx, android.R.layout.simple_expandable_list_item_1,
@@ -47,13 +51,13 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 		layout.addView(name);
 
 		TextView connected = new TextView(ctx);
-		connected.setTextSize(12);
+		connected.setTextSize(14);
 		connected.setPadding(5, 0, 5, 0);
 		if(item.isConnected()) {
 			connected.setText(R.string.contact_connected);
 		} else {
-			String format = ctx.getResources().getString(
-					R.string.contact_last_connected);
+			Resources res = ctx.getResources();
+			String format = res.getString(R.string.contact_last_connected);
 			long then = item.getLastConnected();
 			CharSequence ago = DateUtils.getRelativeTimeSpanString(then);
 			connected.setText(Html.fromHtml(String.format(format, ago)));
@@ -62,4 +66,9 @@ class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 
 		return layout;
 	}
+
+	public void onItemClick(AdapterView<?> parent, View view, int position,
+			long id) {
+		// FIXME: Hook this up to an activity
+	}
 }
diff --git a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
index 47747e3a1bc267c2e85d4aace6af8129294f2766..cba805e863df13b0d69393146c8559d9b6c836d2 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListItem.java
@@ -1,16 +1,12 @@
 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;
+	final Contact contact;
 	private boolean connected;
 
 	ContactListItem(Contact contact, boolean connected) {
@@ -37,12 +33,4 @@ class ContactListItem {
 	void setConnected(boolean connected) {
 		this.connected = connected;
 	}
-
-	private static class ItemComparator implements Comparator<ContactListItem> {
-
-		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
diff --git a/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java
new file mode 100644
index 0000000000000000000000000000000000000000..651f719bea7206758654ad6febe2224df33e182d
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/AscendingHeaderComparator.java
@@ -0,0 +1,19 @@
+package net.sf.briar.android.messages;
+
+import java.util.Comparator;
+
+import net.sf.briar.api.db.PrivateMessageHeader;
+
+class AscendingHeaderComparator implements Comparator<PrivateMessageHeader> {
+
+	static final AscendingHeaderComparator INSTANCE =
+			new AscendingHeaderComparator();
+
+	public int compare(PrivateMessageHeader a, PrivateMessageHeader b) {
+		// The oldest message comes first
+		long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+		if(aTime < bTime) return -1;
+		if(aTime > bTime) return 1;
+		return 0;
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..1782a6ceb140bbf2a43498805fe559e2681a06f3
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
@@ -0,0 +1,156 @@
+package net.sf.briar.android.messages;
+
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.widget.LinearLayout.VERTICAL;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+
+import java.util.Collection;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import net.sf.briar.R;
+import net.sf.briar.android.BriarActivity;
+import net.sf.briar.android.BriarService;
+import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.api.ContactId;
+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.PrivateMessageHeader;
+import net.sf.briar.api.db.event.DatabaseEvent;
+import net.sf.briar.api.db.event.DatabaseListener;
+import net.sf.briar.api.db.event.MessageAddedEvent;
+import net.sf.briar.api.db.event.MessageExpiredEvent;
+import android.content.Intent;
+import android.os.Bundle;
+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.ListView;
+
+import com.google.inject.Inject;
+
+public class ConversationActivity extends BriarActivity
+implements OnClickListener, DatabaseListener {
+
+	private static final Logger LOG =
+			Logger.getLogger(ConversationActivity.class.getName());
+
+	private final BriarServiceConnection serviceConnection =
+			new BriarServiceConnection();
+
+	@Inject private DatabaseComponent db;
+	@Inject @DatabaseExecutor private Executor dbExecutor;
+
+	private ContactId contactId = null;
+	private ConversationAdapter adapter = null;
+
+	@Override
+	public void onCreate(Bundle state) {
+		super.onCreate(null);
+
+		Intent i = getIntent();
+		int id = i.getIntExtra("net.sf.briar.CONTACT_ID", -1);
+		if(id == -1) throw new IllegalStateException();
+		contactId = new ContactId(id);
+		String contactName = i.getStringExtra("net.sf.briar.CONTACT_NAME");
+		if(contactName == null) throw new IllegalStateException();
+		setTitle(contactName);
+
+		LinearLayout layout = new LinearLayout(this);
+		layout.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+		layout.setOrientation(VERTICAL);
+		layout.setGravity(CENTER_HORIZONTAL);
+
+		adapter = new ConversationAdapter(this);
+		ListView list = new ListView(this);
+		// Give me all the width and all the unused height
+		list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f));
+		list.setAdapter(adapter);
+		list.setOnItemClickListener(adapter);
+		layout.addView(list);
+
+		Button composeButton = new Button(this);
+		composeButton.setBackgroundResource(0);
+		composeButton.setLayoutParams(new LayoutParams(MATCH_PARENT,
+				WRAP_CONTENT));
+		composeButton.setCompoundDrawablesWithIntrinsicBounds(0,
+				R.drawable.content_new_email, 0, 0);
+		composeButton.setText(R.string.compose_button);
+		composeButton.setOnClickListener(this);
+		layout.addView(composeButton);
+
+		setContentView(layout);
+
+		// Listen for messages being added or removed
+		db.addListener(this);
+		// Bind to the service so we can wait for the DB to be opened
+		bindService(new Intent(BriarService.class.getName()),
+				serviceConnection, 0);
+		// Load the message headers from the DB
+		reloadMessageHeaders();
+	}
+
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		db.removeListener(this);
+		unbindService(serviceConnection);
+	}
+
+	public void onClick(View view) {
+		// FIXME: Hook this button up to an activity
+	}
+
+	public void eventOccurred(DatabaseEvent e) {
+		if(e instanceof MessageAddedEvent) {
+			if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
+			reloadMessageHeaders();
+		} else if(e instanceof MessageExpiredEvent) {
+			if(LOG.isLoggable(INFO)) LOG.info("Message removed, reloading");
+			reloadMessageHeaders();
+		}
+	}
+
+	private void reloadMessageHeaders() {
+		dbExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					// Wait for the service to be bound and started
+					serviceConnection.waitForStartup();
+					// Load the message headers from the database
+					Collection<PrivateMessageHeader> headers =
+							db.getPrivateMessageHeaders();
+					if(LOG.isLoggable(INFO))
+						LOG.info("Loaded " + headers.size() + " headers");
+					// Update the conversation
+					updateConversation(headers);
+				} catch(DbException e) {
+					if(LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				} catch(InterruptedException e) {
+					if(LOG.isLoggable(INFO))
+						LOG.info("Interrupted while waiting for service");
+					Thread.currentThread().interrupt();
+				}
+			}
+		});
+	}
+
+	private void updateConversation(
+			final Collection<PrivateMessageHeader> headers) {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				adapter.clear();
+				for(PrivateMessageHeader h : headers)
+					if(h.getContactId().equals(contactId)) adapter.add(h);
+				adapter.sort(AscendingHeaderComparator.INSTANCE);
+			}
+		});
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..6720b08dd7c683b6f5c71c465ddee6283fe59877
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java
@@ -0,0 +1,71 @@
+package net.sf.briar.android.messages;
+
+import static android.graphics.Typeface.BOLD;
+import static android.view.Gravity.CENTER;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.widget.LinearLayout.HORIZONTAL;
+import static java.text.DateFormat.SHORT;
+
+import java.util.ArrayList;
+
+import net.sf.briar.R;
+import net.sf.briar.api.db.PrivateMessageHeader;
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+import android.widget.TextView;
+
+class ConversationAdapter extends ArrayAdapter<PrivateMessageHeader>
+implements OnItemClickListener {
+
+	ConversationAdapter(Context ctx) {
+		super(ctx, android.R.layout.simple_expandable_list_item_1,
+				new ArrayList<PrivateMessageHeader>());
+	}
+
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent) {
+		PrivateMessageHeader item = getItem(position);
+		Context ctx = getContext();
+		LinearLayout layout = new LinearLayout(ctx);
+		layout.setOrientation(HORIZONTAL);
+		layout.setGravity(CENTER);
+
+		ImageView star = new ImageView(ctx);
+		star.setPadding(5, 5, 5, 5);
+		if(item.getStarred())
+			star.setImageResource(R.drawable.rating_important);
+		else star.setImageResource(R.drawable.rating_not_important);
+		layout.addView(star);
+
+		TextView subject = new TextView(ctx);
+		// Give me all the unused width
+		subject.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
+				1));
+		subject.setTextSize(14);
+		if(!item.getRead()) subject.setTypeface(null, BOLD);
+		subject.setText(item.getSubject());
+		layout.addView(subject);
+
+		TextView date = new TextView(ctx);
+		date.setTextSize(14);
+		date.setPadding(5, 0, 10, 0);
+		long then = item.getTimestamp(), now = System.currentTimeMillis();
+		date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
+		layout.addView(date);
+
+		return layout;
+	}
+
+	public void onItemClick(AdapterView<?> parent, View view, int position,
+			long id) {
+		// FIXME
+	}
+}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationComparator.java b/briar-android/src/net/sf/briar/android/messages/ConversationComparator.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcf0b179991c325eb1ed87942245f9d9a0d57824
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationComparator.java
@@ -0,0 +1,16 @@
+package net.sf.briar.android.messages;
+
+import java.util.Comparator;
+
+class ConversationComparator implements Comparator<ConversationListItem> {
+
+	static final ConversationComparator INSTANCE = new ConversationComparator();
+
+	public int compare(ConversationListItem a, ConversationListItem b) {
+		// The item with the newest message comes first
+		long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+		if(aTime > bTime) return -1;
+		if(aTime < bTime) return 1;
+		return 0;
+	}
+}
\ No newline at end of file
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
index ebdd646567003bb92e480ae5547e49a7e1059dbf..9188d61770359bd36a30c8e69fbf261fdb639c2f 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -37,7 +37,6 @@ import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout.LayoutParams;
@@ -58,7 +57,7 @@ implements OnClickListener, DatabaseListener {
 	@Inject @DatabaseExecutor private Executor dbExecutor;
 	@Inject private MessageFactory messageFactory;
 
-	private ArrayAdapter<ConversationListItem> adapter = null;
+	private ConversationListAdapter adapter = null;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -73,6 +72,7 @@ implements OnClickListener, DatabaseListener {
 		// Give me all the width and all the unused height
 		list.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT, 1f));
 		list.setAdapter(adapter);
+		list.setOnItemClickListener(adapter);
 		layout.addView(list);
 
 		Button composeButton = new Button(this);
@@ -110,16 +110,23 @@ implements OnClickListener, DatabaseListener {
 							LOG.info("Inserting fake contact and messages");
 						// Insert a fake contact
 						ContactId contactId = db.addContact("Carol");
-						// Insert some messages to the contact
+						// Insert some fake messages to and from the contact
 						Message m = messageFactory.createPrivateMessage(null,
-								"First message's subject",
+								"First message's subject is quite long to test"
+								+ " line wrapping and stuff like that",
 								"First message's body".getBytes("UTF-8"));
 						db.addLocalPrivateMessage(m, contactId);
+						db.setReadFlag(m.getId(), true);
 						db.setStarredFlag(m.getId(), true);
-						Thread.sleep(2000);
+						Thread.sleep(1000);
 						m = messageFactory.createPrivateMessage(m.getId(),
-								"Second message's subject",
+								"Second message's subject is short",
 								"Second message's body".getBytes("UTF-8"));
+						db.receiveMessage(contactId, m);
+						Thread.sleep(1000);
+						m = messageFactory.createPrivateMessage(m.getId(),
+								"Third message's subject is also short",
+								"Third message's body".getBytes("UTF-8"));
 						db.addLocalPrivateMessage(m, contactId);
 						db.setReadFlag(m.getId(), true);
 					}
@@ -198,7 +205,7 @@ implements OnClickListener, DatabaseListener {
 				adapter.clear();
 				for(ConversationListItem i : sortHeaders(contacts, headers))
 					adapter.add(i);
-				adapter.sort(ConversationListItem.COMPARATOR);
+				adapter.sort(ConversationComparator.INSTANCE);
 			}
 		});
 	}
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
index f0ef7ec79ff4f41a1b4c1bf01caae5a464813c78..50a8a574a0084419cc82f1178bbee5a57084072e 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListAdapter.java
@@ -12,16 +12,20 @@ import java.util.ArrayList;
 
 import net.sf.briar.R;
 import android.content.Context;
+import android.content.Intent;
 import android.text.format.DateUtils;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout.LayoutParams;
 import android.widget.TextView;
 
-class ConversationListAdapter extends ArrayAdapter<ConversationListItem> {
+class ConversationListAdapter extends ArrayAdapter<ConversationListItem>
+implements OnItemClickListener {
 
 	ConversationListAdapter(Context ctx) {
 		super(ctx, android.R.layout.simple_expandable_list_item_1,
@@ -72,4 +76,13 @@ class ConversationListAdapter extends ArrayAdapter<ConversationListItem> {
 
 		return layout;
 	}
+
+	public void onItemClick(AdapterView<?> parent, View view, int position,
+			long id) {
+		ConversationListItem item = getItem(position);
+		Intent i = new Intent(getContext(), ConversationActivity.class);
+		i.putExtra("net.sf.briar.CONTACT_ID", item.getContactId().getInt());
+		i.putExtra("net.sf.briar.CONTACT_NAME", item.getName());
+		getContext().startActivity(i);
+	}
 }
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java
index 711329ec3bfdb302121854bb4411f0c1899e0513..24b2e63a44c12544c84077da0a3d19a015820ba5 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListItem.java
@@ -1,48 +1,51 @@
 package net.sf.briar.android.messages;
 
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 
 import net.sf.briar.api.Contact;
+import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.PrivateMessageHeader;
 
 class ConversationListItem {
 
-	static final Comparator<ConversationListItem> COMPARATOR =
-			new ItemComparator();
-
-	private static final Comparator<PrivateMessageHeader> HEADER_COMPARATOR =
-			new HeaderComparator();
-
-	private final Contact contact;
-	private final List<PrivateMessageHeader> headers;
+	private final ContactId contactId;
+	private final String name, subject;
+	private final long timestamp;
+	private final int length;
 	private final boolean read, starred;
 
 	ConversationListItem(Contact contact, List<PrivateMessageHeader> headers) {
 		if(headers.isEmpty()) throw new IllegalArgumentException();
-		Collections.sort(headers, HEADER_COMPARATOR);
-		boolean read = false, starred = false;
+		contactId = contact.getId();
+		name = contact.getName();
+		Collections.sort(headers, DescendingHeaderComparator.INSTANCE);
+		subject = headers.get(0).getSubject();
+		timestamp = headers.get(0).getTimestamp();
+		length = headers.size();
+		boolean allRead = false, anyStarred = false;
 		for(PrivateMessageHeader h : headers) {
-			read &= h.getRead();
-			starred |= h.getStarred();
+			allRead &= h.getRead();
+			anyStarred |= h.getStarred();
 		}
-		this.contact = contact;
-		this.headers = headers;
-		this.read = read;
-		this.starred = starred;
+		read = allRead;
+		starred = anyStarred;
+	}
+
+	ContactId getContactId() {
+		return contactId;
 	}
 
 	String getName() {
-		return contact.getName();
+		return name;
 	}
 
 	String getSubject() {
-		return headers.get(0).getSubject();
+		return subject;
 	}
 
 	long getTimestamp() {
-		return headers.get(0).getTimestamp();
+		return timestamp;
 	}
 
 	boolean getRead() {
@@ -54,28 +57,6 @@ class ConversationListItem {
 	}
 
 	int getLength() {
-		return headers.size();
-	}
-
-	private static class HeaderComparator
-	implements Comparator<PrivateMessageHeader> {
-
-		public int compare(PrivateMessageHeader a, PrivateMessageHeader b) {
-			// The newest message comes first
-			long aTime = a.getTimestamp(), bTime = b.getTimestamp();
-			if(aTime > bTime) return -1;
-			if(aTime < bTime) return 1;
-			return 0;
-		}
-	}
-
-	private static class ItemComparator
-	implements Comparator<ConversationListItem> {
-
-		public int compare(ConversationListItem a, ConversationListItem b) {
-			// The item with the newest message comes first
-			return HEADER_COMPARATOR.compare(a.headers.get(0),
-					b.headers.get(0));
-		}
+		return length;
 	}
 }
diff --git a/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java b/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a8032f0987bed60d75d76d15635734917175685
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/messages/DescendingHeaderComparator.java
@@ -0,0 +1,19 @@
+package net.sf.briar.android.messages;
+
+import java.util.Comparator;
+
+import net.sf.briar.api.db.PrivateMessageHeader;
+
+class DescendingHeaderComparator implements Comparator<PrivateMessageHeader> {
+
+	static final DescendingHeaderComparator INSTANCE =
+			new DescendingHeaderComparator();
+
+	public int compare(PrivateMessageHeader a, PrivateMessageHeader b) {
+		// The newest message comes first
+		long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+		if(aTime > bTime) return -1;
+		if(aTime < bTime) return 1;
+		return 0;
+	}
+}
\ No newline at end of file