diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 70d79d2fa924a6fa2b4b08750d75154181da6985..393815fa3e4ba82b696b13c2f956bbdb7eefb837 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -45,34 +45,6 @@
 		    android:name=".android.contact.ContactListActivity"
 		    android:label="@string/contact_list_title" >
 		</activity>
-		<activity
-			android:name=".android.blogs.BlogActivity"
-			android:label="@string/app_name" >
-		</activity>
-		<activity
-			android:name=".android.blogs.BlogListActivity"
-			android:label="@string/blogs_title" >
-		</activity>
-		<activity
-			android:name=".android.blogs.ConfigureBlogActivity"
-			android:label="@string/app_name" >
-		</activity>
-		<activity
-			android:name=".android.blogs.CreateBlogActivity"
-			android:label="@string/create_blog_title" >
-		</activity>
-		<activity
-		    android:name=".android.blogs.ManageBlogsActivity"
-		    android:label="@string/manage_subscriptions_title" >
-		</activity>
-		<activity
-			android:name=".android.blogs.ReadBlogPostActivity"
-			android:label="@string/app_name" >
-		</activity>
-		<activity
-			android:name=".android.blogs.WriteBlogPostActivity"
-			android:label="@string/new_post_title" >
-		</activity>
 		<activity
 			android:name=".android.groups.ConfigureGroupActivity"
 			android:label="@string/app_name" >
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index eb4bc573682d7201a98bc407e6e4fab601988515..916e3674c75feac857c0b7c181515b2660ea7302 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -14,7 +14,6 @@
 	<string name="contact_list_button">Contacts</string>
 	<string name="messages_button">Messages</string>
 	<string name="groups_button">Groups</string>
-	<string name="blogs_button">Blogs</string>
 	<string name="synchronize_button">Synchronize</string>
 	<string name="quit_button">Quit</string>
 	<string name="new_identity_item">New identity\u2026</string>
@@ -74,23 +73,9 @@
 	<string name="new_group_item">New group\u2026</string>
 	<string name="manage_subscriptions_title">Manage Subscriptions</string>
 	<string name="no_groups_available">No groups available from contacts</string>
-	<string name="blogs_title">Blogs</string>
-	<plurals name="blogs_available">
-	    <item quantity="one">%1$d blog available from contacts</item>
-	    <item quantity="other">%1$d blogs available from contacts</item>
-	</plurals>
-	<string name="no_blogs_available">No blogs available from contacts</string>
 	<string name="subscribed_all">Subscribed, shared with all contacts</string>
 	<string name="subscribed_some">Subscribed, shared with chosen contacts</string>
 	<string name="not_subscribed">Not subscribed</string>
-	<string name="subscribe_to_this_blog">Subscribe to this blog</string>
-	<string name="create_blog_title">New Blog</string>
-	<string name="choose_blog_name">Choose a name for your blog:</string>
-	<string name="blog_visible_to_all">Share this blog with all contacts</string>
-	<string name="blog_visible_to_some">Share this blog with chosen contacts</string>
-	<string name="not_your_blog">Only the creator of this blog can write posts</string>
-	<string name="ok_button">OK</string>
-	<string name="new_blog_item">New blog\u2026</string>
 	<string name="create_nickname_item">New nickname\u2026</string>
 	<string name="create_identity_title">Create an Identity</string>
 	<string name="create_button">Create</string>
@@ -98,5 +83,4 @@
 	<string name="add_button">Add</string>
 	<string name="cancel_button">Cancel</string>
 	<string name="no_groups">You aren\'t subscribed to any groups. Create a group now?</string>
-	<string name="no_blogs">You don\'t have any blogs. Create a blog now?</string>
 </resources>
diff --git a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
index 4f7303ec640eeb97069eb3b8f6d31a588490bca6..915f4b3d45513f6686f503cb4f897b663454e68a 100644
--- a/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
+++ b/briar-android/src/net/sf/briar/android/HomeScreenActivity.java
@@ -23,7 +23,6 @@ import java.util.logging.Logger;
 import net.sf.briar.R;
 import net.sf.briar.android.BriarService.BriarBinder;
 import net.sf.briar.android.BriarService.BriarServiceConnection;
-import net.sf.briar.android.blogs.BlogListActivity;
 import net.sf.briar.android.contact.ContactListActivity;
 import net.sf.briar.android.groups.GroupListActivity;
 import net.sf.briar.android.messages.ConversationListActivity;
@@ -62,8 +61,8 @@ import com.google.inject.Inject;
 
 public class HomeScreenActivity extends RoboActivity {
 
-	// This build expires on 15 August 2013
-	private static final long EXPIRY_DATE = 1376524800 * 1000L;
+	// This build expires on 30 September 2013
+	private static final long EXPIRY_DATE = 1380499200 * 1000L;
 
 	private static final Logger LOG =
 			Logger.getLogger(HomeScreenActivity.class.getName());
@@ -346,20 +345,6 @@ public class HomeScreenActivity extends RoboActivity {
 		});
 		buttons.add(groupsButton);
 
