diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java
index 95e651bfed31e514f5bfb6da700034d2d454a5fa..aa421875ea340b595a8b8afa073c4b40a34ce797 100644
--- a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java
+++ b/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java
@@ -1,6 +1,8 @@
 package net.sf.briar.android.blogs;
 
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
@@ -18,6 +20,7 @@ import net.sf.briar.android.AscendingHeaderComparator;
 import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.HorizontalBorder;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.Author;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
@@ -57,6 +60,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 	private boolean postable = false;
 	private BlogAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -89,6 +93,11 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		ImageButton composeButton = new ImageButton(this);
@@ -145,6 +154,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 	private void displayHeaders(final Collection<GroupMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.clear();
 				for(GroupMessageHeader h : headers) adapter.add(h);
 				adapter.sort(AscendingHeaderComparator.INSTANCE);
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java
index 36eb0cbd8315fef9e5d54c39acd4eb2dac6ccec3..6bc9d9d58067a31ee03331058c35d3b6a716c012 100644
--- a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java
+++ b/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java
@@ -2,6 +2,8 @@ package net.sf.briar.android.blogs;
 
 import static android.view.Gravity.CENTER;
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.HORIZONTAL;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
@@ -23,6 +25,7 @@ import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.HorizontalBorder;
 import net.sf.briar.android.widgets.HorizontalSpace;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
@@ -63,6 +66,7 @@ OnItemClickListener {
 
 	private BlogListAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 	private ImageButton newBlogButton = null, composeButton = null;
 	private ImageButton manageBlogsButton = null;
 
@@ -86,6 +90,11 @@ OnItemClickListener {
 		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		LinearLayout footer = new LinearLayout(this);
@@ -176,6 +185,8 @@ OnItemClickListener {
 	private void clearHeaders() {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(GONE);
+				loading.setVisibility(VISIBLE);
 				adapter.clear();
 				adapter.notifyDataSetChanged();
 			}
@@ -186,6 +197,8 @@ OnItemClickListener {
 			final Collection<GroupMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				// Remove the old item, if any
 				BlogListItem item = findGroup(g.getId());
 				if(item != null) adapter.remove(item);
@@ -201,6 +214,8 @@ OnItemClickListener {
 	private void displayAvailable(final int available) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.setAvailable(available);
 				adapter.notifyDataSetChanged();
 			}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java
index 2367703939ea5f9daffc5ccdddab2e803205a72f..91385ccd9357887bed85ccfd9ccf98b448cf1151 100644
--- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java
+++ b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java
@@ -15,6 +15,7 @@ import java.util.logging.Logger;
 
 import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
@@ -46,6 +47,7 @@ implements DatabaseListener, OnItemClickListener {
 
 	private ManageBlogsAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -60,7 +62,10 @@ implements DatabaseListener, OnItemClickListener {
 		list.setLayoutParams(MATCH_MATCH);
 		list.setAdapter(adapter);
 		list.setOnItemClickListener(this);
-		setContentView(list);
+
+		// Show a progress bar while the list is loading
+		loading = new ListLoadingProgressBar(this);
+		setContentView(loading);
 
 		// Bind to the service so we can wait for it to start
 		bindService(new Intent(BriarService.class.getName()),
@@ -104,6 +109,7 @@ implements DatabaseListener, OnItemClickListener {
 			final Collection<GroupStatus> available) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				setContentView(list);
 				adapter.clear();
 				for(GroupStatus g : available)
 					adapter.add(new ManageBlogsItem(g));
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 11beeead21994fc57d0fa5c41def98b0791c07e8..32f92293e95e15815704b91ef4bc82e71e353a29 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListActivity.java
@@ -5,6 +5,7 @@ import static android.content.Intent.EXTRA_STREAM;
 import static android.view.Gravity.CENTER;
 import static android.view.Gravity.CENTER_HORIZONTAL;
 import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.HORIZONTAL;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
@@ -26,6 +27,7 @@ import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.invitation.AddContactActivity;
 import net.sf.briar.android.widgets.HorizontalBorder;
 import net.sf.briar.android.widgets.HorizontalSpace;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.Contact;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -43,6 +45,8 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.ListView;
@@ -50,7 +54,8 @@ import android.widget.ListView;
 import com.google.inject.Inject;
 
 public class ContactListActivity extends RoboActivity
-implements OnClickListener, DatabaseListener, ConnectionListener {
+implements OnClickListener, OnItemClickListener, DatabaseListener,
+ConnectionListener {
 
 	private static final Logger LOG =
 			Logger.getLogger(ContactListActivity.class.getName());
@@ -61,6 +66,7 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 	@Inject private ConnectionRegistry connectionRegistry;
 	private ContactListAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 	private ImageButton addContactButton = null, shareButton = null;
 
 	// Fields that are accessed from background threads must be volatile
@@ -80,10 +86,14 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 		// Give me all the width and all the unused height
 		list.setLayoutParams(MATCH_WRAP_1);
 		list.setAdapter(adapter);
-		list.setOnItemClickListener(adapter);
-		list.setVisibility(GONE);
+		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		LinearLayout footer = new LinearLayout(this);
@@ -150,6 +160,8 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 			final Map<ContactId, Long> times) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.clear();
 				for(Contact c : contacts) {
 					boolean now = connectionRegistry.isConnected(c.getId());
@@ -189,6 +201,11 @@ implements OnClickListener, DatabaseListener, ConnectionListener {
 		}
 	}
 
+	public void onItemClick(AdapterView<?> parent, View view, int position,
+			long id) {
+		// FIXME: Hook this up to an activity
+	}
+
 	public void eventOccurred(DatabaseEvent e) {
 		if(e instanceof ContactAddedEvent) loadContacts();
 		else if(e instanceof ContactRemovedEvent) loadContacts();
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 577e569d2052b04dc33287568628e0aa29f2ca66..d20412f307744df57d97383fdcea8dd8d8edda44 100644
--- a/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
+++ b/briar-android/src/net/sf/briar/android/contact/ContactListAdapter.java
@@ -13,15 +13,12 @@ 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.TextView;
 
-class ContactListAdapter extends ArrayAdapter<ContactListItem>
-implements OnItemClickListener {
+class ContactListAdapter extends ArrayAdapter<ContactListItem> {
 
 	ContactListAdapter(Context ctx) {
 		super(ctx, android.R.layout.simple_expandable_list_item_1,
@@ -68,9 +65,4 @@ implements OnItemClickListener {
 
 		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/groups/GroupActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
index dca814895fde5ca466abcb59a6743f75b6e50f5e..0ea0adb590c2f3974cc1f32c80cbc991ed26c83e 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupActivity.java
@@ -1,6 +1,8 @@
 package net.sf.briar.android.groups;
 
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
@@ -18,6 +20,7 @@ import net.sf.briar.android.AscendingHeaderComparator;
 import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.HorizontalBorder;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.Author;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
@@ -56,6 +59,7 @@ OnClickListener, OnItemClickListener {
 	private String groupName = null;
 	private GroupAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -87,6 +91,11 @@ OnClickListener, OnItemClickListener {
 		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		ImageButton composeButton = new ImageButton(this);
@@ -143,6 +152,8 @@ OnClickListener, OnItemClickListener {
 	private void displayHeaders(final Collection<GroupMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.clear();
 				for(GroupMessageHeader h : headers) adapter.add(h);
 				adapter.sort(AscendingHeaderComparator.INSTANCE);
diff --git a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
index fb84b857d734e17abdd2fd1bfa2fe11590116f61..725ea96f669173205793ae554054bde663d8eb70 100644
--- a/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/GroupListActivity.java
@@ -2,6 +2,8 @@ package net.sf.briar.android.groups;
 
 import static android.view.Gravity.CENTER;
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.HORIZONTAL;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
@@ -21,6 +23,7 @@ import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.HorizontalBorder;
 import net.sf.briar.android.widgets.HorizontalSpace;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
@@ -61,6 +64,7 @@ OnItemClickListener {
 
 	private GroupListAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 	private ImageButton newGroupButton = null, composeButton = null;
 	private ImageButton manageGroupsButton = null;
 
@@ -84,6 +88,11 @@ OnItemClickListener {
 		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		LinearLayout footer = new LinearLayout(this);
@@ -171,6 +180,8 @@ OnItemClickListener {
 	private void clearHeaders() {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(GONE);
+				loading.setVisibility(VISIBLE);
 				adapter.clear();
 				adapter.notifyDataSetChanged();
 			}
@@ -181,6 +192,8 @@ OnItemClickListener {
 			final Collection<GroupMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				// Remove the old item, if any
 				GroupListItem item = findGroup(g.getId());
 				if(item != null) adapter.remove(item);
@@ -196,6 +209,8 @@ OnItemClickListener {
 	private void displayAvailable(final int available) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.setAvailable(available);
 				adapter.notifyDataSetChanged();
 			}
diff --git a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java
index 00a2b1c65a8e2a63798d831d49a7e4f3d1f4b948..aae133ce177b5ca91069ead8879a209d242c6a9b 100644
--- a/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java
+++ b/briar-android/src/net/sf/briar/android/groups/ManageGroupsActivity.java
@@ -15,6 +15,7 @@ import java.util.logging.Logger;
 
 import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.android.DatabaseUiExecutor;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
@@ -46,6 +47,7 @@ implements DatabaseListener, OnItemClickListener {
 
 	private ManageGroupsAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -60,7 +62,10 @@ implements DatabaseListener, OnItemClickListener {
 		list.setLayoutParams(MATCH_MATCH);
 		list.setAdapter(adapter);
 		list.setOnItemClickListener(this);
-		setContentView(list);
+
+		// Show a progress bar while the list is loading
+		loading = new ListLoadingProgressBar(this);
+		setContentView(loading);
 
 		// Bind to the service so we can wait for it to start
 		bindService(new Intent(BriarService.class.getName()),
@@ -104,6 +109,7 @@ implements DatabaseListener, OnItemClickListener {
 			final Collection<GroupStatus> available) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				setContentView(list);
 				adapter.clear();
 				for(GroupStatus g : available)
 					adapter.add(new ManageGroupsItem(g));
diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
index e67052dd32edf72e44a4530f9b92a26a6847af6f..31b28f953ad6111f694ab9c7b999d1cd65c0e5a9 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationActivity.java
@@ -1,6 +1,8 @@
 package net.sf.briar.android.messages;
 
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
@@ -16,6 +18,7 @@ import net.sf.briar.android.AscendingHeaderComparator;
 import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.widgets.HorizontalBorder;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.AuthorId;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -53,6 +56,7 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 	private String contactName = null;
 	private ConversationAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -88,6 +92,11 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 		list.setOnItemClickListener(this);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		ImageButton composeButton = new ImageButton(this);
@@ -145,6 +154,8 @@ implements DatabaseListener, OnClickListener, OnItemClickListener {
 			final Collection<PrivateMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				adapter.clear();
 				for(PrivateMessageHeader h : headers) adapter.add(h);
 				adapter.sort(AscendingHeaderComparator.INSTANCE);
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 d5f38caca53106eb19be2fda8e65c9b02cf1634e..9486a615068b7d320175b920c198f968e83826ad 100644
--- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
+++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java
@@ -1,6 +1,8 @@
 package net.sf.briar.android.messages;
 
 import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
 import static android.widget.LinearLayout.VERTICAL;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
@@ -17,6 +19,7 @@ import net.sf.briar.android.BriarService;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
 import net.sf.briar.android.invitation.AddContactActivity;
 import net.sf.briar.android.widgets.HorizontalBorder;
+import net.sf.briar.android.widgets.ListLoadingProgressBar;
 import net.sf.briar.api.Contact;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.android.DatabaseUiExecutor;
@@ -51,6 +54,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
 
 	private ConversationListAdapter adapter = null;
 	private ListView list = null;
+	private ListLoadingProgressBar loading = null;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject private volatile DatabaseComponent db;
@@ -72,6 +76,11 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
 		list.setOnItemClickListener(adapter);
 		layout.addView(list);
 
+		// Show a progress bar while the list is loading
+		list.setVisibility(GONE);
+		loading = new ListLoadingProgressBar(this);
+		layout.addView(loading);
+
 		layout.addView(new HorizontalBorder(this));
 
 		ImageButton composeButton = new ImageButton(this);
@@ -95,6 +104,7 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
 	}
 
 	private void loadHeaders() {
+		clearHeaders();
 		dbUiExecutor.execute(new Runnable() {
 			public void run() {
 				try {
@@ -125,10 +135,23 @@ implements OnClickListener, DatabaseListener, NoContactsDialog.Listener {
 		});
 	}
 
+	private void clearHeaders() {
+		runOnUiThread(new Runnable() {
+			public void run() {
+				list.setVisibility(GONE);
+				loading.setVisibility(VISIBLE);
+				adapter.clear();
+				adapter.notifyDataSetChanged();
+			}
+		});
+	}
+
 	private void displayHeaders(final Contact c,
 			final Collection<PrivateMessageHeader> headers) {
 		runOnUiThread(new Runnable() {
 			public void run() {
+				list.setVisibility(VISIBLE);
+				loading.setVisibility(GONE);
 				// Remove the old item, if any
 				ConversationListItem item = findConversation(c.getId());
 				if(item != null) adapter.remove(item);
diff --git a/briar-android/src/net/sf/briar/android/widgets/ListLoadingProgressBar.java b/briar-android/src/net/sf/briar/android/widgets/ListLoadingProgressBar.java
new file mode 100644
index 0000000000000000000000000000000000000000..b66fb8025e6c7b29da608312c9b431798328d208
--- /dev/null
+++ b/briar-android/src/net/sf/briar/android/widgets/ListLoadingProgressBar.java
@@ -0,0 +1,21 @@
+package net.sf.briar.android.widgets;
+
+import static android.view.Gravity.CENTER;
+import static net.sf.briar.android.widgets.CommonLayoutParams.MATCH_WRAP_1;
+import static net.sf.briar.android.widgets.CommonLayoutParams.WRAP_WRAP;
+import android.content.Context;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+
+public class ListLoadingProgressBar extends LinearLayout {
+
+	public ListLoadingProgressBar(Context ctx) {
+		super(ctx);
+		setLayoutParams(MATCH_WRAP_1);
+		setGravity(CENTER);
+		ProgressBar progress = new ProgressBar(ctx);
+		progress.setLayoutParams(WRAP_WRAP);
+		progress.setIndeterminate(true);
+		addView(progress);
+	}
+}