-		Button blogsButton = new Button(this);
-		blogsButton.setLayoutParams(matchMatch);
-		blogsButton.setBackgroundResource(0);
-		blogsButton.setCompoundDrawablesWithIntrinsicBounds(0,
-				R.drawable.social_blog, 0, 0);
-		blogsButton.setText(R.string.blogs_button);
-		blogsButton.setOnClickListener(new OnClickListener() {
-			public void onClick(View view) {
-				startActivity(new Intent(HomeScreenActivity.this,
-						BlogListActivity.class));
-			}
-		});
-		buttons.add(blogsButton);
-
 		Button syncButton = new Button(this);
 		syncButton.setLayoutParams(matchMatch);
 		syncButton.setBackgroundResource(0);
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java
deleted file mode 100644
index b3fa2cd92fc441e7f1478654fe78cfdc8d2c9812..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/BlogActivity.java
+++ /dev/null
@@ -1,250 +0,0 @@
-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;
-import static net.sf.briar.android.blogs.ReadBlogPostActivity.RESULT_NEXT;
-import static net.sf.briar.android.blogs.ReadBlogPostActivity.RESULT_PREV;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP_1;
-
-import java.util.Collection;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.AscendingHeaderComparator;
-import net.sf.briar.android.util.HorizontalBorder;
-import net.sf.briar.android.util.ListLoadingProgressBar;
-import net.sf.briar.api.Author;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.db.GroupMessageHeader;
-import net.sf.briar.api.db.NoSuchSubscriptionException;
-import net.sf.briar.api.db.event.DatabaseEvent;
-import net.sf.briar.api.db.event.DatabaseListener;
-import net.sf.briar.api.db.event.GroupMessageAddedEvent;
-import net.sf.briar.api.db.event.MessageExpiredEvent;
-import net.sf.briar.api.db.event.RatingChangedEvent;
-import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.GroupId;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-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;
-
-import com.google.inject.Inject;
-
-public class BlogActivity extends RoboFragmentActivity
-implements DatabaseListener, OnClickListener, OnItemClickListener {
-
-	private static final Logger LOG =
-			Logger.getLogger(BlogActivity.class.getName());
-
-	private String groupName = null;
-	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;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-	private volatile GroupId groupId = null;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		Intent i = getIntent();
-		byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
-		if(b == null) throw new IllegalStateException();
-		groupId = new GroupId(b);
-		groupName = i.getStringExtra("net.sf.briar.GROUP_NAME");
-		if(groupName == null) throw new IllegalStateException();
-		setTitle(groupName);
-		postable = i.getBooleanExtra("net.sf.briar.POSTABLE", false);
-
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
-
-		adapter = new BlogAdapter(this);
-		list = new ListView(this);
-		// Give me all the width and all the unused height
-		list.setLayoutParams(MATCH_WRAP_1);
-		list.setAdapter(adapter);
-		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);
-		composeButton.setBackgroundResource(0);
-		composeButton.setImageResource(R.drawable.content_new_email);
-		composeButton.setOnClickListener(this);
-		layout.addView(composeButton);
-
-		setContentView(layout);
-	}
-
-	@Override
-	public void onResume() {
-		super.onResume();
-		db.addListener(this);
-		loadHeaders();
-	}
-
-	private void loadHeaders() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<GroupMessageHeader> headers =
-							db.getGroupMessageHeaders(groupId);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Load took " + duration + " ms");
-					displayHeaders(headers);
-				} catch(NoSuchSubscriptionException e) {
-					if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
-					runOnUiThread(new Runnable() {
-						public void run() {
-							finish();
-						}
-					});
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	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);
-				adapter.notifyDataSetChanged();
-				selectFirstUnread();
-			}
-		});
-	}
-
-	private void selectFirstUnread() {
-		int firstUnread = -1, count = adapter.getCount();
-		for(int i = 0; i < count; i++) {
-			if(!adapter.getItem(i).isRead()) {
-				firstUnread = i;
-				break;
-			}
-		}
-		if(firstUnread == -1) list.setSelection(count - 1);
-		else list.setSelection(firstUnread);
-	}
-
-	@Override
-	public void onActivityResult(int request, int result, Intent data) {
-		if(result == RESULT_PREV) {
-			int position = request - 1;
-			if(position >= 0 && position < adapter.getCount())
-				displayMessage(position);
-		} else if(result == RESULT_NEXT) {
-			int position = request + 1;
-			if(position >= 0 && position < adapter.getCount())
-				displayMessage(position);
-		}
-	}
-
-	@Override
-	public void onPause() {
-		super.onPause();
-		db.removeListener(this);
-	}
-
-	public void eventOccurred(DatabaseEvent e) {
-		if(e instanceof GroupMessageAddedEvent) {
-			GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
-			if(g.getGroup().getId().equals(groupId)) {
-				if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
-				loadHeaders();
-			}
-		} else if(e instanceof MessageExpiredEvent) {
-			if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
-			loadHeaders();
-		} else if(e instanceof RatingChangedEvent) {
-			if(LOG.isLoggable(INFO)) LOG.info("Rating changed, reloading");
-			loadHeaders();
-		} else if(e instanceof SubscriptionRemovedEvent) {
-			SubscriptionRemovedEvent s = (SubscriptionRemovedEvent) e;
-			if(s.getGroup().getId().equals(groupId)) {
-				if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
-				runOnUiThread(new Runnable() {
-					public void run() {
-						finish();
-					}
-				});
-			}
-		}
-	}
-
-	public void onClick(View view) {
-		if(postable) {
-			Intent i = new Intent(this, WriteBlogPostActivity.class);
-			i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
-			startActivity(i);
-		} else {
-			NotYourBlogDialog dialog = new NotYourBlogDialog();
-			dialog.show(getSupportFragmentManager(), "NotYourBlogDialog");
-		}
-	}
-
-	public void onItemClick(AdapterView<?> parent, View view, int position,
-			long id) {
-		displayMessage(position);
-	}
-
-	private void displayMessage(int position) {
-		GroupMessageHeader item = adapter.getItem(position);
-		Intent i = new Intent(this, ReadBlogPostActivity.class);
-		i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
-		i.putExtra("net.sf.briar.GROUP_NAME", groupName);
-		i.putExtra("net.sf.briar.POSTABLE", postable);
-		i.putExtra("net.sf.briar.MESSAGE_ID", item.getId().getBytes());
-		Author author = item.getAuthor();
-		if(author != null) {
-			i.putExtra("net.sf.briar.AUTHOR_NAME", author.getName());
-			i.putExtra("net.sf.briar.RATING", item.getRating().toString());
-		}
-		i.putExtra("net.sf.briar.CONTENT_TYPE", item.getContentType());
-		i.putExtra("net.sf.briar.TIMESTAMP", item.getTimestamp());
-		startActivityForResult(i, position);
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogAdapter.java b/briar-android/src/net/sf/briar/android/blogs/BlogAdapter.java
deleted file mode 100644
index bd181bdedf0188429257a57655b9b9c350211624..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/BlogAdapter.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.graphics.Typeface.BOLD;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static android.widget.LinearLayout.VERTICAL;
-import static java.text.DateFormat.SHORT;
-import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP_1;
-import static net.sf.briar.api.messaging.Rating.BAD;
-import static net.sf.briar.api.messaging.Rating.GOOD;
-
-import java.util.ArrayList;
-
-import net.sf.briar.R;
-import net.sf.briar.android.util.HorizontalSpace;
-import net.sf.briar.api.Author;
-import net.sf.briar.api.db.GroupMessageHeader;
-import net.sf.briar.api.messaging.Rating;
-import android.content.Context;
-import android.content.res.Resources;
-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.TextView;
-
-class BlogAdapter extends ArrayAdapter<GroupMessageHeader> {
-
-	BlogAdapter(Context ctx) {
-		super(ctx, android.R.layout.simple_expandable_list_item_1,
-				new ArrayList<GroupMessageHeader>());
-	}
-
-	@Override
-	public View getView(int position, View convertView, ViewGroup parent) {
-		GroupMessageHeader item = getItem(position);
-		Context ctx = getContext();
-		Resources res = ctx.getResources();
-
-		LinearLayout layout = new LinearLayout(ctx);
-		layout.setOrientation(HORIZONTAL);
-		if(!item.isRead())
-			layout.setBackgroundColor(res.getColor(R.color.unread_background));
-
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		// Give me all the unused width
-		innerLayout.setLayoutParams(WRAP_WRAP_1);
-		innerLayout.setOrientation(VERTICAL);
-
-		LinearLayout authorLayout = new LinearLayout(ctx);
-		authorLayout.setOrientation(HORIZONTAL);
-		authorLayout.setGravity(CENTER_VERTICAL);
-
-		ImageView thumb = new ImageView(ctx);
-		thumb.setPadding(5, 5, 5, 5);
-		Rating rating = item.getRating();
-		if(rating == GOOD) thumb.setImageResource(R.drawable.rating_good);
-		else if(rating == BAD) thumb.setImageResource(R.drawable.rating_bad);
-		else thumb.setImageResource(R.drawable.rating_unrated);
-		authorLayout.addView(thumb);
-
-		TextView name = new TextView(ctx);
-		// Give me all the unused width
-		name.setLayoutParams(WRAP_WRAP_1);
-		name.setTextSize(18);
-		name.setMaxLines(1);
-		name.setPadding(0, 10, 10, 10);
-		Author author = item.getAuthor();
-		if(author == null) {
-			name.setTextColor(res.getColor(R.color.anonymous_author));
-			name.setText(R.string.anonymous);
-		} else {
-			name.setText(author.getName());
-		}
-		authorLayout.addView(name);
-		innerLayout.addView(authorLayout);
-
-		if(item.getContentType().equals("text/plain")) {
-			TextView subject = new TextView(ctx);
-			subject.setTextSize(14);
-			subject.setMaxLines(2);
-			subject.setPadding(10, 0, 10, 10);
-			if(!item.isRead()) subject.setTypeface(null, BOLD);
-			String s = item.getSubject();
-			subject.setText(s == null ? "" : s);
-			innerLayout.addView(subject);
-		} else {
-			LinearLayout attachmentLayout = new LinearLayout(ctx);
-			attachmentLayout.setOrientation(HORIZONTAL);
-			ImageView attachment = new ImageView(ctx);
-			attachment.setPadding(5, 0, 5, 5);
-			attachment.setImageResource(R.drawable.content_attachment);
-			attachmentLayout.addView(attachment);
-			attachmentLayout.addView(new HorizontalSpace(ctx));
-			innerLayout.addView(attachmentLayout);
-		}
-		layout.addView(innerLayout);
-
-		TextView date = new TextView(ctx);
-		date.setTextSize(14);
-		date.setPadding(0, 10, 10, 10);
-		long then = item.getTimestamp(), now = System.currentTimeMillis();
-		date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
-		layout.addView(date);
-
-		return layout;
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java b/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java
deleted file mode 100644
index 0b16ce3423102b33c10c070283780ede0def27ca..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/BlogListActivity.java
+++ /dev/null
@@ -1,412 +0,0 @@
-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;
-import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.blogs.BlogListItem.MANAGE;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP_1;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.util.HorizontalBorder;
-import net.sf.briar.android.util.HorizontalSpace;
-import net.sf.briar.android.util.ListLoadingProgressBar;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.db.GroupMessageHeader;
-import net.sf.briar.api.db.NoSuchSubscriptionException;
-import net.sf.briar.api.db.event.DatabaseEvent;
-import net.sf.briar.api.db.event.DatabaseListener;
-import net.sf.briar.api.db.event.GroupMessageAddedEvent;
-import net.sf.briar.api.db.event.MessageExpiredEvent;
-import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent;
-import net.sf.briar.api.db.event.SubscriptionAddedEvent;
-import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.Group;
-import net.sf.briar.api.messaging.GroupId;
-import net.sf.briar.api.messaging.GroupStatus;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-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;
-
-import com.google.inject.Inject;
-
-public class BlogListActivity extends RoboFragmentActivity
-implements DatabaseListener, OnClickListener, NoBlogsDialog.Listener,
-OnItemClickListener {
-
-	private static final Logger LOG =
-			Logger.getLogger(BlogListActivity.class.getName());
-
-	private BlogListAdapter adapter = null;
-	private ListView list = null;
-	private ListLoadingProgressBar loading = null;
-	private ImageButton newBlogButton = null, composeButton = null;
-	private ImageButton manageBlogsButton = null;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject private volatile DatabaseComponent db;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
-
-		adapter = new BlogListAdapter(this);
-		list = new ListView(this);
-		// Give me all the width and all the unused height
-		list.setLayoutParams(MATCH_WRAP_1);
-		list.setAdapter(adapter);
-		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);
-		footer.setLayoutParams(MATCH_WRAP);
-		footer.setOrientation(HORIZONTAL);
-		footer.setGravity(CENTER);
-		footer.addView(new HorizontalSpace(this));
-
-		newBlogButton = new ImageButton(this);
-		newBlogButton.setBackgroundResource(0);
-		newBlogButton.setImageResource(R.drawable.social_new_blog);
-		newBlogButton.setOnClickListener(this);
-		footer.addView(newBlogButton);
-		footer.addView(new HorizontalSpace(this));
-
-		composeButton = new ImageButton(this);
-		composeButton.setBackgroundResource(0);
-		composeButton.setImageResource(R.drawable.content_new_email);
-		composeButton.setOnClickListener(this);
-		footer.addView(composeButton);
-		footer.addView(new HorizontalSpace(this));
-
-		manageBlogsButton = new ImageButton(this);
-		manageBlogsButton.setBackgroundResource(0);
-		manageBlogsButton.setImageResource(R.drawable.action_settings);
-		manageBlogsButton.setOnClickListener(this);
-		footer.addView(manageBlogsButton);
-		footer.addView(new HorizontalSpace(this));
-		layout.addView(footer);
-
-		setContentView(layout);
-	}
-
-	@Override
-	public void onResume() {
-		super.onResume();
-		db.addListener(this);
-		loadHeaders();
-	}
-
-	private void loadHeaders() {
-		clearHeaders();
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Set<GroupId> local = new HashSet<GroupId>();
-					for(Group g : db.getLocalGroups()) local.add(g.getId());
-					int available = 0;
-					for(GroupStatus s : db.getAvailableGroups()) {
-						Group g = s.getGroup();
-						if(!g.isRestricted()) continue;
-						if(s.isSubscribed()) {
-							boolean postable = local.contains(g.getId());
-							try {
-								Collection<GroupMessageHeader> headers =
-										db.getGroupMessageHeaders(g.getId());
-								displayHeaders(g, postable, headers);
-							} catch(NoSuchSubscriptionException e) {
-								if(LOG.isLoggable(INFO))
-									LOG.info("Subscription removed");
-							}
-						} else {
-							available++;
-						}
-					}
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Full load took " + duration + " ms");
-					displayAvailable(available);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void clearHeaders() {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				list.setVisibility(GONE);
-				loading.setVisibility(VISIBLE);
-				adapter.clear();
-				adapter.notifyDataSetChanged();
-			}
-		});
-	}
-
-	private void displayHeaders(final Group g, final boolean postable,
-			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);
-				// Add a new item
-				adapter.add(new BlogListItem(g, postable, headers));
-				adapter.sort(ItemComparator.INSTANCE);
-				adapter.notifyDataSetChanged();
-				selectFirstUnread();
-			} 
-		});
-	}
-
-	private void displayAvailable(final int available) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				list.setVisibility(VISIBLE);
-				loading.setVisibility(GONE);
-				adapter.setAvailable(available);
-				adapter.notifyDataSetChanged();
-			}
-		});
-	}
-
-	private BlogListItem findGroup(GroupId g) {
-		int count = adapter.getCount();
-		for(int i = 0; i < count; i++) {
-			BlogListItem item = adapter.getItem(i);
-			if(item == MANAGE) continue;
-			if(item.getGroup().getId().equals(g)) return item;
-		}
-		return null; // Not found
-	}
-
-	private void selectFirstUnread() {
-		int firstUnread = -1, count = adapter.getCount();
-		for(int i = 0; i < count; i++) {
-			BlogListItem item = adapter.getItem(i);
-			if(item == MANAGE) continue;
-			if(item.getUnreadCount() > 0) {
-				firstUnread = i;
-				break;
-			}
-		}
-		if(firstUnread == -1) list.setSelection(count - 1);
-		else list.setSelection(firstUnread);
-	}
-
-	@Override
-	public void onPause() {
-		super.onPause();
-		db.removeListener(this);
-	}
-
-	public void eventOccurred(DatabaseEvent e) {
-		if(e instanceof GroupMessageAddedEvent) {
-			Group g = ((GroupMessageAddedEvent) e).getGroup();
-			if(g.isRestricted()) {
-				if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
-				loadHeaders(g);
-			}
-		} else if(e instanceof MessageExpiredEvent) {
-			if(LOG.isLoggable(INFO)) LOG.info("Message expired, reloading");
-			loadHeaders();
-		} else if(e instanceof RemoteSubscriptionsUpdatedEvent) {
-			if(LOG.isLoggable(INFO))
-				LOG.info("Remote subscriptions changed, reloading");
-			loadAvailable();
-		} else if(e instanceof SubscriptionAddedEvent) {
-			Group g = ((SubscriptionAddedEvent) e).getGroup();
-			if(g.isRestricted()) {
-				if(LOG.isLoggable(INFO)) LOG.info("Group added, reloading");
-				loadHeaders();
-			}
-		} else if(e instanceof SubscriptionRemovedEvent) {
-			Group g = ((SubscriptionRemovedEvent) e).getGroup();
-			if(g.isRestricted()) {
-				// Reload the group, expecting NoSuchSubscriptionException
-				if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
-				loadHeaders(g);
-			}
-		}
-	}
-
-	private void loadHeaders(final Group g) {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<GroupMessageHeader> headers =
-							db.getGroupMessageHeaders(g.getId());
-					boolean postable = db.getLocalGroups().contains(g);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Partial load took " + duration + " ms");
-					displayHeaders(g, postable, headers);
-				} catch(NoSuchSubscriptionException e) {
-					if(LOG.isLoggable(INFO)) LOG.info("Subscription removed");
-					removeGroup(g.getId());
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void removeGroup(final GroupId g) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				BlogListItem item = findGroup(g);
-				if(item != null) {
-					adapter.remove(item);
-					adapter.notifyDataSetChanged();
-					selectFirstUnread();
-				}
-			}
-		});
-	}
-
-	private void loadAvailable() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					int available = 0;
-					long now = System.currentTimeMillis();
-					for(GroupStatus s : db.getAvailableGroups()) {
-						if(s.getGroup().isRestricted() && !s.isSubscribed())
-							available++;
-					}
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Loading available took " + duration + " ms");
-					displayAvailable(available);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	public void onClick(View view) {
-		if(view == newBlogButton) {
-			startActivity(new Intent(this, CreateBlogActivity.class));
-		} else if(view == composeButton) {
-			if(countPostableGroups() == 0) {
-				NoBlogsDialog dialog = new NoBlogsDialog();
-				dialog.setListener(this);
-				dialog.show(getSupportFragmentManager(), "NoBlogsDialog");
-			} else {
-				startActivity(new Intent(this, WriteBlogPostActivity.class));
-			}
-		} else if(view == manageBlogsButton) {
-			startActivity(new Intent(this, ManageBlogsActivity.class));
-		}
-	}
-
-	private int countPostableGroups() {
-		int postable = 0, count = adapter.getCount();
-		for(int i = 0; i < count; i++) {
-			BlogListItem item = adapter.getItem(i);
-			if(item == MANAGE) continue;
-			if(item.isPostable()) postable++;
-		}
-		return postable;
-	}
-
-	public void blogCreationSelected() {
-		startActivity(new Intent(this, CreateBlogActivity.class));
-	}
-
-	public void blogCreationCancelled() {}
-
-	public void onItemClick(AdapterView<?> parent, View view, int position,
-			long id) {
-		BlogListItem item = adapter.getItem(position);
-		if(item == MANAGE) {
-			startActivity(new Intent(this, ManageBlogsActivity.class));
-		} else {
-			Intent i = new Intent(this, BlogActivity.class);
-			i.putExtra("net.sf.briar.GROUP_ID",
-					item.getGroup().getId().getBytes());
-			i.putExtra("net.sf.briar.GROUP_NAME", item.getGroup().getName());
-			i.putExtra("net.sf.briar.POSTABLE", item.isPostable());
-			startActivity(i);
-		}
-	}
-
-	private static class ItemComparator implements Comparator<BlogListItem> {
-
-		private static final ItemComparator INSTANCE = new ItemComparator();
-
-		public int compare(BlogListItem a, BlogListItem b) {
-			if(a == b) return 0;
-			// The manage blogs item comes last
-			if(a == MANAGE) return 1;
-			if(b == MANAGE) return -1;
-			// 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;
-			// Break ties by group name
-			String aName = a.getGroup().getName();
-			String bName = b.getGroup().getName();
-			return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
-		}
-	}
-}
\ No newline at end of file
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java b/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java
deleted file mode 100644
index f99eb1a8a4088216c2bd92c436ab185014906043..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/BlogListAdapter.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.graphics.Typeface.BOLD;
-import static android.view.Gravity.CENTER;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static android.widget.LinearLayout.VERTICAL;
-import static java.text.DateFormat.SHORT;
-import static net.sf.briar.android.blogs.BlogListItem.MANAGE;
-import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP_1;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import net.sf.briar.R;
-import net.sf.briar.android.util.HorizontalSpace;
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.format.DateUtils;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class BlogListAdapter extends BaseAdapter {
-
-	private final Context ctx;
-	private final List<BlogListItem> list = new ArrayList<BlogListItem>();
-	private int available = 0;
-
-	BlogListAdapter(Context ctx) {
-		this.ctx = ctx;
-	}
-
-	public void setAvailable(int available) {
-		this.available = available;
-	}
-
-	public void add(BlogListItem item) {
-		list.add(item);
-	}
-
-	public void clear() {
-		list.clear();
-	}
-
-	public int getCount() {
-		return available == 0 ? list.size() : list.size() + 1;
-	}
-
-	public BlogListItem getItem(int position) {
-		return position == list.size() ? MANAGE : list.get(position);
-	}
-
-	public long getItemId(int position) {
-		return android.R.layout.simple_expandable_list_item_1;
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		BlogListItem item = getItem(position);
-		Resources res = ctx.getResources();
-
-		if(item == MANAGE) {
-			TextView manage = new TextView(ctx);
-			manage.setGravity(CENTER);
-			manage.setTextSize(18);
-			manage.setPadding(10, 10, 10, 10);
-			String format = res.getQuantityString(R.plurals.blogs_available,
-					available);
-			manage.setText(String.format(format, available));
-			return manage;
-		}
-
-		LinearLayout layout = new LinearLayout(ctx);
-		layout.setOrientation(HORIZONTAL);
-		if(item.getUnreadCount() > 0)
-			layout.setBackgroundColor(res.getColor(R.color.unread_background));
-
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		// Give me all the unused width
-		innerLayout.setLayoutParams(WRAP_WRAP_1);
-		innerLayout.setOrientation(VERTICAL);
-
-		TextView name = new TextView(ctx);
-		name.setTextSize(18);
-		name.setMaxLines(1);
-		name.setPadding(10, 10, 10, 10);
-		int unread = item.getUnreadCount();
-		String groupName = item.getGroup().getName();
-		if(unread > 0) name.setText(groupName + " (" + unread + ")");
-		else name.setText(groupName);
-		innerLayout.addView(name);
-
-		if(item.isEmpty()) {
-			TextView noPosts = new TextView(ctx);
-			noPosts.setTextSize(14);
-			noPosts.setPadding(10, 0, 10, 10);
-			noPosts.setTextColor(res.getColor(R.color.no_posts));
-			noPosts.setText(R.string.no_posts);
-			innerLayout.addView(noPosts);
-			layout.addView(innerLayout);
-		} else {
-			if(item.getContentType().equals("text/plain")) {
-				TextView subject = new TextView(ctx);
-				subject.setTextSize(14);
-				subject.setMaxLines(2);
-				subject.setPadding(10, 0, 10, 10);
-				if(item.getUnreadCount() > 0) subject.setTypeface(null, BOLD);
-				String s = item.getSubject();
-				subject.setText(s == null ? "" : s);
-				innerLayout.addView(subject);
-			} else {
-				LinearLayout attachmentLayout = new LinearLayout(ctx);
-				attachmentLayout.setOrientation(HORIZONTAL);
-				ImageView attachment = new ImageView(ctx);
-				attachment.setPadding(5, 0, 5, 5);
-				attachment.setImageResource(R.drawable.content_attachment);
-				attachmentLayout.addView(attachment);
-				attachmentLayout.addView(new HorizontalSpace(ctx));
-				innerLayout.addView(attachmentLayout);
-			}
-			layout.addView(innerLayout);
-
-			TextView date = new TextView(ctx);
-			date.setTextSize(14);
-			date.setPadding(0, 10, 10, 10);
-			long then = item.getTimestamp(), now = System.currentTimeMillis();
-			date.setText(DateUtils.formatSameDayTime(then, now, SHORT, SHORT));
-			layout.addView(date);
-		}
-
-		return layout;
-	}
-
-	@Override
-	public boolean isEmpty() {
-		return list.isEmpty() && available == 0;
-	}
-
-	public void remove(BlogListItem item) {
-		list.remove(item);
-	}
-
-	public void sort(Comparator<BlogListItem> comparator) {
-		Collections.sort(list, comparator);
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/BlogListItem.java b/briar-android/src/net/sf/briar/android/blogs/BlogListItem.java
deleted file mode 100644
index 72f3b1b8d5b2c6f7390ca49183ab942913cf7df2..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/BlogListItem.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import net.sf.briar.android.DescendingHeaderComparator;
-import net.sf.briar.api.Author;
-import net.sf.briar.api.db.GroupMessageHeader;
-import net.sf.briar.api.messaging.Group;
-
-class BlogListItem {
-
-	static final BlogListItem MANAGE = new BlogListItem(null, false,
-			Collections.<GroupMessageHeader>emptyList());
-
-	private final Group group;
-	private final boolean postable, empty;
-	private final String authorName, contentType, subject;
-	private final long timestamp;
-	private final int unread;
-
-	BlogListItem(Group group, boolean postable,
-			Collection<GroupMessageHeader> headers) {
-		this.group = group;
-		this.postable = postable;
-		empty = headers.isEmpty();
-		if(empty) {
-			authorName = null;
-			contentType = null;
-			subject = null;
-			timestamp = 0;
-			unread = 0;
-		} else {
-			List<GroupMessageHeader> list =
-					new ArrayList<GroupMessageHeader>(headers);
-			Collections.sort(list, DescendingHeaderComparator.INSTANCE);
-			GroupMessageHeader newest = list.get(0);
-			Author a = newest.getAuthor();
-			if(a == null) authorName = null;
-			else authorName = a.getName();
-			contentType = newest.getContentType();
-			subject = newest.getSubject();
-			timestamp = newest.getTimestamp();
-			int unread = 0;
-			for(GroupMessageHeader h : list) if(!h.isRead()) unread++;
-			this.unread = unread;
-		}
-	}
-
-	Group getGroup() {
-		return group;
-	}
-
-	boolean isPostable() {
-		return postable;
-	}
-
-	boolean isEmpty() {
-		return empty;
-	}
-
-	String getAuthorName() {
-		return authorName;
-	}
-
-	String getContentType() {
-		return contentType;
-	}
-
-	String getSubject() {
-		return subject;
-	}
-
-	long getTimestamp() {
-		return timestamp;
-	}
-
-	int getUnreadCount() {
-		return unread;
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java
deleted file mode 100644
index c34dc6e6ac0ef3ab8f6786f7310a9fc52d4dfe8d..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/ConfigureBlogActivity.java
+++ /dev/null
@@ -1,248 +0,0 @@
-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;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
-import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.contact.SelectContactsDialog;
-import net.sf.briar.android.invitation.AddContactActivity;
-import net.sf.briar.android.messages.NoContactsDialog;
-import net.sf.briar.api.Contact;
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.Group;
-import net.sf.briar.api.messaging.GroupId;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-
-import com.google.inject.Inject;
-
-public class ConfigureBlogActivity extends RoboFragmentActivity
-implements OnClickListener, NoContactsDialog.Listener,
-SelectContactsDialog.Listener {
-
-	private static final Logger LOG =
-			Logger.getLogger(ConfigureBlogActivity.class.getName());
-
-	private boolean subscribed = false;
-	private CheckBox subscribeCheckBox = null;
-	private RadioGroup radioGroup = null;
-	private RadioButton visibleToAll = null, visibleToSome = null;
-	private Button doneButton = null;
-	private ProgressBar progress = null;
-	private NoContactsDialog noContactsDialog = null;
-	private SelectContactsDialog selectContactsDialog = null;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject private volatile DatabaseComponent db;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-	private volatile Group group = null;
-	private volatile Collection<ContactId> selected = Collections.emptyList();
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		Intent i = getIntent();
-		byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
-		if(b == null) throw new IllegalStateException();
-		GroupId id = new GroupId(b);
-		String name = i.getStringExtra("net.sf.briar.GROUP_NAME");
-		if(name == null) throw new IllegalStateException();
-		setTitle(name);
-		byte[] publicKey = i.getByteArrayExtra("net.sf.briar.PUBLIC_KEY");
-		if(publicKey == null) throw new IllegalStateException();
-		group = new Group(id, name, publicKey);
-		subscribed = i.getBooleanExtra("net.sf.briar.SUBSCRIBED", false);
-		boolean all = i.getBooleanExtra("net.sf.briar.VISIBLE_TO_ALL", false);
-
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
-
-		subscribeCheckBox = new CheckBox(this);
-		subscribeCheckBox.setId(1);
-		subscribeCheckBox.setText(R.string.subscribe_to_this_blog);
-		subscribeCheckBox.setChecked(subscribed);
-		subscribeCheckBox.setOnClickListener(this);
-		layout.addView(subscribeCheckBox);
-
-		radioGroup = new RadioGroup(this);
-		radioGroup.setOrientation(VERTICAL);
-
-		visibleToAll = new RadioButton(this);
-		visibleToAll.setId(2);
-		visibleToAll.setText(R.string.blog_visible_to_all);
-		visibleToAll.setEnabled(subscribed);
-		visibleToAll.setOnClickListener(this);
-		radioGroup.addView(visibleToAll);
-
-		visibleToSome = new RadioButton(this);
-		visibleToSome.setId(3);
-		visibleToSome.setText(R.string.blog_visible_to_some);
-		visibleToSome.setEnabled(subscribed);
-		visibleToSome.setOnClickListener(this);
-		radioGroup.addView(visibleToSome);
-
-		if(!subscribed || all) radioGroup.check(visibleToAll.getId());
-		else radioGroup.check(visibleToSome.getId());
-		layout.addView(radioGroup);
-
-		doneButton = new Button(this);
-		doneButton.setLayoutParams(WRAP_WRAP);
-		doneButton.setText(R.string.done_button);
-		doneButton.setOnClickListener(this);
-		layout.addView(doneButton);
-
-		progress = new ProgressBar(this);
-		progress.setLayoutParams(WRAP_WRAP);
-		progress.setIndeterminate(true);
-		progress.setVisibility(GONE);
-		layout.addView(progress);
-
-		setContentView(layout);
-
-		FragmentManager fm = getSupportFragmentManager();
-		Fragment f = fm.findFragmentByTag("NoContactsDialog");
-		if(f == null) noContactsDialog = new NoContactsDialog();
-		else noContactsDialog = (NoContactsDialog) f;
-		noContactsDialog.setListener(this);
-
-		f = fm.findFragmentByTag("SelectContactsDialog");
-		if(f == null) selectContactsDialog = new SelectContactsDialog();
-		else selectContactsDialog = (SelectContactsDialog) f;
-		selectContactsDialog.setListener(this);
-	}
-
-	public void onClick(View view) {
-		if(view == subscribeCheckBox) {
-			boolean subscribe = subscribeCheckBox.isChecked();
-			visibleToAll.setEnabled(subscribe);
-			visibleToSome.setEnabled(subscribe);
-		} else if(view == visibleToSome) {
-			loadContacts();
-		} else if(view == doneButton) {
-			boolean subscribe = subscribeCheckBox.isChecked();
-			boolean all = visibleToAll.isChecked();
-			Collection<ContactId> visible =
-					Collections.unmodifiableCollection(selected);
-			// Replace the button with a progress bar
-			doneButton.setVisibility(GONE);
-			progress.setVisibility(VISIBLE);
-			// Update the blog in a background thread
-			if(subscribe || subscribed)
-				updateGroup(subscribe, subscribed, all, visible);
-		}
-	}
-
-	private void loadContacts() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<Contact> contacts = db.getContacts();
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Load took " + duration + " ms");
-					displayContacts(contacts);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void displayContacts(final Collection<Contact> contacts) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				FragmentManager fm = getSupportFragmentManager();
-				if(contacts.isEmpty()) {
-					noContactsDialog.show(fm, "NoContactsDialog");
-				} else {
-					selectContactsDialog.setContacts(contacts);
-					selectContactsDialog.show(fm, "SelectContactsDialog");
-				}
-			}
-		});
-	}
-
-	private void updateGroup(final boolean subscribe,
-			final boolean wasSubscribed, final boolean all,
-			final Collection<ContactId> visible) {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					if(subscribe) {
-						if(!wasSubscribed) db.subscribe(group);
-						db.setVisibleToAll(group.getId(), all);
-						if(!all) db.setVisibility(group.getId(), visible);
-					} else if(wasSubscribed) {
-						db.unsubscribe(group);
-					}
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Update took " + duration + " ms");
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-				runOnUiThread(new Runnable() {
-					public void run() {
-						finish();
-					}
-				});
-			}
-		});
-	}
-
-	public void contactCreationSelected() {
-		startActivity(new Intent(this, AddContactActivity.class));
-	}
-
-	public void contactCreationCancelled() {}
-
-	public void contactsSelected(Collection<ContactId> selected) {
-		this.selected = selected;
-	}
-
-	public void contactSelectionCancelled() {}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java b/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java
deleted file mode 100644
index 9f7cbeadeec7410980efbf288068f5c95c876cce..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/CreateBlogActivity.java
+++ /dev/null
@@ -1,290 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.text.InputType.TYPE_CLASS_TEXT;
-import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
-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.view.inputmethod.InputMethodManager.HIDE_IMPLICIT_ONLY;
-import static android.widget.LinearLayout.VERTICAL;
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
-import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.contact.SelectContactsDialog;
-import net.sf.briar.android.invitation.AddContactActivity;
-import net.sf.briar.android.messages.NoContactsDialog;
-import net.sf.briar.api.Contact;
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.crypto.CryptoComponent;
-import net.sf.briar.api.crypto.CryptoExecutor;
-import net.sf.briar.api.crypto.KeyPair;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.GroupFactory;
-import net.sf.briar.api.messaging.LocalGroup;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.google.inject.Inject;
-
-public class CreateBlogActivity extends RoboFragmentActivity
-implements OnEditorActionListener, OnClickListener, NoContactsDialog.Listener,
-SelectContactsDialog.Listener {
-
-	private static final Logger LOG =
-			Logger.getLogger(CreateBlogActivity.class.getName());
-
-	@Inject @CryptoExecutor private Executor cryptoExecutor;
-	private EditText nameEntry = null;
-	private RadioGroup radioGroup = null;
-	private RadioButton visibleToAll = null, visibleToSome = null;
-	private Button createButton = null;
-	private ProgressBar progress = null;
-	private NoContactsDialog noContactsDialog = null;
-	private SelectContactsDialog selectContactsDialog = null;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject private volatile CryptoComponent crypto;
-	@Inject private volatile GroupFactory groupFactory;
-	@Inject private volatile DatabaseComponent db;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-	private volatile Collection<ContactId> selected = Collections.emptyList();
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_MATCH);
-		layout.setOrientation(VERTICAL);
-		layout.setGravity(CENTER_HORIZONTAL);
-
-		TextView chooseName = new TextView(this);
-		chooseName.setGravity(CENTER);
-		chooseName.setTextSize(18);
-		chooseName.setPadding(10, 10, 10, 0);
-		chooseName.setText(R.string.choose_blog_name);
-		layout.addView(chooseName);
-
-		nameEntry = new EditText(this) {
-			@Override
-			protected void onTextChanged(CharSequence text, int start,
-					int lengthBefore, int lengthAfter) {
-				enableOrDisableCreateButton();
-			}
-		};
-		nameEntry.setId(1);
-		nameEntry.setMaxLines(1);
-		nameEntry.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES);
-		nameEntry.setOnEditorActionListener(this);
-		layout.addView(nameEntry);
-
-		radioGroup = new RadioGroup(this);
-		radioGroup.setOrientation(VERTICAL);
-
-		visibleToAll = new RadioButton(this);
-		visibleToAll.setId(2);
-		visibleToAll.setText(R.string.blog_visible_to_all);
-		visibleToAll.setOnClickListener(this);
-		radioGroup.addView(visibleToAll);
-
-		visibleToSome = new RadioButton(this);
-		visibleToSome.setId(3);
-		visibleToSome.setText(R.string.blog_visible_to_some);
-		visibleToSome.setOnClickListener(this);
-		radioGroup.addView(visibleToSome);
-		layout.addView(radioGroup);
-
-		createButton = new Button(this);
-		createButton.setLayoutParams(WRAP_WRAP);
-		createButton.setText(R.string.create_button);
-		createButton.setEnabled(false);
-		createButton.setOnClickListener(this);
-		layout.addView(createButton);
-
-		progress = new ProgressBar(this);
-		progress.setLayoutParams(WRAP_WRAP);
-		progress.setIndeterminate(true);
-		progress.setVisibility(GONE);
-		layout.addView(progress);
-
-		setContentView(layout);
-
-		FragmentManager fm = getSupportFragmentManager();
-		Fragment f = fm.findFragmentByTag("NoContactsDialog");
-		if(f == null) noContactsDialog = new NoContactsDialog();
-		else noContactsDialog = (NoContactsDialog) f;
-		noContactsDialog.setListener(this);
-
-		f = fm.findFragmentByTag("SelectContactsDialog");
-		if(f == null) selectContactsDialog = new SelectContactsDialog();
-		else selectContactsDialog = (SelectContactsDialog) f;
-		selectContactsDialog.setListener(this);
-	}
-
-	private void enableOrDisableCreateButton() {
-		if(nameEntry == null || radioGroup == null || createButton == null)
-			return; // Activity not created yet
-		boolean nameNotEmpty = nameEntry.getText().length() > 0;
-		boolean visibilitySelected = radioGroup.getCheckedRadioButtonId() != -1;
-		createButton.setEnabled(nameNotEmpty && visibilitySelected);
-	}
-
-	public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
-		validateName();
-		return true;
-	}
-
-	public void onClick(View view) {
-		if(view == visibleToAll) {
-			enableOrDisableCreateButton();
-		} else if(view == visibleToSome) {
-			loadContacts();
-		} else if(view == createButton) {
-			if(!validateName()) return;
-			final String name = nameEntry.getText().toString();
-			final boolean all = visibleToAll.isChecked();
-			final Collection<ContactId> visible =
-					Collections.unmodifiableCollection(selected);
-			// Replace the button with a progress bar
-			createButton.setVisibility(GONE);
-			progress.setVisibility(VISIBLE);
-			// Create the blog in a background thread
-			cryptoExecutor.execute(new Runnable() {
-				public void run() {
-					KeyPair keyPair = crypto.generateSignatureKeyPair();
-					final byte[] publicKey = keyPair.getPublic().getEncoded();
-					final byte[] privateKey = keyPair.getPrivate().getEncoded();
-					LocalGroup g;
-					try {
-						g = groupFactory.createLocalGroup(name, publicKey,
-								privateKey);
-					} catch(IOException e) {
-						throw new RuntimeException(e);
-					}
-					storeLocalGroup(g, all, visible);
-				}
-			});
-		}
-	}
-
-	private void loadContacts() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<Contact> contacts = db.getContacts();
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Load took " + duration + " ms");
-					displayContacts(contacts);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void displayContacts(final Collection<Contact> contacts) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				FragmentManager fm = getSupportFragmentManager();
-				if(contacts.isEmpty()) {
-					noContactsDialog.show(fm, "NoContactsDialog");
-				} else {
-					selectContactsDialog.setContacts(contacts);
-					selectContactsDialog.show(fm, "SelectContactsDialog");
-				}
-			}
-		});
-	}
-
-	private void storeLocalGroup(final LocalGroup g, final boolean all,
-			final Collection<ContactId> visible) {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					db.addLocalGroup(g);
-					db.subscribe(g);
-					if(all) db.setVisibleToAll(g.getId(), true);
-					else db.setVisibility(g.getId(), visible);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Storing group took " + duration + " ms");
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-				runOnUiThread(new Runnable() {
-					public void run() {
-						finish();
-					}
-				});
-			}
-		});
-	}
-
-	private boolean validateName() {
-		if(nameEntry.getText().toString().equals("")) return false;
-		// Hide the soft keyboard
-		Object o = getSystemService(INPUT_METHOD_SERVICE);
-		((InputMethodManager) o).toggleSoftInput(HIDE_IMPLICIT_ONLY, 0);
-		return true;
-	}
-
-	public void contactCreationSelected() {
-		startActivity(new Intent(this, AddContactActivity.class));
-	}
-
-	public void contactCreationCancelled() {
-		enableOrDisableCreateButton();
-	}
-
-	public void contactsSelected(Collection<ContactId> selected) {
-		this.selected = selected;
-		enableOrDisableCreateButton();
-	}
-
-	public void contactSelectionCancelled() {
-		enableOrDisableCreateButton();
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/LocalGroupItem.java b/briar-android/src/net/sf/briar/android/blogs/LocalGroupItem.java
deleted file mode 100644
index cd7f893556bbf80276adf621537a1522a003d517..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/LocalGroupItem.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import net.sf.briar.api.messaging.LocalGroup;
-
-class LocalGroupItem {
-
-	static final LocalGroupItem NEW = new LocalGroupItem(null);
-
-	private final LocalGroup localGroup;
-
-	LocalGroupItem(LocalGroup localGroup) {
-		this.localGroup = localGroup;
-	}
-
-	LocalGroup getLocalGroup() {
-		return localGroup;
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/LocalGroupItemComparator.java b/briar-android/src/net/sf/briar/android/blogs/LocalGroupItemComparator.java
deleted file mode 100644
index b6943000cefa54cf75743c3f15af55c55cef6136..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/LocalGroupItemComparator.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static net.sf.briar.android.blogs.LocalGroupItem.NEW;
-
-import java.util.Comparator;
-
-class LocalGroupItemComparator implements Comparator<LocalGroupItem> {
-
-	static final LocalGroupItemComparator INSTANCE =
-			new LocalGroupItemComparator();
-
-	public int compare(LocalGroupItem a, LocalGroupItem b) {
-		if(a == b) return 0;
-		if(a == NEW) return 1;
-		if(b == NEW) return -1;
-		String aName = a.getLocalGroup().getName();
-		String bName = b.getLocalGroup().getName();
-		return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/LocalGroupSpinnerAdapter.java b/briar-android/src/net/sf/briar/android/blogs/LocalGroupSpinnerAdapter.java
deleted file mode 100644
index c0ee80065dcb0c67bd70ecb265249536e9ec4959..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/LocalGroupSpinnerAdapter.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static net.sf.briar.android.blogs.LocalGroupItem.NEW;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import net.sf.briar.R;
-import android.content.Context;
-import android.content.res.Resources;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.SpinnerAdapter;
-import android.widget.TextView;
-
-class LocalGroupSpinnerAdapter extends BaseAdapter implements SpinnerAdapter {
-
-	private final Context ctx;
-	private final List<LocalGroupItem> list = new ArrayList<LocalGroupItem>();
-
-	LocalGroupSpinnerAdapter(Context ctx) {
-		this.ctx = ctx;
-	}
-
-	public void add(LocalGroupItem item) {
-		list.add(item);
-	}
-
-	public void clear() {
-		list.clear();
-	}
-
-	public int getCount() {
-		return list.isEmpty() ? 0 : list.size() + 1;
-	}
-
-	@Override
-	public View getDropDownView(int position, View convertView,
-			ViewGroup parent) {
-		return getView(position, convertView, parent);
-	}
-
-	public LocalGroupItem getItem(int position) {
-		if(position == list.size()) return NEW;
-		return list.get(position);
-	}
-
-	public long getItemId(int position) {
-		return android.R.layout.simple_spinner_item;
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		TextView name = new TextView(ctx);
-		name.setTextSize(18);
-		name.setMaxLines(1);
-		Resources res = ctx.getResources();
-		int pad = res.getInteger(R.integer.spinner_padding);
-		name.setPadding(pad, pad, pad, pad);
-		LocalGroupItem item = getItem(position);
-		if(item == NEW) name.setText(R.string.new_blog_item);
-		else name.setText(item.getLocalGroup().getName());
-		return name;
-	}
-
-	@Override
-	public boolean isEmpty() {
-		return list.isEmpty();
-	}
-
-	public void sort(Comparator<LocalGroupItem> comparator) {
-		Collections.sort(list, comparator);
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java
deleted file mode 100644
index 430e40e7d182680d89118befd2778156366e3f2a..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsActivity.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.blogs.ManageBlogsItem.NONE;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.android.util.ListLoadingProgressBar;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.db.event.DatabaseEvent;
-import net.sf.briar.api.db.event.DatabaseListener;
-import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent;
-import net.sf.briar.api.db.event.SubscriptionAddedEvent;
-import net.sf.briar.api.db.event.SubscriptionRemovedEvent;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.Group;
-import net.sf.briar.api.messaging.GroupStatus;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
-
-import com.google.inject.Inject;
-
-public class ManageBlogsActivity extends RoboFragmentActivity
-implements DatabaseListener, OnItemClickListener {
-
-	private static final Logger LOG =
-			Logger.getLogger(ManageBlogsActivity.class.getName());
-
-	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;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		adapter = new ManageBlogsAdapter(this);
-		list = new ListView(this);
-		list.setLayoutParams(MATCH_MATCH);
-		list.setAdapter(adapter);
-		list.setOnItemClickListener(this);
-
-		// Show a progress bar while the list is loading
-		loading = new ListLoadingProgressBar(this);
-		setContentView(loading);
-	}
-
-	@Override
-	public void onResume() {
-		super.onResume();
-		db.addListener(this);
-		loadAvailableGroups();
-	}
-
-	private void loadAvailableGroups() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					List<GroupStatus> available = new ArrayList<GroupStatus>();
-					for(GroupStatus s : db.getAvailableGroups())
-						if(s.getGroup().isRestricted()) available.add(s);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Load took " + duration + " ms");
-					available = Collections.unmodifiableList(available);
-					displayAvailableGroups(available);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void displayAvailableGroups(
-			final Collection<GroupStatus> available) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				setContentView(list);
-				adapter.clear();
-				for(GroupStatus g : available)
-					adapter.add(new ManageBlogsItem(g));
-				adapter.sort(ItemComparator.INSTANCE);
-				adapter.notifyDataSetChanged();
-			}
-		});
-	}
-
-	@Override
-	public void onPause() {
-		super.onPause();
-		db.removeListener(this);
-	}
-
-	public void eventOccurred(DatabaseEvent e) {
-		if(e instanceof RemoteSubscriptionsUpdatedEvent) {
-			if(LOG.isLoggable(INFO))
-				LOG.info("Remote subscriptions changed, reloading");
-			loadAvailableGroups();
-		} else if(e instanceof SubscriptionAddedEvent) {
-			Group g = ((SubscriptionAddedEvent) e).getGroup();
-			if(g.isRestricted()) {
-				if(LOG.isLoggable(INFO)) LOG.info("Group added, reloading");
-				loadAvailableGroups();
-			}
-		} else if(e instanceof SubscriptionRemovedEvent) {
-			Group g = ((SubscriptionRemovedEvent) e).getGroup();
-			if(g.isRestricted()) {
-				if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
-				loadAvailableGroups();
-			}
-		}
-	}
-
-	public void onItemClick(AdapterView<?> parent, View view, int position,
-			long id) {
-		ManageBlogsItem item = adapter.getItem(position);
-		if(item == NONE) return;
-		GroupStatus s = item.getGroupStatus();
-		Group g = s.getGroup();
-		Intent i = new Intent(this, ConfigureBlogActivity.class);
-		i.putExtra("net.sf.briar.GROUP_ID", g.getId().getBytes());
-		i.putExtra("net.sf.briar.GROUP_NAME", g.getName());
-		i.putExtra("net.sf.briar.PUBLIC_KEY", g.getPublicKey());
-		i.putExtra("net.sf.briar.SUBSCRIBED", s.isSubscribed());
-		i.putExtra("net.sf.briar.VISIBLE_TO_ALL", s.isVisibleToAll());
-		startActivity(i);
-	}
-
-	private static class ItemComparator implements Comparator<ManageBlogsItem> {
-
-		private static final ItemComparator INSTANCE = new ItemComparator();
-
-		public int compare(ManageBlogsItem a, ManageBlogsItem b) {
-			if(a == b) return 0;
-			if(a == NONE) return 1;
-			if(b == NONE) return -1;
-			String aName = a.getGroupStatus().getGroup().getName();
-			String bName = b.getGroupStatus().getGroup().getName();
-			return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
-		}
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java
deleted file mode 100644
index 6afe109f1774b0edb1f196d8f5ef386375840510..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsAdapter.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.view.Gravity.CENTER;
-import static android.view.View.INVISIBLE;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static android.widget.LinearLayout.VERTICAL;
-import static net.sf.briar.android.blogs.ManageBlogsItem.NONE;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import net.sf.briar.R;
-import net.sf.briar.api.messaging.GroupStatus;
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-class ManageBlogsAdapter extends BaseAdapter {
-
-	private final Context ctx;
-	private final List<ManageBlogsItem> list = new ArrayList<ManageBlogsItem>();
-
-	ManageBlogsAdapter(Context ctx) {
-		this.ctx = ctx;
-	}
-
-	public void add(ManageBlogsItem item) {
-		list.add(item);
-	}
-
-	public void clear() {
-		list.clear();
-	}
-
-	public int getCount() {
-		return list.isEmpty() ? 1 : list.size();
-	}
-
-	public ManageBlogsItem getItem(int position) {
-		return list.isEmpty() ? NONE : list.get(position);
-	}
-
-	public long getItemId(int position) {
-		return android.R.layout.simple_expandable_list_item_1;
-	}
-
-	public View getView(int position, View convertView, ViewGroup parent) {
-		ManageBlogsItem item = getItem(position);
-
-		if(item == NONE) {
-			TextView none = new TextView(ctx);
-			none.setGravity(CENTER);
-			none.setTextSize(18);
-			none.setPadding(10, 10, 10, 10);
-			none.setText(R.string.no_blogs_available);
-			return none;
-		}
-
-		GroupStatus s = item.getGroupStatus();
-		LinearLayout layout = new LinearLayout(ctx);
-		layout.setOrientation(HORIZONTAL);
-
-		ImageView subscribed = new ImageView(ctx);
-		subscribed.setPadding(5, 5, 5, 5);
-		subscribed.setImageResource(R.drawable.navigation_accept);
-		if(!s.isSubscribed()) subscribed.setVisibility(INVISIBLE);
-		layout.addView(subscribed);
-
-		LinearLayout innerLayout = new LinearLayout(ctx);
-		innerLayout.setOrientation(VERTICAL);
-
-		TextView name = new TextView(ctx);
-		name.setTextSize(18);
-		name.setMaxLines(1);
-		name.setPadding(0, 10, 10, 10);
-		name.setText(s.getGroup().getName());
-		innerLayout.addView(name);
-
-		TextView status = new TextView(ctx);
-		status.setTextSize(14);
-		status.setPadding(0, 0, 10, 10);
-		if(s.isSubscribed()) {
-			if(s.isVisibleToAll()) status.setText(R.string.subscribed_all);
-			else status.setText(R.string.subscribed_some);
-		} else {
-			status.setText(R.string.not_subscribed);
-		}
-		innerLayout.addView(status);
-		layout.addView(innerLayout);
-
-		return layout;
-	}
-
-	@Override
-	public boolean isEmpty() {
-		return false;
-	}
-
-	public void remove(ManageBlogsItem item) {
-		list.remove(item);
-	}
-
-	public void sort(Comparator<ManageBlogsItem> comparator) {
-		Collections.sort(list, comparator);
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java b/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java
deleted file mode 100644
index dfa61ea77db41184339d4b5e82cf4b0d95372084..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/ManageBlogsItem.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import net.sf.briar.api.messaging.GroupStatus;
-
-class ManageBlogsItem {
-
-	static final ManageBlogsItem NONE = new ManageBlogsItem(null);
-
-	private final GroupStatus status;
-
-	ManageBlogsItem(GroupStatus status) {
-		this.status = status;
-	}
-
-	GroupStatus getGroupStatus() {
-		return status;
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/NoBlogsDialog.java b/briar-android/src/net/sf/briar/android/blogs/NoBlogsDialog.java
deleted file mode 100644
index b835960ae9e768a9627552c37abf89fd1cc2f2ef..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/NoBlogsDialog.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import net.sf.briar.R;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-public class NoBlogsDialog extends DialogFragment {
-
-	private Listener listener = null;
-
-	void setListener(Listener listener) {
-		this.listener = listener;
-	}
-
-	@Override
-	public Dialog onCreateDialog(Bundle state) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-		builder.setMessage(R.string.no_blogs);
-		builder.setPositiveButton(R.string.create_button,
-				new DialogInterface.OnClickListener() {
-			public void onClick(DialogInterface dialog, int id) {
-				listener.blogCreationSelected();
-			}
-		});
-		builder.setNegativeButton(R.string.cancel_button,
-				new DialogInterface.OnClickListener() {
-			public void onClick(DialogInterface dialog, int id) {
-				listener.blogCreationCancelled();
-			}
-		});
-		return builder.create();
-	}
-
-	interface Listener {
-
-		void blogCreationSelected();
-
-		void blogCreationCancelled();
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/NotYourBlogDialog.java b/briar-android/src/net/sf/briar/android/blogs/NotYourBlogDialog.java
deleted file mode 100644
index c306339de1000db054b84d75f985a1e5fa0206dc..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/NotYourBlogDialog.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import net.sf.briar.R;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-public class NotYourBlogDialog extends DialogFragment {
-
-	private static final DialogInterface.OnClickListener IGNORE =
-			new DialogInterface.OnClickListener() {
-		public void onClick(DialogInterface dialog, int which) {}
-	};
-
-	@Override
-	public Dialog onCreateDialog(Bundle state) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-		builder.setMessage(R.string.not_your_blog);
-		builder.setPositiveButton(R.string.ok_button, IGNORE);
-		return builder.create();
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java b/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java
deleted file mode 100644
index f243acb1f9aeff4553aa0c52789bfa97f472c979..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/ReadBlogPostActivity.java
+++ /dev/null
@@ -1,297 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.view.Gravity.CENTER;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static android.widget.LinearLayout.VERTICAL;
-import static java.text.DateFormat.SHORT;
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP_1;
-import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP_1;
-import static net.sf.briar.api.messaging.Rating.BAD;
-import static net.sf.briar.api.messaging.Rating.GOOD;
-import static net.sf.briar.api.messaging.Rating.UNRATED;
-
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.util.HorizontalBorder;
-import net.sf.briar.android.util.HorizontalSpace;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.db.NoSuchMessageException;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.GroupId;
-import net.sf.briar.api.messaging.MessageId;
-import net.sf.briar.api.messaging.Rating;
-import roboguice.activity.RoboFragmentActivity;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.text.format.DateUtils;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import com.google.inject.Inject;
-
-public class ReadBlogPostActivity extends RoboFragmentActivity
-implements OnClickListener {
-
-	static final int RESULT_REPLY = RESULT_FIRST_USER;
-	static final int RESULT_PREV = RESULT_FIRST_USER + 1;
-	static final int RESULT_NEXT = RESULT_FIRST_USER + 2;
-
-	private static final Logger LOG =
-			Logger.getLogger(ReadBlogPostActivity.class.getName());
-
-	private GroupId groupId = null;
-	private boolean postable = false;
-	private Rating rating = UNRATED;
-	private boolean read;
-	private ImageView thumb = null;
-	private ImageButton readButton = null, prevButton = null, nextButton = null;
-	private ImageButton replyButton = null;
-	private TextView content = null;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject private volatile DatabaseComponent db;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-	private volatile MessageId messageId = null;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		Intent i = getIntent();
-		byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
-		if(b == null) throw new IllegalStateException();
-		groupId = new GroupId(b);
-		String groupName = i.getStringExtra("net.sf.briar.GROUP_NAME");
-		if(groupName == null) throw new IllegalStateException();
-		setTitle(groupName);
-		postable = i.getBooleanExtra("net.sf.briar.POSTABLE", false);
-		b = i.getByteArrayExtra("net.sf.briar.MESSAGE_ID");
-		if(b == null) throw new IllegalStateException();
-		messageId = new MessageId(b);
-		String authorName = i.getStringExtra("net.sf.briar.AUTHOR_NAME");
-		String r = i.getStringExtra("net.sf.briar.RATING");
-		if(r != null) rating = Rating.valueOf(r);
-		String contentType = i.getStringExtra("net.sf.briar.CONTENT_TYPE");
-		if(contentType == null) throw new IllegalStateException();
-		long timestamp = i.getLongExtra("net.sf.briar.TIMESTAMP", -1);
-		if(timestamp == -1) throw new IllegalStateException();
-
-		if(state == null) {
-			read = false;
-			setReadInDatabase(true);
-		} else {
-			read = state.getBoolean("net.sf.briar.READ");
-		}
-
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_WRAP);
-		layout.setOrientation(VERTICAL);
-
-		ScrollView scrollView = new ScrollView(this);
-		// Give me all the width and all the unused height
-		scrollView.setLayoutParams(MATCH_WRAP_1);
-
-		LinearLayout message = new LinearLayout(this);
-		message.setOrientation(VERTICAL);
-		Resources res = getResources();
-		message.setBackgroundColor(res.getColor(R.color.content_background));
-
-		LinearLayout header = new LinearLayout(this);
-		header.setLayoutParams(MATCH_WRAP);
-		header.setOrientation(HORIZONTAL);
-		header.setGravity(CENTER_VERTICAL);
-
-		thumb = new ImageView(this);
-		thumb.setPadding(5, 5, 5, 5);
-		if(rating == GOOD) thumb.setImageResource(R.drawable.rating_good);
-		else if(rating == BAD) thumb.setImageResource(R.drawable.rating_bad);
-		else thumb.setImageResource(R.drawable.rating_unrated);
-		header.addView(thumb);
-
-		TextView name = new TextView(this);
-		// Give me all the unused width
-		name.setLayoutParams(WRAP_WRAP_1);
-		name.setTextSize(18);
-		name.setMaxLines(1);
-		name.setPadding(0, 10, 10, 10);
-		if(authorName == null) {
-			name.setTextColor(res.getColor(R.color.anonymous_author));
-			name.setText(R.string.anonymous);
-		} else {
-			name.setText(authorName);
-		}
-		header.addView(name);
-
-		TextView date = new TextView(this);
-		date.setTextSize(14);
-		date.setPadding(0, 10, 10, 10);
-		long now = System.currentTimeMillis();
-		date.setText(DateUtils.formatSameDayTime(timestamp, now, SHORT, SHORT));
-		header.addView(date);
-		message.addView(header);
-
-		if(contentType.equals("text/plain")) {
-			// Load and display the message body
-			content = new TextView(this);
-			content.setPadding(10, 0, 10, 10);
-			message.addView(content);
-			loadMessageBody();
-		}
-		scrollView.addView(message);
-		layout.addView(scrollView);
-
-		layout.addView(new HorizontalBorder(this));
-
-		LinearLayout footer = new LinearLayout(this);
-		footer.setLayoutParams(MATCH_WRAP);
-		footer.setOrientation(HORIZONTAL);
-		footer.setGravity(CENTER);
-
-		readButton = new ImageButton(this);
-		readButton.setBackgroundResource(0);
-		if(read) readButton.setImageResource(R.drawable.content_unread);
-		else readButton.setImageResource(R.drawable.content_read);
-		readButton.setOnClickListener(this);
-		footer.addView(readButton);
-		footer.addView(new HorizontalSpace(this));
-
-		prevButton = new ImageButton(this);
-		prevButton.setBackgroundResource(0);
-		prevButton.setImageResource(R.drawable.navigation_previous_item);
-		prevButton.setOnClickListener(this);
-		footer.addView(prevButton);
-		footer.addView(new HorizontalSpace(this));
-
-		nextButton = new ImageButton(this);
-		nextButton.setBackgroundResource(0);
-		nextButton.setImageResource(R.drawable.navigation_next_item);
-		nextButton.setOnClickListener(this);
-		footer.addView(nextButton);
-		footer.addView(new HorizontalSpace(this));
-
-		replyButton = new ImageButton(this);
-		replyButton.setBackgroundResource(0);
-		replyButton.setImageResource(R.drawable.social_reply_all);
-		replyButton.setOnClickListener(this);
-		footer.addView(replyButton);
-		layout.addView(footer);
-
-		setContentView(layout);
-	}
-
-	private void setReadInDatabase(final boolean read) {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					db.setReadFlag(messageId, read);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Setting flag took " + duration + " ms");
-					setReadInUi(read);
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void setReadInUi(final boolean read) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				ReadBlogPostActivity.this.read = read;
-				if(read) readButton.setImageResource(R.drawable.content_unread);
-				else readButton.setImageResource(R.drawable.content_read);
-			}
-		});
-	}
-
-	private void loadMessageBody() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					byte[] body = db.getMessageBody(messageId);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Loading message took " + duration + " ms");
-					final String text = new String(body, "UTF-8");
-					runOnUiThread(new Runnable() {
-						public void run() {
-							content.setText(text);
-						}
-					});
-				} catch(NoSuchMessageException e) {
-					if(LOG.isLoggable(INFO)) LOG.info("Message removed");
-					runOnUiThread(new Runnable() {
-						public void run() {
-							finish();
-						}
-					});
-				} 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 database");
-					Thread.currentThread().interrupt();
-				} catch(UnsupportedEncodingException e) {
-					throw new RuntimeException(e);
-				}
-			}
-		});
-	}
-
-	@Override
-	public void onSaveInstanceState(Bundle state) {
-		super.onSaveInstanceState(state);
-		state.putBoolean("net.sf.briar.READ", read);
-	}
-
-	public void onClick(View view) {
-		if(view == readButton) {
-			setReadInDatabase(!read);
-		} else if(view == prevButton) {
-			setResult(RESULT_PREV);
-			finish();
-		} else if(view == nextButton) {
-			setResult(RESULT_NEXT);
-			finish();
-		} else if(view == replyButton) {
-			if(postable) {
-				Intent i = new Intent(this, WriteBlogPostActivity.class);
-				i.putExtra("net.sf.briar.GROUP_ID", groupId.getBytes());
-				i.putExtra("net.sf.briar.PARENT_ID", messageId.getBytes());
-				startActivity(i);
-				setResult(RESULT_REPLY);
-				finish();
-			} else {
-				NotYourBlogDialog dialog = new NotYourBlogDialog();
-				dialog.show(getSupportFragmentManager(), "NotYourBlogDialog");
-			}
-		}
-	}
-}
diff --git a/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java b/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java
deleted file mode 100644
index d28262c042c801d0fa1d30ecfecbe34e94189117..0000000000000000000000000000000000000000
--- a/briar-android/src/net/sf/briar/android/blogs/WriteBlogPostActivity.java
+++ /dev/null
@@ -1,357 +0,0 @@
-package net.sf.briar.android.blogs;
-
-import static android.text.InputType.TYPE_CLASS_TEXT;
-import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.widget.LinearLayout.HORIZONTAL;
-import static android.widget.LinearLayout.VERTICAL;
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.Collection;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import net.sf.briar.R;
-import net.sf.briar.android.identity.CreateIdentityActivity;
-import net.sf.briar.android.identity.LocalAuthorItem;
-import net.sf.briar.android.identity.LocalAuthorItemComparator;
-import net.sf.briar.android.identity.LocalAuthorSpinnerAdapter;
-import net.sf.briar.android.util.HorizontalSpace;
-import net.sf.briar.api.AuthorId;
-import net.sf.briar.api.LocalAuthor;
-import net.sf.briar.api.android.DatabaseUiExecutor;
-import net.sf.briar.api.crypto.CryptoComponent;
-import net.sf.briar.api.crypto.KeyParser;
-import net.sf.briar.api.crypto.PrivateKey;
-import net.sf.briar.api.db.DatabaseComponent;
-import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.lifecycle.LifecycleManager;
-import net.sf.briar.api.messaging.GroupId;
-import net.sf.briar.api.messaging.LocalGroup;
-import net.sf.briar.api.messaging.Message;
-import net.sf.briar.api.messaging.MessageFactory;
-import net.sf.briar.api.messaging.MessageId;
-import roboguice.activity.RoboActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.text.InputType;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.google.inject.Inject;
-
-public class WriteBlogPostActivity extends RoboActivity
-implements OnItemSelectedListener, OnClickListener {
-
-	private static final Logger LOG =
-			Logger.getLogger(WriteBlogPostActivity.class.getName());
-
-	@Inject private CryptoComponent crypto;
-	@Inject private MessageFactory messageFactory;
-	private LocalAuthorSpinnerAdapter fromAdapter = null;
-	private LocalGroupSpinnerAdapter toAdapter = null;
-	private Spinner fromSpinner = null, toSpinner = null;
-	private ImageButton sendButton = null;
-	private EditText content = null;
-	private AuthorId localAuthorId = null;
-	private GroupId localGroupId = null;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject private volatile DatabaseComponent db;
-	@Inject @DatabaseUiExecutor private volatile Executor dbUiExecutor;
-	@Inject private volatile LifecycleManager lifecycleManager;
-	private volatile LocalAuthor localAuthor = null;
-	private volatile LocalGroup localGroup = null;
-	private volatile MessageId parentId = null;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		Intent i = getIntent();
-		byte[] b = i.getByteArrayExtra("net.sf.briar.GROUP_ID");
-		if(b != null) localGroupId = new GroupId(b);
-		b = i.getByteArrayExtra("net.sf.briar.PARENT_ID");
-		if(b != null) parentId = new MessageId(b);
-
-		if(state != null) {
-			b = state.getByteArray("net.sf.briar.LOCAL_AUTHOR_ID");
-			if(b != null) localAuthorId = new AuthorId(b);
-			b = state.getByteArray("net.sf.briar.LOCAL_GROUP_ID");
-			if(b != null) localGroupId = new GroupId(b);
-		}
-
-		LinearLayout layout = new LinearLayout(this);
-		layout.setLayoutParams(MATCH_WRAP);
-		layout.setOrientation(VERTICAL);
-
-		LinearLayout header = new LinearLayout(this);
-		header.setLayoutParams(MATCH_WRAP);
-		header.setOrientation(HORIZONTAL);
-		header.setGravity(CENTER_VERTICAL);
-
-		TextView from = new TextView(this);
-		from.setTextSize(18);
-		from.setPadding(10, 10, 0, 10);
-		from.setText(R.string.from);
-		header.addView(from);
-
-		fromAdapter = new LocalAuthorSpinnerAdapter(this, true);
-		fromSpinner = new Spinner(this);
-		fromSpinner.setAdapter(fromAdapter);
-		fromSpinner.setOnItemSelectedListener(this);
-		header.addView(fromSpinner);
-
-		header.addView(new HorizontalSpace(this));
-
-		sendButton = new ImageButton(this);
-		sendButton.setBackgroundResource(0);
-		sendButton.setImageResource(R.drawable.social_send_now);
-		sendButton.setEnabled(false); // Enabled when a group is selected
-		sendButton.setOnClickListener(this);
-		header.addView(sendButton);
-		layout.addView(header);
-
-		header = new LinearLayout(this);
-		header.setLayoutParams(MATCH_WRAP);
-		header.setOrientation(HORIZONTAL);
-		header.setGravity(CENTER_VERTICAL);
-
-		TextView to = new TextView(this);
-		to.setTextSize(18);
-		to.setPadding(10, 0, 0, 10);
-		to.setText(R.string.to);
-		header.addView(to);
-
-		toAdapter = new LocalGroupSpinnerAdapter(this);
-		toSpinner = new Spinner(this);
-		toSpinner.setAdapter(toAdapter);
-		toSpinner.setOnItemSelectedListener(this);
-		header.addView(toSpinner);
-		layout.addView(header);
-
-		content = new EditText(this);
-		content.setId(1);
-		int inputType = TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE
-				| TYPE_TEXT_FLAG_CAP_SENTENCES;
-		content.setInputType(inputType);
-		layout.addView(content);
-
-		setContentView(layout);
-	}
-
-	@Override
-	public void onResume() {
-		super.onResume();
-		loadLocalAuthors();
-		loadLocalGroups();
-	}
-
-	private void loadLocalAuthors() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<LocalAuthor> localAuthors = db.getLocalAuthors();
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Loading authors took " + duration + " ms");
-					displayLocalAuthors(localAuthors);
-				} catch(DbException e) {
-					if(LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				} catch(InterruptedException e) {
-					LOG.info("Interrupted while waiting for database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void displayLocalAuthors(
-			final Collection<LocalAuthor> localAuthors) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				if(localAuthors.isEmpty()) throw new IllegalStateException();
-				fromAdapter.clear();
-				for(LocalAuthor a : localAuthors)
-					fromAdapter.add(new LocalAuthorItem(a));
-				fromAdapter.sort(LocalAuthorItemComparator.INSTANCE);
-				fromAdapter.notifyDataSetChanged();
-				int count = fromAdapter.getCount();
-				for(int i = 0; i < count; i++) {
-					LocalAuthorItem item = fromAdapter.getItem(i);
-					if(item == LocalAuthorItem.ANONYMOUS) continue;
-					if(item == LocalAuthorItem.NEW) continue;
-					if(item.getLocalAuthor().getId().equals(localAuthorId)) {
-						localAuthor = item.getLocalAuthor();
-						fromSpinner.setSelection(i);
-						break;
-					}
-				}
-			}
-		});
-	}
-
-	private void loadLocalGroups() {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					Collection<LocalGroup> groups = db.getLocalGroups();
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Loading groups took " + duration + " ms");
-					displayLocalGroups(groups);
-				} catch(DbException e) {
-					if(LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				} catch(InterruptedException e) {
-					LOG.info("Interrupted while waiting for database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-
-	private void displayLocalGroups(final Collection<LocalGroup> groups) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				if(groups.isEmpty()) finish();
-				toAdapter.clear();
-				for(LocalGroup g : groups) toAdapter.add(new LocalGroupItem(g));
-				toAdapter.sort(LocalGroupItemComparator.INSTANCE);
-				toAdapter.notifyDataSetChanged();
-				int count = toAdapter.getCount();
-				for(int i = 0; i < count; i++) {
-					LocalGroupItem item = toAdapter.getItem(i);
-					if(item == LocalGroupItem.NEW) continue;
-					if(item.getLocalGroup().getId().equals(localGroupId)) {
-						localGroup = item.getLocalGroup();
-						toSpinner.setSelection(i);
-						break;
-					}
-				}
-			}
-		});
-	}
-
-	@Override
-	public void onSaveInstanceState(Bundle state) {
-		super.onSaveInstanceState(state);
-		if(localAuthorId != null) {
-			byte[] b =  localAuthorId.getBytes();
-			state.putByteArray("net.sf.briar.LOCAL_AUTHOR_ID", b);
-		}
-		if(localGroupId != null) {
-			byte[] b =  localGroupId.getBytes();
-			state.putByteArray("net.sf.briar.LOCAL_GROUP_ID", b);
-		}
-	}
-
-	public void onItemSelected(AdapterView<?> parent, View view, int position,
-			long id) {
-		if(parent == fromSpinner) {
-			LocalAuthorItem item = fromAdapter.getItem(position);
-			if(item == LocalAuthorItem.ANONYMOUS) {
-				localAuthor = null;
-				localAuthorId = null;
-			} else if(item == LocalAuthorItem.NEW) {
-				localAuthor = null;
-				localAuthorId = null;
-				startActivity(new Intent(this, CreateIdentityActivity.class));
-			} else {
-				localAuthor = item.getLocalAuthor();
-				localAuthorId = localAuthor.getId();
-			}
-		} else if(parent == toSpinner) {
-			LocalGroupItem item = toAdapter.getItem(position);
-			if(item == LocalGroupItem.NEW) {
-				localGroup = null;
-				localGroupId = null;
-				startActivity(new Intent(this, CreateBlogActivity.class));
-			} else {
-				localGroup = item.getLocalGroup();
-				localGroupId = localGroup.getId();
-				sendButton.setEnabled(true);
-			}
-		}
-	}
-
-	public void onNothingSelected(AdapterView<?> parent) {
-		if(parent == fromSpinner) {
-			localAuthor = null;
-			localAuthorId = null;
-		} else if(parent == toSpinner) {
-			localGroup = null;
-			localGroupId = null;
-			sendButton.setEnabled(false);
-		}
-	}
-
-	public void onClick(View view) {
-		if(localGroup == null) throw new IllegalStateException();
-		try {
-			byte[] b = content.getText().toString().getBytes("UTF-8");
-			storeMessage(createMessage(b));
-		} catch(GeneralSecurityException e) {
-			throw new RuntimeException(e);
-		} catch(IOException e) {
-			throw new RuntimeException(e);
-		}
-		finish();
-	}
-
-	// FIXME: This should happen on a CryptoExecutor thread
-	private Message createMessage(byte[] body) throws IOException,
-	GeneralSecurityException {
-		KeyParser keyParser = crypto.getSignatureKeyParser();
-		byte[] groupKeyBytes = localGroup.getPrivateKey();
-		PrivateKey groupKey = keyParser.parsePrivateKey(groupKeyBytes);
-		if(localAuthor == null) {
-			return messageFactory.createAnonymousMessage(parentId, localGroup,
-					groupKey, "text/plain", body);
-		} else {
-			byte[] authorKeyBytes = localAuthor.getPrivateKey();
-			PrivateKey authorKey = keyParser.parsePrivateKey(authorKeyBytes);
-			return messageFactory.createPseudonymousMessage(parentId,
-					localGroup, groupKey, localAuthor, authorKey, "text/plain",
-					body);
-		}
-	}
-
-	private void storeMessage(final Message m) {
-		dbUiExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					long now = System.currentTimeMillis();
-					db.addLocalGroupMessage(m);
-					long duration = System.currentTimeMillis() - now;
-					if(LOG.isLoggable(INFO))
-						LOG.info("Storing message took " + duration + " ms");
-				} 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 database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
-	}
-}