diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java
index fa3671b5013b9fe29f2823d09719d0a578ec88bf..a144adb9e7e969d9b12b55acdf2cc8177fbb4d2b 100644
--- a/briar-android/src/org/briarproject/android/BaseActivity.java
+++ b/briar-android/src/org/briarproject/android/BaseActivity.java
@@ -12,7 +12,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.inputmethod.InputMethodManager.SHOW_FORCED;
 import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
 import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
 
@@ -62,18 +61,18 @@ public abstract class BaseActivity extends AppCompatActivity
 	}
 
 	@Override
-	protected void onResume() {
-		super.onResume();
+	protected void onStart() {
+		super.onStart();
 		for (ActivityLifecycleController alc : lifecycleControllers) {
-			alc.onActivityResume();
+			alc.onActivityStart();
 		}
 	}
 
 	@Override
-	protected void onPause() {
-		super.onPause();
+	protected void onStop() {
+		super.onStop();
 		for (ActivityLifecycleController alc : lifecycleControllers) {
-			alc.onActivityPause();
+			alc.onActivityStop();
 		}
 	}
 
diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java
index 4c01808af7cba45255b7d091657471145c1d3112..c0bda36a8a722b6526e075fa7bf73ea2526f1544 100644
--- a/briar-android/src/org/briarproject/android/BriarActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarActivity.java
@@ -34,10 +34,11 @@ public abstract class BriarActivity extends BaseActivity {
 			Logger.getLogger(BriarActivity.class.getName());
 
 	@Inject
-	protected BriarController briarController;
-	// TODO remove this when the deprecated method runOnDbThread is removed
+	BriarController briarController;
+
+	@Deprecated
 	@Inject
-	protected DbController dbController;
+	DbController dbController;
 
 	@Override
 	protected void onActivityResult(int request, int result, Intent data) {
@@ -49,8 +50,8 @@ public abstract class BriarActivity extends BaseActivity {
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		if (!briarController.hasEncryptionKey() && !isFinishing()) {
 			Intent i = new Intent(this, PasswordActivity.class);
 			i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
index 751700559ebc95d966a558eb0e4ad39458d51fea..5d69216a75ed1eafb08890864033c8b93587a399 100644
--- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java
+++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
@@ -141,8 +141,8 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		updateTransports();
 	}
 
diff --git a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
index 0015bc111e22d70032ce92114a1839cac71db4b5..7ff91c18bde74948718295728c12630f3b1483e4 100644
--- a/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/BaseControllerImpl.java
@@ -12,8 +12,6 @@ import org.briarproject.api.blogs.BlogManager;
 import org.briarproject.api.blogs.BlogPostHeader;
 import org.briarproject.api.db.DatabaseExecutor;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.event.BlogPostAddedEvent;
-import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.identity.IdentityManager;
@@ -47,7 +45,7 @@ abstract class BaseControllerImpl extends DbControllerImpl
 	private final Map<MessageId, BlogPostHeader> headerCache =
 			new ConcurrentHashMap<>();
 
-	protected volatile OnBlogPostAddedListener listener;
+	private volatile OnBlogPostAddedListener listener;
 
 	BaseControllerImpl(@DatabaseExecutor Executor dbExecutor,
 			LifecycleManager lifecycleManager, EventBus eventBus,
@@ -63,9 +61,7 @@ abstract class BaseControllerImpl extends DbControllerImpl
 	@Override
 	@CallSuper
 	public void onStart() {
-		if (listener == null)
-			throw new IllegalStateException(
-					"OnBlogPostAddedListener needs to be attached");
+		if (listener == null) throw new IllegalStateException();
 		eventBus.addListener(this);
 	}
 
@@ -75,26 +71,30 @@ abstract class BaseControllerImpl extends DbControllerImpl
 		eventBus.removeListener(this);
 	}
 
-	@Override
-	@CallSuper
-	public void eventOccurred(Event e) {
-		if (e instanceof BlogPostAddedEvent) {
-			final BlogPostAddedEvent b = (BlogPostAddedEvent) e;
-			LOG.info("New blog post added");
-			listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-				@Override
-				public void run() {
-					listener.onBlogPostAdded(b.getHeader(), b.isLocal());
-				}
-			});
-		}
-	}
-
 	@Override
 	public void setOnBlogPostAddedListener(OnBlogPostAddedListener listener) {
 		this.listener = listener;
 	}
 
+	void onBlogPostAdded(final BlogPostHeader h, final boolean local) {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				listener.onBlogPostAdded(h, local);
+			}
+		});
+	}
+
+	void onBlogRemoved() {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				listener.onBlogRemoved();
+			}
+		});
+	}
+
+
 	@Override
 	public void loadBlogPosts(final GroupId groupId,
 			final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
index 5394821f8751dce0fc439445c3ca645434026b56..64cee65a5b89d45644f6fab5674e5398b0e05e10 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogControllerImpl.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
+import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 
 public class BlogControllerImpl extends BaseControllerImpl
@@ -50,15 +51,15 @@ public class BlogControllerImpl extends BaseControllerImpl
 	}
 
 	@Override
-	public void onActivityResume() {
-		super.onStart(); // TODO: Should be called when activity starts. #609
+	public void onActivityStart() {
+		super.onStart();
 		notificationManager.blockNotification(groupId);
 		notificationManager.clearBlogPostNotification(groupId);
 	}
 
 	@Override
-	public void onActivityPause() {
-		super.onStop(); // TODO: Should be called when activity stops. #609
+	public void onActivityStop() {
+		super.onStop();
 		notificationManager.unblockNotification(groupId);
 	}
 
@@ -75,20 +76,16 @@ public class BlogControllerImpl extends BaseControllerImpl
 	public void eventOccurred(Event e) {
 		if (groupId == null) throw new IllegalStateException();
 		if (e instanceof BlogPostAddedEvent) {
-			BlogPostAddedEvent s = (BlogPostAddedEvent) e;
-			if (s.getGroupId().equals(groupId)) {
-				super.eventOccurred(e);
+			BlogPostAddedEvent b = (BlogPostAddedEvent) e;
+			if (b.getGroupId().equals(groupId)) {
+				LOG.info("Blog post added");
+				onBlogPostAdded(b.getHeader(), b.isLocal());
 			}
 		} else if (e instanceof GroupRemovedEvent) {
-			GroupRemovedEvent s = (GroupRemovedEvent) e;
-			if (s.getGroup().getId().equals(groupId)) {
+			GroupRemovedEvent g = (GroupRemovedEvent) e;
+			if (g.getGroup().getId().equals(groupId)) {
 				LOG.info("Blog removed");
-				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-					@Override
-					public void run() {
-						listener.onBlogRemoved();
-					}
-				});
+				onBlogRemoved();
 			}
 		}
 	}
@@ -115,11 +112,15 @@ public class BlogControllerImpl extends BaseControllerImpl
 			@Override
 			public void run() {
 				try {
+					long now = System.currentTimeMillis();
 					LocalAuthor a = identityManager.getLocalAuthor();
 					Blog b = blogManager.getBlog(groupId);
 					boolean ours = a.getId().equals(b.getAuthor().getId());
 					boolean removable = blogManager.canBeRemoved(groupId);
 					BlogItem blog = new BlogItem(b, ours, removable);
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Loading blog took " + duration + " ms");
 					handler.onResult(blog);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
@@ -138,8 +139,12 @@ public class BlogControllerImpl extends BaseControllerImpl
 			@Override
 			public void run() {
 				try {
+					long now = System.currentTimeMillis();
 					Blog b = blogManager.getBlog(groupId);
 					blogManager.removeBlog(b);
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Removing blog took " + duration + " ms");
 					handler.onResult(null);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
index 25d266c312050286eeeb69289005f19930edb29e..eb655209108c6a290394c31c3fc3241d4f711c12 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
@@ -123,18 +123,13 @@ public class BlogFragment extends BaseFragment implements
 	public void onStart() {
 		super.onStart();
 		loadBlog();
-	}
-
-	@Override
-	public void onResume() {
-		super.onResume();
 		loadBlogPosts(false);
 		list.startPeriodicUpdate();
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		list.stopPeriodicUpdate();
 	}
 
@@ -215,9 +210,11 @@ public class BlogFragment extends BaseFragment implements
 						adapter.add(post);
 						if (local) {
 							list.scrollToPosition(0);
-							displaySnackbar(R.string.blogs_blog_post_created, false);
+							displaySnackbar(R.string.blogs_blog_post_created,
+									false);
 						} else {
-							displaySnackbar(R.string.blogs_blog_post_received, true);
+							displaySnackbar(R.string.blogs_blog_post_received,
+									true);
 						}
 					}
 
@@ -236,11 +233,11 @@ public class BlogFragment extends BaseFragment implements
 						listener) {
 					@Override
 					public void onResultUi(Collection<BlogPostItem> posts) {
-						if (posts.size() > 0) {
+						if (posts.isEmpty()) {
+							list.showData();
+						} else {
 							adapter.addAll(posts);
 							if (reload) list.scrollToPosition(0);
-						} else {
-							list.showData();
 						}
 					}
 
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedController.java b/briar-android/src/org/briarproject/android/blogs/FeedController.java
index e2934f49fd67757128d0dc521f020d86953fcb4a..90015b066f6a17f9a79dc76c1d8dd66e6fc04cde 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedController.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedController.java
@@ -1,7 +1,6 @@
 package org.briarproject.android.blogs;
 
 import org.briarproject.android.controller.handler.ResultExceptionHandler;
-import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.api.blogs.Blog;
 import org.briarproject.api.db.DbException;
 
@@ -12,6 +11,6 @@ public interface FeedController extends BaseController {
 	void loadBlogPosts(
 			ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler);
 
-	void loadPersonalBlog(ResultHandler<Blog> resultHandler);
+	void loadPersonalBlog(ResultExceptionHandler<Blog, DbException> handler);
 
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
index 0d85144d8dd08e5389cfe62019216d876493fd6e..faf626b5462e281dd83e95e61a52f7eda29e6fa3 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedControllerImpl.java
@@ -2,14 +2,16 @@ package org.briarproject.android.blogs;
 
 import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.controller.handler.ResultExceptionHandler;
-import org.briarproject.android.controller.handler.ResultHandler;
 import org.briarproject.api.blogs.Blog;
 import org.briarproject.api.blogs.BlogManager;
 import org.briarproject.api.db.DatabaseExecutor;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.NoSuchGroupException;
 import org.briarproject.api.db.NoSuchMessageException;
+import org.briarproject.api.event.BlogPostAddedEvent;
+import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
+import org.briarproject.api.event.GroupRemovedEvent;
 import org.briarproject.api.identity.Author;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.lifecycle.LifecycleManager;
@@ -52,15 +54,28 @@ public class FeedControllerImpl extends BaseControllerImpl
 		notificationManager.unblockAllBlogPostNotifications();
 	}
 
+	@Override
+	public void eventOccurred(Event e) {
+		if (e instanceof BlogPostAddedEvent) {
+			BlogPostAddedEvent b = (BlogPostAddedEvent) e;
+			LOG.info("Blog post added");
+			onBlogPostAdded(b.getHeader(), b.isLocal());
+		} else if (e instanceof GroupRemovedEvent) {
+			GroupRemovedEvent g = (GroupRemovedEvent) e;
+			if (g.getGroup().getClientId().equals(blogManager.getClientId())) {
+				LOG.info("Blog removed");
+				onBlogRemoved();
+			}
+		}
+	}
+
 	@Override
 	public void loadBlogPosts(
 			final ResultExceptionHandler<Collection<BlogPostItem>, DbException> handler) {
-		LOG.info("Loading all blog posts...");
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
 				try {
-					// load blog posts
 					long now = System.currentTimeMillis();
 					Collection<BlogPostItem> posts = new ArrayList<>();
 					for (Blog b : blogManager.getBlogs()) {
@@ -85,24 +100,23 @@ public class FeedControllerImpl extends BaseControllerImpl
 	}
 
 	@Override
-	public void loadPersonalBlog(final ResultHandler<Blog> resultHandler) {
-		LOG.info("Loading personal blog...");
+	public void loadPersonalBlog(
+			final ResultExceptionHandler<Blog, DbException> handler) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
 				try {
-					// load blog posts
 					long now = System.currentTimeMillis();
 					Author a = identityManager.getLocalAuthor();
 					Blog b = blogManager.getPersonalBlog(a);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
-						LOG.info("Loading pers. blog took " + duration + " ms");
-					resultHandler.onResult(b);
+						LOG.info("Loading blog took " + duration + " ms");
+					handler.onResult(b);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
-					resultHandler.onResult(null);
+					handler.onException(e);
 				}
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
index d07a800d59a6bbe61b5de4b0e453e68326b2ece9..6f960d3c128a310de26d699dbe8919c7f910c100 100644
--- a/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/FeedFragment.java
@@ -20,7 +20,6 @@ import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.blogs.BaseController.OnBlogPostAddedListener;
 import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
 import org.briarproject.android.controller.handler.UiResultExceptionHandler;
-import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.android.view.BriarRecyclerView;
 import org.briarproject.api.blogs.Blog;
@@ -99,40 +98,56 @@ public class FeedFragment extends BaseFragment implements
 	public void onStart() {
 		super.onStart();
 		feedController.onStart();
+		loadPersonalBlog();
+		loadBlogPosts(false);
+	}
+
+	@Override
+	public void onStop() {
+		super.onStop();
+		feedController.onStop();
+		adapter.clear();
+		list.showProgressBar();
+		list.stopPeriodicUpdate();
+		// TODO save list position in database/preferences?
+	}
+
+	private void loadPersonalBlog() {
 		feedController.loadPersonalBlog(
-				new UiResultHandler<Blog>(listener) {
+				new UiResultExceptionHandler<Blog, DbException>(listener) {
 					@Override
 					public void onResultUi(Blog b) {
 						personalBlog = b;
 					}
+
+					@Override
+					public void onExceptionUi(DbException exception) {
+						// TODO: Decide how to handle errors in the UI
+						finish();
+					}
 				});
+	}
+
+	private void loadBlogPosts(final boolean clear) {
 		feedController.loadBlogPosts(
 				new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
 						listener) {
 					@Override
 					public void onResultUi(Collection<BlogPostItem> posts) {
-						if (posts.isEmpty()) {
-							list.showData();
-						} else {
-							adapter.addAll(posts);
-						}
+						if (clear) adapter.setItems(posts);
+						else adapter.addAll(posts);
+						if (posts.isEmpty()) list.showData();
 					}
+
 					@Override
-					public void onExceptionUi(DbException exception) {
-						// TODO
+					public void onExceptionUi(DbException e) {
+						// TODO: Decide how to handle errors in the UI
+						finish();
 					}
 				});
 		list.startPeriodicUpdate();
 	}
 
-	@Override
-	public void onStop() {
-		super.onStop();
-		feedController.onStop();
-		list.stopPeriodicUpdate();
-		// TODO save list position in database/preferences?
-	}
-
 	@Override
 	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
 		inflater.inflate(R.menu.blogs_feed_actions, menu);
@@ -185,9 +200,11 @@ public class FeedFragment extends BaseFragment implements
 							showSnackBar(R.string.blogs_blog_post_received);
 						}
 					}
+
 					@Override
 					public void onExceptionUi(DbException exception) {
 						// TODO: Decide how to handle errors in the UI
+						finish();
 					}
 				}
 		);
@@ -234,6 +251,6 @@ public class FeedFragment extends BaseFragment implements
 
 	@Override
 	public void onBlogRemoved() {
-		finish();
+		loadBlogPosts(true);
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
index 2fe3ad30ccf90ac3496ef0d5989cbd4b6856e45d..0eb6df792e525221d74becf993e0ba3a20665cde 100644
--- a/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/RssFeedManageActivity.java
@@ -37,9 +37,7 @@ public class RssFeedManageActivity extends BriarActivity
 
 	private BriarRecyclerView list;
 	private RssFeedAdapter adapter;
-
-	// Fields that are accessed from background threads must be volatile
-	private volatile GroupId groupId = null;
+	private GroupId groupId;
 
 	@Inject
 	@SuppressWarnings("WeakerAccess")
@@ -65,11 +63,18 @@ public class RssFeedManageActivity extends BriarActivity
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		loadFeeds();
 	}
 
+	@Override
+	public void onStop() {
+		super.onStop();
+		adapter.clear();
+		list.showProgressBar();
+	}
+
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		MenuInflater inflater = getMenuInflater();
@@ -139,7 +144,7 @@ public class RssFeedManageActivity extends BriarActivity
 		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (feeds.size() == 0) list.showData();
+				if (feeds.isEmpty()) list.showData();
 				else adapter.addAll(feeds);
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
index 70d326ca42266b50da015e30191740ad786e0a2c..014f0d1f48541911a14c218008bb78fd70429165 100644
--- a/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
+++ b/briar-android/src/org/briarproject/android/blogs/WriteBlogPostActivity.java
@@ -94,15 +94,15 @@ public class WriteBlogPostActivity extends BriarActivity
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
-		notificationManager.unblockNotification(groupId);
+	public void onStart() {
+		super.onStart();
+		notificationManager.blockNotification(groupId);
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
-		notificationManager.blockNotification(groupId);
+	public void onStop() {
+		super.onStop();
+		notificationManager.unblockNotification(groupId);
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
index aa48714f77f086e031054e7d5929e5b70c11ed24..cd01ad1a426faa92757372bade5fe2db41005e7f 100644
--- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
@@ -13,7 +13,6 @@ import org.briarproject.R;
 import org.briarproject.android.util.BriarAdapter;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.identity.Author;
-import org.briarproject.api.sync.GroupId;
 import org.briarproject.util.StringUtils;
 
 import im.delight.android.identicons.IdenticonDrawable;
@@ -90,17 +89,6 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
 		return INVALID_POSITION; // Not found
 	}
 
-	int findItemPosition(GroupId g) {
-		int count = getItemCount();
-		for (int i = 0; i < count; i++) {
-			ContactListItem item = getItemAt(i);
-			if (item != null && item.getGroupId().equals(g)) {
-				return i;
-			}
-		}
-		return INVALID_POSITION; // Not found
-	}
-
 	public static class BaseContactHolder extends RecyclerView.ViewHolder {
 
 		public final ViewGroup layout;
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index 891bfcfbc254b38e4b3242b1e092ae8d9d39f211..d640439a68697a7da96bf0ea3aacc48eda1adb0f 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -170,8 +170,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		notificationManager.blockAllContactNotifications();
 		notificationManager.clearAllContactNotifications();
 		eventBus.addListener(this);
@@ -180,8 +180,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 		notificationManager.unblockAllContactNotifications();
 		adapter.clear();
@@ -213,10 +213,10 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 							// Continue
 						}
 					}
-					displayContacts(contacts);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Full load took " + duration + " ms");
+					displayContacts(contacts);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -229,7 +229,7 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (contacts.size() == 0) list.showData();
+				if (contacts.isEmpty()) list.showData();
 				else adapter.addAll(contacts);
 			}
 		});
@@ -238,40 +238,45 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactStatusChangedEvent) {
-			LOG.info("Contact Status changed, reloading");
-			// is also broadcast when contact was added
-			loadContacts();
+			ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
+			if (c.isActive()) {
+				LOG.info("Contact activated, reloading");
+				loadContacts();
+			} else {
+				LOG.info("Contact deactivated, removing item");
+				removeItem(c.getContactId());
+			}
 		} else if (e instanceof ContactConnectedEvent) {
 			setConnected(((ContactConnectedEvent) e).getContactId(), true);
 		} else if (e instanceof ContactDisconnectedEvent) {
 			setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
 		} else if (e instanceof ContactRemovedEvent) {
-			LOG.info("Contact removed");
+			LOG.info("Contact removed, removing item");
 			removeItem(((ContactRemovedEvent) e).getContactId());
 		} else if (e instanceof PrivateMessageReceivedEvent) {
-			LOG.info("Message received, update contact");
+			LOG.info("Private message received, updating item");
 			PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
 			PrivateMessageHeader h = p.getMessageHeader();
-			updateItem(p.getGroupId(), ConversationItem.from(h));
+			updateItem(p.getContactId(), ConversationItem.from(h));
 		} else if (e instanceof IntroductionRequestReceivedEvent) {
-			LOG.info("Introduction Request received, update contact");
+			LOG.info("Introduction request received, updating item");
 			IntroductionRequestReceivedEvent m =
 					(IntroductionRequestReceivedEvent) e;
 			IntroductionRequest ir = m.getIntroductionRequest();
 			updateItem(m.getContactId(), ConversationItem.from(ir));
 		} else if (e instanceof IntroductionResponseReceivedEvent) {
-			LOG.info("Introduction Response received, update contact");
+			LOG.info("Introduction response received, updating item");
 			IntroductionResponseReceivedEvent m =
 					(IntroductionResponseReceivedEvent) e;
 			IntroductionResponse ir = m.getIntroductionResponse();
 			updateItem(m.getContactId(), ConversationItem.from(ir));
 		} else if (e instanceof InvitationRequestReceivedEvent) {
-			LOG.info("Invitation Request received, update contact");
+			LOG.info("Invitation request received, updating item");
 			InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
 			InvitationRequest ir = m.getRequest();
 			updateItem(m.getContactId(), ConversationItem.from(ir));
 		} else if (e instanceof InvitationResponseReceivedEvent) {
-			LOG.info("Invitation Response received, update contact");
+			LOG.info("Invitation response received, updating item");
 			InvitationResponseReceivedEvent m =
 					(InvitationResponseReceivedEvent) e;
 			InvitationResponse ir = m.getResponse();
@@ -293,20 +298,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 		});
 	}
 
-	private void updateItem(final GroupId g, final ConversationItem m) {
-		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-			@Override
-			public void run() {
-				int position = adapter.findItemPosition(g);
-				ContactListItem item = adapter.getItemAt(position);
-				if (item != null) {
-					item.addMessage(m);
-					adapter.updateItemAt(position, item);
-				}
-			}
-		});
-	}
-
 	private void removeItem(final ContactId c) {
 		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 1d563ad0ce1679a7d218e911d083d3d270eb95d4..fd948d0aadca0ff38cc02730bbe007fe4d5d01d2 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -34,7 +34,6 @@ import org.briarproject.android.view.TextInputView;
 import org.briarproject.android.view.TextInputView.TextInputListener;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.blogs.BlogSharingManager;
-import org.briarproject.api.clients.BaseMessageHeader;
 import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
@@ -42,7 +41,6 @@ import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoExecutor;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.NoSuchContactException;
-import org.briarproject.api.db.NoSuchMessageException;
 import org.briarproject.api.event.ContactConnectedEvent;
 import org.briarproject.api.event.ContactDisconnectedEvent;
 import org.briarproject.api.event.ContactRemovedEvent;
@@ -150,7 +148,6 @@ public class ConversationActivity extends BriarActivity
 	private volatile ContactId contactId = null;
 	private volatile String contactName = null;
 	private volatile byte[] contactIdenticonKey = null;
-	private volatile boolean connected = false;
 
 	@SuppressWarnings("ConstantConditions")
 	@Override
@@ -214,18 +211,19 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		eventBus.addListener(this);
 		notificationManager.blockNotification(groupId);
 		notificationManager.clearPrivateMessageNotification(groupId);
-		loadData();
+		loadContactDetails();
+		loadMessages();
 		list.startPeriodicUpdate();
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 		notificationManager.unblockNotification(groupId);
 		list.stopPeriodicUpdate();
@@ -277,7 +275,7 @@ public class ConversationActivity extends BriarActivity
 		finish();
 	}
 
-	private void loadData() {
+	private void loadContactDetails() {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
@@ -291,13 +289,12 @@ public class ConversationActivity extends BriarActivity
 						contactIdenticonKey =
 								contact.getAuthor().getId().getBytes();
 					}
-					connected = connectionRegistry.isConnected(contactId);
+					boolean connected =
+							connectionRegistry.isConnected(contactId);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Loading contact took " + duration + " ms");
-					displayContactDetails();
-					// Load the messages here to make sure we have a contactId
-					loadMessages();
+					displayContactDetails(connected);
 				} catch (NoSuchContactException e) {
 					finishOnUiThread();
 				} catch (DbException e) {
@@ -308,7 +305,7 @@ public class ConversationActivity extends BriarActivity
 		});
 	}
 
-	private void displayContactDetails() {
+	private void displayContactDetails(final boolean connected) {
 		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
@@ -359,7 +356,7 @@ public class ConversationActivity extends BriarActivity
 					invitations.addAll(blogInvitations);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
-						LOG.info("Loading headers took " + duration + " ms");
+						LOG.info("Loading messages took " + duration + " ms");
 					displayMessages(headers, introductions, invitations);
 				} catch (NoSuchContactException e) {
 					finishOnUiThread();
@@ -378,13 +375,12 @@ public class ConversationActivity extends BriarActivity
 			@Override
 			public void run() {
 				textInputView.setSendButtonEnabled(true);
-				if (headers.isEmpty() && introductions.isEmpty() &&
-						invitations.isEmpty()) {
-					// we have no messages,
-					// so let the list know to hide progress bar
+				int size = headers.size() + introductions.size() +
+						invitations.size();
+				if (size == 0) {
 					list.showData();
 				} else {
-					List<ConversationItem> items = new ArrayList<>();
+					List<ConversationItem> items = new ArrayList<>(size);
 					for (PrivateMessageHeader h : headers) {
 						ConversationMessageItem item = ConversationItem.from(h);
 						byte[] body = bodyCache.get(h.getId());
@@ -392,28 +388,26 @@ public class ConversationActivity extends BriarActivity
 						else item.setBody(body);
 						items.add(item);
 					}
-					for (IntroductionMessage m : introductions) {
-						ConversationItem item;
-						if (m instanceof IntroductionRequest) {
-							item = ConversationItem
-									.from((IntroductionRequest) m);
+					for (IntroductionMessage im : introductions) {
+						if (im instanceof IntroductionRequest) {
+							IntroductionRequest ir = (IntroductionRequest) im;
+							items.add(ConversationItem.from(ir));
 						} else {
-							item = ConversationItem
+							IntroductionResponse ir = (IntroductionResponse) im;
+							items.add(ConversationItem
 									.from(ConversationActivity.this,
-											contactName,
-											(IntroductionResponse) m);
+											contactName, ir));
 						}
-						items.add(item);
 					}
-					for (InvitationMessage i : invitations) {
-						if (i instanceof InvitationRequest) {
-							InvitationRequest r = (InvitationRequest) i;
-							items.add(ConversationItem.from(r));
-						} else if (i instanceof InvitationResponse) {
-							InvitationResponse r = (InvitationResponse) i;
+					for (InvitationMessage im : invitations) {
+						if (im instanceof InvitationRequest) {
+							InvitationRequest ir = (InvitationRequest) im;
+							items.add(ConversationItem.from(ir));
+						} else if (im instanceof InvitationResponse) {
+							InvitationResponse ir = (InvitationResponse) im;
 							items.add(ConversationItem
 									.from(ConversationActivity.this,
-											contactName, r));
+											contactName, ir));
 						}
 					}
 					adapter.addAll(items);
@@ -435,8 +429,6 @@ public class ConversationActivity extends BriarActivity
 					if (LOG.isLoggable(INFO))
 						LOG.info("Loading body took " + duration + " ms");
 					displayMessageBody(m, body);
-				} catch (NoSuchMessageException e) {
-					// The item will be removed when we get the event
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -496,9 +488,10 @@ public class ConversationActivity extends BriarActivity
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					for (Map.Entry<MessageId, GroupId> e : unread.entrySet())
-						messagingManager
-								.setReadFlag(e.getValue(), e.getKey(), true);
+					for (Map.Entry<MessageId, GroupId> e : unread.entrySet()) {
+						messagingManager.setReadFlag(e.getValue(), e.getKey(),
+								true);
+					}
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Marking read took " + duration + " ms");
@@ -525,7 +518,6 @@ public class ConversationActivity extends BriarActivity
 				PrivateMessageHeader h = p.getMessageHeader();
 				addConversationItem(ConversationItem.from(h));
 				loadMessageBody(h.getId());
-				markMessageReadIfNew(h);
 			}
 		} else if (e instanceof MessagesSentEvent) {
 			MessagesSentEvent m = (MessagesSentEvent) e;
@@ -543,15 +535,13 @@ public class ConversationActivity extends BriarActivity
 			ContactConnectedEvent c = (ContactConnectedEvent) e;
 			if (c.getContactId().equals(contactId)) {
 				LOG.info("Contact connected");
-				connected = true;
-				displayContactDetails();
+				displayContactDetails(true);
 			}
 		} else if (e instanceof ContactDisconnectedEvent) {
 			ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
 			if (c.getContactId().equals(contactId)) {
 				LOG.info("Contact disconnected");
-				connected = false;
-				displayContactDetails();
+				displayContactDetails(false);
 			}
 		} else if (e instanceof IntroductionRequestReceivedEvent) {
 			IntroductionRequestReceivedEvent event =
@@ -561,7 +551,6 @@ public class ConversationActivity extends BriarActivity
 				IntroductionRequest ir = event.getIntroductionRequest();
 				ConversationItem item = new ConversationIntroductionInItem(ir);
 				addConversationItem(item);
-				markMessageReadIfNew(ir);
 			}
 		} else if (e instanceof IntroductionResponseReceivedEvent) {
 			IntroductionResponseReceivedEvent event =
@@ -572,7 +561,6 @@ public class ConversationActivity extends BriarActivity
 				ConversationItem item =
 						ConversationItem.from(this, contactName, ir);
 				addConversationItem(item);
-				markMessageReadIfNew(ir);
 			}
 		} else if (e instanceof InvitationRequestReceivedEvent) {
 			InvitationRequestReceivedEvent event =
@@ -582,7 +570,6 @@ public class ConversationActivity extends BriarActivity
 				InvitationRequest ir = event.getRequest();
 				ConversationItem item = ConversationItem.from(ir);
 				addConversationItem(item);
-				markMessageReadIfNew(ir);
 			}
 		} else if (e instanceof InvitationResponseReceivedEvent) {
 			InvitationResponseReceivedEvent event =
@@ -593,46 +580,10 @@ public class ConversationActivity extends BriarActivity
 				ConversationItem item =
 						ConversationItem.from(this, contactName, ir);
 				addConversationItem(item);
-				markMessageReadIfNew(ir);
 			}
 		}
 	}
 
-	private void markMessageReadIfNew(final BaseMessageHeader h) {
-		runOnUiThreadUnlessDestroyed(new Runnable() {
-			@Override
-			public void run() {
-				ConversationItem item = adapter.getLastItem();
-				if (item != null) {
-					// Mark the message read if it's the newest message
-					long lastMsgTime = item.getTime();
-					long newMsgTime = h.getTimestamp();
-					if (newMsgTime > lastMsgTime)
-						markNewMessageRead(h.getGroupId(), h.getId());
-					else loadMessages();
-				} else {
-					// mark the message as read as well if it is the first one
-					markNewMessageRead(h.getGroupId(), h.getId());
-				}
-			}
-		});
-	}
-
-	private void markNewMessageRead(final GroupId g, final MessageId m) {
-		runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					messagingManager.setReadFlag(g, m, true);
-					loadMessages();
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
-
 	private void markMessages(final Collection<MessageId> messageIds,
 			final boolean sent, final boolean seen) {
 		runOnUiThreadUnlessDestroyed(new Runnable() {
@@ -654,7 +605,6 @@ public class ConversationActivity extends BriarActivity
 
 	@Override
 	public void onSendClick(String text) {
-		markMessagesRead();
 		if (text.equals("")) return;
 		long timestamp = System.currentTimeMillis();
 		timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
diff --git a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
index 303f9b89b40e36fd8a90f0e3dfc06092201c47c2..96d0cf4f0201539b39c35974db08e8b7be60dacb 100644
--- a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
+++ b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
@@ -6,9 +6,9 @@ public interface ActivityLifecycleController {
 
 	void onActivityCreate(Activity activity);
 
-	void onActivityResume();
+	void onActivityStart();
 
-	void onActivityPause();
+	void onActivityStop();
 
 	void onActivityDestroy();
 }
diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
index 459730ebd2b616224156ace7baefe430060b286a..f49d6485f7b58e4673e06f4f40e1125275e85610 100644
--- a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
@@ -19,18 +19,18 @@ public class BriarControllerImpl implements BriarController {
 	private static final Logger LOG =
 			Logger.getLogger(BriarControllerImpl.class.getName());
 
-	@Inject
-	BriarServiceConnection serviceConnection;
-	@Inject
-	DatabaseConfig databaseConfig;
-	@Inject
-	Activity activity;
+	private final BriarServiceConnection serviceConnection;
+	private final DatabaseConfig databaseConfig;
+	private final Activity activity;
 
 	private boolean bound = false;
 
 	@Inject
-	public BriarControllerImpl() {
-
+	BriarControllerImpl(BriarServiceConnection serviceConnection,
+			DatabaseConfig databaseConfig, Activity activity) {
+		this.serviceConnection = serviceConnection;
+		this.databaseConfig = databaseConfig;
+		this.activity = activity;
 	}
 
 	@Override
@@ -40,13 +40,11 @@ public class BriarControllerImpl implements BriarController {
 	}
 
 	@Override
-	@CallSuper
-	public void onActivityResume() {
+	public void onActivityStart() {
 	}
 
 	@Override
-	@CallSuper
-	public void onActivityPause() {
+	public void onActivityStop() {
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
index 060f77933e3993d214d548d8b8a9810e7e0b05d9..55d5d267f74c8fb16b8befdae50ee54c5ba61c48 100644
--- a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
@@ -57,12 +57,12 @@ public class NavDrawerControllerImpl extends DbControllerImpl
 	}
 
 	@Override
-	public void onActivityResume() {
+	public void onActivityStart() {
 		eventBus.addListener(this);
 	}
 
 	@Override
-	public void onActivityPause() {
+	public void onActivityStop() {
 		eventBus.removeListener(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index 81b41f99fed3dbc19467fd6ce6e56dc7c6067ee4..03ebdf438e960042e49012b49a0c3f3e9ce53eca 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -1,6 +1,7 @@
 package org.briarproject.android.forum;
 
 import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.LayoutRes;
@@ -98,9 +99,8 @@ public class ForumActivity extends
 
 	@Override
 	public boolean onOptionsItemSelected(final MenuItem item) {
-		ActivityOptionsCompat options =
-				makeCustomAnimation(this, android.R.anim.slide_in_left,
-						android.R.anim.slide_out_right);
+		ActivityOptionsCompat options = makeCustomAnimation(this,
+				android.R.anim.slide_in_left, android.R.anim.slide_out_right);
 		// Handle presses on the action bar items
 		switch (item.getItemId()) {
 			case R.id.action_forum_compose_post:
@@ -110,9 +110,8 @@ public class ForumActivity extends
 				Intent i2 = new Intent(this, ShareForumActivity.class);
 				i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i2.putExtra(GROUP_ID, groupId.getBytes());
-				ActivityCompat
-						.startActivityForResult(this, i2, REQUEST_FORUM_SHARED,
-								options.toBundle());
+				ActivityCompat.startActivityForResult(this, i2,
+						REQUEST_FORUM_SHARED, options.toBundle());
 				return true;
 			case R.id.action_forum_sharing_status:
 				Intent i3 = new Intent(this, SharingStatusForumActivity.class);
@@ -146,17 +145,14 @@ public class ForumActivity extends
 	}
 
 	private void showUnsubscribeDialog() {
-		DialogInterface.OnClickListener okListener =
-				new DialogInterface.OnClickListener() {
-					@Override
-					public void onClick(final DialogInterface dialog,
-							int which) {
-						deleteNamedGroup();
-					}
-				};
-		AlertDialog.Builder builder =
-				new AlertDialog.Builder(ForumActivity.this,
-						R.style.BriarDialogTheme);
+		OnClickListener okListener = new OnClickListener() {
+			@Override
+			public void onClick(final DialogInterface dialog, int which) {
+				deleteNamedGroup();
+			}
+		};
+		AlertDialog.Builder builder = new AlertDialog.Builder(
+				ForumActivity.this, R.style.BriarDialogTheme);
 		builder.setTitle(getString(R.string.dialog_title_leave_forum));
 		builder.setMessage(getString(R.string.dialog_message_leave_forum));
 		builder.setNegativeButton(R.string.dialog_button_leave, okListener);
@@ -171,14 +167,11 @@ public class ForumActivity extends
 					@Override
 					public void onResultUi(Void v) {
 						Toast.makeText(ForumActivity.this,
-								R.string.forum_left_toast,
-								LENGTH_SHORT)
-								.show();
+								R.string.forum_left_toast, LENGTH_SHORT).show();
 					}
 
 					@Override
-					public void onExceptionUi(
-							DbException exception) {
+					public void onExceptionUi(DbException exception) {
 						// TODO proper error handling
 						finish();
 					}
diff --git a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
index fa62f1b292740855de64345b1b2e9866c0404dca..a0b89b0ed4aa4d9363bf20f4fb0487a3de5fc313 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumControllerImpl.java
@@ -28,8 +28,8 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-public class ForumControllerImpl
-		extends ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost>
+public class ForumControllerImpl extends
+		ThreadListControllerImpl<Forum, ForumItem, ForumPostHeader, ForumPost>
 		implements ForumController {
 
 	private static final Logger LOG =
@@ -49,8 +49,8 @@ public class ForumControllerImpl
 	}
 
 	@Override
-	public void onActivityResume() {
-		super.onActivityResume();
+	public void onActivityStart() {
+		super.onActivityStart();
 		notificationManager.clearForumPostNotification(getGroupId());
 	}
 
@@ -59,7 +59,7 @@ public class ForumControllerImpl
 		super.eventOccurred(e);
 
 		if (e instanceof ForumPostReceivedEvent) {
-			final ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
+			ForumPostReceivedEvent pe = (ForumPostReceivedEvent) e;
 			if (pe.getGroupId().equals(getGroupId())) {
 				LOG.info("Forum post received, adding...");
 				final ForumPostHeader fph = pe.getForumPostHeader();
@@ -102,9 +102,8 @@ public class ForumControllerImpl
 	@Override
 	protected ForumPost createLocalMessage(String body, long timestamp,
 			@Nullable MessageId parentId, LocalAuthor author) {
-		return forumManager
-				.createLocalPost(getGroupId(), body, timestamp, parentId,
-						author);
+		return forumManager.createLocalPost(getGroupId(), body, timestamp,
+				parentId, author);
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 1ebba8c1c327b16b23c9489e623ec4c62713784c..0edb1a0755a26c801fc92d2aca220008257835ae 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -111,9 +111,8 @@ public class ForumListFragment extends BaseEventFragment implements
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
-
+	public void onStart() {
+		super.onStart();
 		notificationManager.blockAllForumPostNotifications();
 		notificationManager.clearAllForumPostNotifications();
 		loadForums();
@@ -122,9 +121,8 @@ public class ForumListFragment extends BaseEventFragment implements
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
-
+	public void onStop() {
+		super.onStop();
 		notificationManager.unblockAllForumPostNotifications();
 		adapter.clear();
 		list.showProgressBar();
@@ -156,7 +154,6 @@ public class ForumListFragment extends BaseEventFragment implements
 			@Override
 			public void run() {
 				try {
-					// load forums
 					long now = System.currentTimeMillis();
 					Collection<ForumListItem> forums = new ArrayList<>();
 					for (Forum f : forumManager.getForums()) {
@@ -168,10 +165,10 @@ public class ForumListFragment extends BaseEventFragment implements
 							// Continue
 						}
 					}
-					displayForums(forums);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Full load took " + duration + " ms");
+					displayForums(forums);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -184,8 +181,8 @@ public class ForumListFragment extends BaseEventFragment implements
 		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (forums.size() > 0) adapter.addAll(forums);
-				else list.showData();
+				if (forums.isEmpty()) list.showData();
+				else adapter.addAll(forums);
 			}
 		});
 	}
@@ -245,9 +242,10 @@ public class ForumListFragment extends BaseEventFragment implements
 			}
 		} else if (e instanceof ForumPostReceivedEvent) {
 			ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
-			LOG.info("Forum post added, updating...");
+			LOG.info("Forum post added, updating item");
 			updateItem(f.getGroupId(), f.getForumPostHeader());
 		} else if (e instanceof ForumInvitationReceivedEvent) {
+			LOG.info("Forum invitation received, reloading available forums");
 			loadAvailableForums();
 		}
 	}
diff --git a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
index 69ceab43a6281a5a7ae1f0ad901697a6b2651d82..cf78840532ca486968a10c09d320a57b617d63bd 100644
--- a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
@@ -12,14 +12,14 @@ public abstract class BaseEventFragment extends BaseFragment implements
 	protected volatile EventBus eventBus;
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		eventBus.addListener(this);
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
index d671bf245c692463ea937e7d6532e831dea79278..2cb6b13e6152d89b1e118e8b2cd8494559e78b26 100644
--- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
@@ -44,6 +44,7 @@ public abstract class BaseFragment extends Fragment
 
 	public interface BaseFragmentListener extends DestroyableContext {
 
+		@Deprecated
 		void runOnDbThread(Runnable runnable);
 
 		@UiThread
diff --git a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
index 15c718b6709519831533590334fa7b702d860f05..a3d6551267d1cd6fca14e571e2ebeea12236c011 100644
--- a/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/SettingsFragment.java
@@ -155,14 +155,14 @@ public class SettingsFragment extends PreferenceFragmentCompat
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		eventBus.addListener(this);
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java
index 059ab8cd11e00b8714cd1b6ec94baf97f71b2994..e291302b8e6b86323bfbd8ff587bce6854fbc8ee 100644
--- a/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java
+++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserAdapter.java
@@ -1,19 +1,19 @@
 package org.briarproject.android.introduction;
 
 import android.content.Context;
+import android.support.annotation.UiThread;
 import android.view.View;
 
 import org.briarproject.android.contact.ContactListAdapter;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.api.identity.AuthorId;
 
-public class ContactChooserAdapter extends ContactListAdapter {
+@UiThread
+class ContactChooserAdapter extends ContactListAdapter {
 
 	private AuthorId localAuthorId;
 
-	public ContactChooserAdapter(Context context,
-			OnItemClickListener listener) {
-
+	ContactChooserAdapter(Context context, OnItemClickListener listener) {
 		super(context, listener);
 	}
 
@@ -46,7 +46,7 @@ public class ContactChooserAdapter extends ContactListAdapter {
 	 *
 	 * @param authorId The ID of the local Author
 	 */
-	public void setLocalAuthor(AuthorId authorId) {
+	void setLocalAuthor(AuthorId authorId) {
 		localAuthorId = authorId;
 		notifyDataSetChanged();
 	}
diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
index b26d3a8dc05c9dbdf8911d96d13d81d116437846..888cc61e79eb48b713a61ffeba6788c759f02abb 100644
--- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
+++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
@@ -45,18 +45,18 @@ public class ContactChooserFragment extends BaseFragment {
 	private IntroductionActivity introductionActivity;
 	private BriarRecyclerView list;
 	private ContactChooserAdapter adapter;
-	private int contactId;
+	private ContactId contactId;
 
 	// Fields that are accessed from background threads must be volatile
-	protected volatile Contact c1;
+	volatile Contact c1;
 	@Inject
-	protected volatile ContactManager contactManager;
+	volatile ContactManager contactManager;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 	@Inject
-	protected volatile ConversationManager conversationManager;
+	volatile ConversationManager conversationManager;
 	@Inject
-	protected volatile ConnectionRegistry connectionRegistry;
+	volatile ConnectionRegistry connectionRegistry;
 
 	public static ContactChooserFragment newInstance() {
 		
@@ -87,9 +87,7 @@ public class ContactChooserFragment extends BaseFragment {
 				new ContactListAdapter.OnItemClickListener() {
 					@Override
 					public void onItemClick(View view, ContactListItem item) {
-						if (c1 == null) {
-							throw new RuntimeException("c1 not accountExists");
-						}
+						if (c1 == null) throw new IllegalStateException();
 						Contact c2 = item.getContact();
 						if (!c1.getLocalAuthorId()
 								.equals(c2.getLocalAuthorId())) {
@@ -113,15 +111,14 @@ public class ContactChooserFragment extends BaseFragment {
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
-
+	public void onStart() {
+		super.onStart();
 		loadContacts();
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		adapter.clear();
 		list.showProgressBar();
 	}
@@ -145,7 +142,7 @@ public class ContactChooserFragment extends BaseFragment {
 					AuthorId localAuthorId =
 							identityManager.getLocalAuthor().getId();
 					for (Contact c : contactManager.getActiveContacts()) {
-						if (c.getId().getInt() == contactId) {
+						if (c.getId().equals(contactId)) {
 							c1 = c;
 						} else {
 							ContactId id = c.getId();
@@ -176,7 +173,7 @@ public class ContactChooserFragment extends BaseFragment {
 			@Override
 			public void run() {
 				adapter.setLocalAuthor(localAuthorId);
-				if (contacts.size() == 0) list.showData();
+				if (contacts.isEmpty()) list.showData();
 				else adapter.addAll(contacts);
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
index 8c4e6465243c87fabdb56a27fab183485025dfdd..aeada3f1d1187b954a05a2b2b719bc5d8e559435 100644
--- a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
+++ b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
@@ -14,6 +14,7 @@ import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
 
 // TODO extend the BriarFragmentActivity ?
 public class IntroductionActivity extends BriarActivity implements
@@ -21,16 +22,16 @@ public class IntroductionActivity extends BriarActivity implements
 
 	public static final String CONTACT_ID = "briar.CONTACT_ID";
 
-	private int contactId;
+	private ContactId contactId;
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 
 		Intent intent = getIntent();
-		contactId = intent.getIntExtra(CONTACT_ID, -1);
-		if (contactId == -1)
-			throw new IllegalArgumentException("Wrong ContactId");
+		int id = intent.getIntExtra(CONTACT_ID, -1);
+		if (id == -1) throw new IllegalStateException("No ContactId");
+		contactId = new ContactId(id);
 
 		setContentView(R.layout.activity_fragment_container);
 
@@ -75,7 +76,7 @@ public class IntroductionActivity extends BriarActivity implements
 		}
 	}
 
-	int getContactId() {
+	ContactId getContactId() {
 		return contactId;
 	}
 
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index bec5b346f6e2c1dd711febfcd23a6fb790431471..9a8f592e17243a71c1d9512aff68ca08fcd11b08 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -37,9 +37,13 @@ public class AddContactActivity extends BriarActivity
 	private static final Logger LOG =
 			Logger.getLogger(AddContactActivity.class.getName());
 
-	@Inject protected CryptoComponent crypto;
-	@Inject protected InvitationTaskFactory invitationTaskFactory;
-	@Inject protected ReferenceManager referenceManager;
+	@Inject
+	CryptoComponent crypto;
+	@Inject
+	InvitationTaskFactory invitationTaskFactory;
+	@Inject
+	ReferenceManager referenceManager;
+
 	private AddContactView view = null;
 	private InvitationTask task = null;
 	private long taskHandle = -1;
@@ -52,7 +56,8 @@ public class AddContactActivity extends BriarActivity
 	private String contactName = null;
 
 	// Fields that are accessed from background threads must be volatile
-	@Inject protected volatile IdentityManager identityManager;
+	@Inject
+	volatile IdentityManager identityManager;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -150,8 +155,8 @@ public class AddContactActivity extends BriarActivity
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		view.populate();
 	}
 
diff --git a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
index 8ef2764cf42ea9af3fd483057b866ad38b6bcb86..8a075f151d31e2d13ef6e746f5656eb58512ee6f 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
@@ -40,15 +40,13 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 	private static final int STEP_QR = 2;
 
 	@Inject
-	protected EventBus eventBus;
-
-	private Toolbar toolbar;
+	EventBus eventBus;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ContactExchangeTask contactExchangeTask;
+	volatile ContactExchangeTask contactExchangeTask;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 
 	@Override
 	public void injectActivity(ActivityComponent component) {
@@ -61,7 +59,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 		super.onCreate(state);
 		setContentView(R.layout.activity_plain);
 
-		toolbar = (Toolbar) findViewById(R.id.toolbar);
+		Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 
 		setSupportActionBar(toolbar);
 		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -83,14 +81,14 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		eventBus.addListener(this);
 	}
 
 	@Override
-	protected void onPause() {
-		super.onPause();
+	protected void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
index cef537288c3c845d24137d380994bed35b9f93d3..fc5d286b0d0406fd017fab8cca3f071c1e8b8b5c 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
@@ -162,25 +162,16 @@ public class ShowQrCodeFragment extends BaseEventFragment
 		} else {
 			startListening();
 		}
-	}
 
-	@Override
-	public void onResume() {
-		super.onResume();
 		openCamera();
 	}
 
-	@Override
-	public void onPause() {
-		super.onPause();
-		releaseCamera();
-	}
-
 	@Override
 	public void onStop() {
 		super.onStop();
 		stopListening();
 		if (receiver != null) getActivity().unregisterReceiver(receiver);
+		releaseCamera();
 	}
 
 	@UiThread
diff --git a/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java b/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java
index 094eeaac2b07300a3404637d0c218ec88feede21..f2f69739431231059f03631def954c9c27a45556 100644
--- a/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java
+++ b/briar-android/src/org/briarproject/android/panic/PanicPreferencesFragment.java
@@ -132,16 +132,16 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		getPreferenceScreen().getSharedPreferences()
 				.registerOnSharedPreferenceChangeListener(this);
 		showPanicApp(PanicResponder.getTriggerPackageName(getActivity()));
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		getPreferenceScreen().getSharedPreferences()
 				.unregisterOnSharedPreferenceChangeListener(this);
 	}
diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
index fb0cd8ac59136aa84e4fc01910f5c5ecffb5072a..8a6644efddaebff7b71a226c7631604e28b6f284 100644
--- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java
@@ -27,8 +27,8 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-public class GroupControllerImpl
-		extends ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage>
+public class GroupControllerImpl extends
+		ThreadListControllerImpl<PrivateGroup, GroupMessageItem, GroupMessageHeader, GroupMessage>
 		implements GroupController {
 
 	private static final Logger LOG =
@@ -48,8 +48,8 @@ public class GroupControllerImpl
 	}
 
 	@Override
-	public void onActivityResume() {
-		super.onActivityResume();
+	public void onActivityStart() {
+		super.onActivityStart();
 		// TODO: Add new notification manager methods for private groups
 	}
 
@@ -101,9 +101,8 @@ public class GroupControllerImpl
 	@Override
 	protected GroupMessage createLocalMessage(String body, long timestamp,
 			@Nullable MessageId parentId, LocalAuthor author) {
-		return privateGroupManager
-				.createLocalMessage(getGroupId(), body, timestamp, parentId,
-						author);
+		return privateGroupManager.createLocalMessage(getGroupId(), body,
+				timestamp, parentId, author);
 	}
 
 	@Override
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java
index 89b208b00e2638488760fc8a2fd6259099e72933..ac75f29cd57ef089b8cfc0a26306619093dccfd5 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupItem.java
@@ -1,56 +1,51 @@
 package org.briarproject.android.privategroup.list;
 
+import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.identity.Author;
+import org.briarproject.api.nullsafety.NotNullByDefault;
 import org.briarproject.api.privategroup.GroupMessageHeader;
 import org.briarproject.api.privategroup.PrivateGroup;
 import org.briarproject.api.sync.GroupId;
-import org.jetbrains.annotations.NotNull;
 
 // This class is not thread-safe
+@NotNullByDefault
 class GroupItem {
 
 	private final PrivateGroup privateGroup;
-	private int messageCount;
-	private long lastUpdate;
-	private int unreadCount;
+	private int messageCount, unreadCount;
+	private long timestamp;
 	private boolean dissolved;
 
-	GroupItem(@NotNull PrivateGroup privateGroup, int messageCount,
-			long lastUpdate, int unreadCount, boolean dissolved) {
-
+	GroupItem(PrivateGroup privateGroup, GroupCount count, boolean dissolved) {
 		this.privateGroup = privateGroup;
-		this.messageCount = messageCount;
-		this.lastUpdate = lastUpdate;
-		this.unreadCount = unreadCount;
+		this.messageCount = count.getMsgCount();
+		this.unreadCount = count.getUnreadCount();
+		this.timestamp = count.getLatestMsgTime();
 		this.dissolved = dissolved;
 	}
 
 	void addMessageHeader(GroupMessageHeader header) {
 		messageCount++;
-		if (header.getTimestamp() > lastUpdate) {
-			lastUpdate = header.getTimestamp();
+		if (header.getTimestamp() > timestamp) {
+			timestamp = header.getTimestamp();
 		}
 		if (!header.isRead()) {
 			unreadCount++;
 		}
 	}
 
-	@NotNull
 	PrivateGroup getPrivateGroup() {
 		return privateGroup;
 	}
 
-	@NotNull
 	GroupId getId() {
 		return privateGroup.getId();
 	}
 
-	@NotNull
 	Author getCreator() {
 		return privateGroup.getAuthor();
 	}
 
-	@NotNull
 	String getName() {
 		return privateGroup.getName();
 	}
@@ -63,8 +58,8 @@ class GroupItem {
 		return messageCount;
 	}
 
-	long getLastUpdate() {
-		return lastUpdate;
+	long getTimestamp() {
+		return timestamp;
 	}
 
 	int getUnreadCount() {
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java
index bae48022a7e8599cf4bbeef00f069ee88ed7651c..b5588e3440b559f2fc38989c6b30745c1d8044ff 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListAdapter.java
@@ -38,7 +38,7 @@ class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
 	public int compare(GroupItem a, GroupItem b) {
 		if (a == b) return 0;
 		// The group with the latest message comes first
-		long aTime = a.getLastUpdate(), bTime = b.getLastUpdate();
+		long aTime = a.getTimestamp(), bTime = b.getTimestamp();
 		if (aTime > bTime) return -1;
 		if (aTime < bTime) return 1;
 		// Break ties by group name
@@ -50,7 +50,7 @@ class GroupListAdapter extends BriarAdapter<GroupItem, GroupViewHolder> {
 	@Override
 	public boolean areContentsTheSame(GroupItem a, GroupItem b) {
 		return a.getMessageCount() == b.getMessageCount() &&
-				a.getLastUpdate() == b.getLastUpdate() &&
+				a.getTimestamp() == b.getTimestamp() &&
 				a.getUnreadCount() == b.getUnreadCount() &&
 				a.isDissolved() == b.isDissolved();
 	}
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java
index 27e8c90d4a04104df35a4e26a4bff4b1c3773a97..fbe05315d01fcb316fb57ef3f74b95e27f5d107a 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListController.java
@@ -31,6 +31,7 @@ public interface GroupListController extends DbController {
 			ResultExceptionHandler<Void, DbException> result);
 
 	interface GroupListListener extends DestroyableContext {
+
 		@UiThread
 		void onGroupMessageAdded(GroupMessageHeader header);
 
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
index 9db84cdcadfa143748c975dce863815075ba0d1c..efa36fe5f2079e2bc818e0d0baad8b53e428d4c7 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListControllerImpl.java
@@ -8,6 +8,7 @@ import org.briarproject.android.controller.handler.ResultExceptionHandler;
 import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.db.DatabaseExecutor;
 import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.NoSuchGroupException;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
@@ -16,6 +17,7 @@ import org.briarproject.api.event.GroupMessageAddedEvent;
 import org.briarproject.api.event.GroupRemovedEvent;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.lifecycle.LifecycleManager;
+import org.briarproject.api.privategroup.GroupMessageHeader;
 import org.briarproject.api.privategroup.PrivateGroup;
 import org.briarproject.api.privategroup.PrivateGroupManager;
 import org.briarproject.api.sync.ClientId;
@@ -29,6 +31,7 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
+import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 
 public class GroupListControllerImpl extends DbControllerImpl
@@ -81,59 +84,77 @@ public class GroupListControllerImpl extends DbControllerImpl
 	@CallSuper
 	public void eventOccurred(Event e) {
 		if (e instanceof GroupMessageAddedEvent) {
-			final GroupMessageAddedEvent m = (GroupMessageAddedEvent) e;
-			LOG.info("New group message added");
-			listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-				@Override
-				public void run() {
-					listener.onGroupMessageAdded(m.getHeader());
-				}
-			});
+			GroupMessageAddedEvent g = (GroupMessageAddedEvent) e;
+			LOG.info("Private group message added");
+			onGroupMessageAdded(g.getHeader());
 		} else if (e instanceof GroupAddedEvent) {
-			final GroupAddedEvent gae = (GroupAddedEvent) e;
-			ClientId id = gae.getGroup().getClientId();
+			GroupAddedEvent g = (GroupAddedEvent) e;
+			ClientId id = g.getGroup().getClientId();
 			if (id.equals(groupManager.getClientId())) {
 				LOG.info("Private group added");
-				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-					@Override
-					public void run() {
-						listener.onGroupAdded(gae.getGroup().getId());
-					}
-				});
+				onGroupAdded(g.getGroup().getId());
 			}
 		} else if (e instanceof GroupRemovedEvent) {
-			final GroupRemovedEvent gre = (GroupRemovedEvent) e;
-			ClientId id = gre.getGroup().getClientId();
+			GroupRemovedEvent g = (GroupRemovedEvent) e;
+			ClientId id = g.getGroup().getClientId();
 			if (id.equals(groupManager.getClientId())) {
 				LOG.info("Private group removed");
-				listener.runOnUiThreadUnlessDestroyed(new Runnable() {
-					@Override
-					public void run() {
-						listener.onGroupRemoved(gre.getGroup().getId());
-					}
-				});
+				onGroupRemoved(g.getGroup().getId());
 			}
 		}
 	}
 
+	private void onGroupMessageAdded(final GroupMessageHeader h) {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				listener.onGroupMessageAdded(h);
+			}
+		});
+	}
+
+	private void onGroupAdded(final GroupId g) {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				listener.onGroupAdded(g);
+			}
+		});
+	}
+
+	private void onGroupRemoved(final GroupId g) {
+		listener.runOnUiThreadUnlessDestroyed(new Runnable() {
+			@Override
+			public void run() {
+				listener.onGroupRemoved(g);
+			}
+		});
+	}
+
 	@Override
 	public void loadGroups(
 			final ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				LOG.info("Loading groups from database...");
 				try {
+					long now = System.currentTimeMillis();
 					Collection<PrivateGroup> groups =
 							groupManager.getPrivateGroups();
 					List<GroupItem> items = new ArrayList<>(groups.size());
 					for (PrivateGroup g : groups) {
-						GroupCount c = groupManager.getGroupCount(g.getId());
-						boolean dissolved = groupManager.isDissolved(g.getId());
-						items.add(new GroupItem(g, c.getMsgCount(),
-								c.getLatestMsgTime(), c.getUnreadCount(),
-								dissolved));
+						try {
+							GroupId id = g.getId();
+							GroupCount count = groupManager.getGroupCount(id);
+							boolean dissolved = groupManager.isDissolved(id);
+							items.add(new GroupItem(g, count, dissolved));
+						} catch (NoSuchGroupException e) {
+							// Continue
+						}
 					}
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Loading groups took " + duration + " ms");
 					handler.onResult(items);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
@@ -150,9 +171,13 @@ public class GroupListControllerImpl extends DbControllerImpl
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				LOG.info("Removing group from database...");
 				try {
+					long now = System.currentTimeMillis();
 					groupManager.removePrivateGroup(g);
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Removing group took " + duration + " ms");
+					handler.onResult(null);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java
index bf773c28c654d0be47ad835c51de88d40b1e1947..a786e766c98c70ba1b1456afab2eca3de94548f2 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupListFragment.java
@@ -1,6 +1,5 @@
 package org.briarproject.android.privategroup.list;
 
-import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
@@ -16,7 +15,6 @@ import org.briarproject.R;
 import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.controller.handler.UiResultExceptionHandler;
 import org.briarproject.android.fragment.BaseFragment;
-import org.briarproject.android.invitation.AddContactActivity;
 import org.briarproject.android.privategroup.list.GroupListController.GroupListListener;
 import org.briarproject.android.privategroup.list.GroupViewHolder.OnGroupRemoveClickListener;
 import org.briarproject.android.view.BriarRecyclerView;
@@ -152,12 +150,9 @@ public class GroupListFragment extends BaseFragment implements
 				new UiResultExceptionHandler<Collection<GroupItem>, DbException>(
 						listener) {
 					@Override
-					public void onResultUi(Collection<GroupItem> result) {
-						if (result.isEmpty()) {
-							list.showData();
-						} else {
-							adapter.addAll(result);
-						}
+					public void onResultUi(Collection<GroupItem> groups) {
+						if (groups.isEmpty()) list.showData();
+						else adapter.addAll(groups);
 					}
 
 					@Override
diff --git a/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java b/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java
index c7d59dd1ff12611509016cd1d77a99d17dffa4dd..7f3031aec9f66d0bacbab0ebca4b0be37a014561 100644
--- a/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java
+++ b/briar-android/src/org/briarproject/android/privategroup/list/GroupViewHolder.java
@@ -88,7 +88,7 @@ class GroupViewHolder extends RecyclerView.ViewHolder {
 				postCount.setTextColor(
 						getColor(ctx, R.color.briar_text_secondary));
 
-				long lastUpdate = group.getLastUpdate();
+				long lastUpdate = group.getTimestamp();
 				date.setText(AndroidUtils.formatDate(ctx, lastUpdate));
 				date.setVisibility(VISIBLE);
 				avatar.setProblem(false);
diff --git a/briar-android/src/org/briarproject/android/report/DevReportActivity.java b/briar-android/src/org/briarproject/android/report/DevReportActivity.java
index 919a0b6200a202cadc10f41f8334e38b3358a3b2..0d142757e17849f0f3069573787e6f2c91711459 100644
--- a/briar-android/src/org/briarproject/android/report/DevReportActivity.java
+++ b/briar-android/src/org/briarproject/android/report/DevReportActivity.java
@@ -163,8 +163,8 @@ public class DevReportActivity extends BaseCrashReportDialog
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		if (chevron.isSelected()) refresh();
 	}
 
diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
index 8e270d6407ca27f62a3b4f2d411efa49023230a5..82db75adf15b2ad6ab70e893935628d68601cf9a 100644
--- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
@@ -30,7 +30,6 @@ import org.briarproject.api.sync.GroupId;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 import java.util.logging.Logger;
 
@@ -57,11 +56,11 @@ public class ContactSelectorFragment extends BaseFragment implements
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ContactManager contactManager;
+	volatile ContactManager contactManager;
 	@Inject
-	protected volatile IdentityManager identityManager;
+	volatile IdentityManager identityManager;
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
+	volatile ForumSharingManager forumSharingManager;
 
 	private volatile GroupId groupId;
 
@@ -91,8 +90,9 @@ public class ContactSelectorFragment extends BaseFragment implements
 
 		setHasOptionsMenu(true);
 		Bundle args = getArguments();
-		groupId = new GroupId(args.getByteArray(GROUP_ID));
-		if (groupId == null) throw new IllegalStateException("No GroupId");
+		byte[] b = args.getByteArray(GROUP_ID);
+		if (b == null) throw new IllegalStateException("No GroupId");
+		groupId = new GroupId(b);
 	}
 
 	@Override
@@ -125,12 +125,16 @@ public class ContactSelectorFragment extends BaseFragment implements
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
+		loadContacts(selectedContacts);
+	}
 
-		if (selectedContacts != null)
-			loadContacts(Collections.unmodifiableCollection(selectedContacts));
-		else loadContacts(null);
+	@Override
+	public void onStop() {
+		super.onStop();
+		adapter.clear();
+		list.showProgressBar();
 	}
 
 	@Override
@@ -202,9 +206,8 @@ public class ContactSelectorFragment extends BaseFragment implements
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Load took " + duration + " ms");
-					displayContacts(Collections.unmodifiableList(contacts));
+					displayContacts(contacts);
 				} catch (DbException e) {
-					displayContacts(Collections.<ContactListItem>emptyList());
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
@@ -216,8 +219,8 @@ public class ContactSelectorFragment extends BaseFragment implements
 		shareActivity.runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (!contacts.isEmpty()) adapter.addAll(contacts);
-				else list.showData();
+				if (contacts.isEmpty()) list.showData();
+				else adapter.addAll(contacts);
 				updateMenuItem();
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
index a6b33a0d8c601d32f06ddb3b895df849a7e6a556..fc691ac2b0f725854e3adb70a7caa7202de55b59 100644
--- a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
@@ -2,6 +2,7 @@ package org.briarproject.android.sharing;
 
 import android.content.Context;
 import android.os.Bundle;
+import android.support.annotation.CallSuper;
 import android.support.v7.widget.LinearLayoutManager;
 import android.widget.Toast;
 
@@ -42,7 +43,6 @@ abstract class InvitationsActivity extends BriarActivity
 
 		adapter = getAdapter(this, this);
 
-
 		list = (BriarRecyclerView) findViewById(R.id.list);
 		if (list != null) {
 			list.setLayoutManager(new LinearLayoutManager(this));
@@ -51,21 +51,22 @@ abstract class InvitationsActivity extends BriarActivity
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		eventBus.addListener(this);
 		loadInvitations(false);
 	}
 
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		eventBus.removeListener(this);
 		adapter.clear();
 		list.showProgressBar();
 	}
 
 	@Override
+	@CallSuper
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactRemovedEvent) {
 			LOG.info("Contact removed, reloading...");
@@ -110,8 +111,8 @@ abstract class InvitationsActivity extends BriarActivity
 					LOG.info("No more invitations available, finishing");
 					finish();
 				} else {
-					if (clear) adapter.clear();
-					adapter.addAll(invitations);
+					if (clear) adapter.setItems(invitations);
+					else adapter.addAll(invitations);
 				}
 			}
 		});
diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java
index 58e818269f87af830749632353e88d3abbe9241a..014391d5b6a8940d0ad35109083209ab2bf679fb 100644
--- a/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java
@@ -29,9 +29,9 @@ public class InvitationsBlogActivity extends InvitationsActivity {
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile BlogManager blogManager;
+	volatile BlogManager blogManager;
 	@Inject
-	protected volatile BlogSharingManager blogSharingManager;
+	volatile BlogSharingManager blogSharingManager;
 
 	@Override
 	public void injectActivity(ActivityComponent component) {
@@ -62,31 +62,34 @@ public class InvitationsBlogActivity extends InvitationsActivity {
 		}
 	}
 
+	@Override
 	protected InvitationAdapter getAdapter(Context ctx,
 			AvailableForumClickListener listener) {
 		return new BlogInvitationAdapter(ctx, listener);
 	}
 
+	@Override
 	protected void loadInvitations(final boolean clear) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				Collection<InvitationItem> invitations = new ArrayList<>();
 				try {
+					Collection<InvitationItem> invitations = new ArrayList<>();
 					long now = System.currentTimeMillis();
 					invitations.addAll(blogSharingManager.getInvitations());
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Load took " + duration + " ms");
+					displayInvitations(invitations, clear);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
-				displayInvitations(invitations, clear);
 			}
 		});
 	}
 
+	@Override
 	protected void respondToInvitation(final InvitationItem item,
 			final boolean accept) {
 		runOnDbThread(new Runnable() {
@@ -95,6 +98,7 @@ public class InvitationsBlogActivity extends InvitationsActivity {
 				try {
 					Blog b = (Blog) item.getShareable();
 					for (Contact c : item.getNewSharers()) {
+						// TODO: What happens if a contact has been removed?
 						blogSharingManager.respondToInvitation(b, c, accept);
 					}
 				} catch (DbException e) {
@@ -105,10 +109,12 @@ public class InvitationsBlogActivity extends InvitationsActivity {
 		});
 	}
 
+	@Override
 	protected int getAcceptRes() {
 		return R.string.blogs_sharing_joined_toast;
 	}
 
+	@Override
 	protected int getDeclineRes() {
 		return R.string.blogs_sharing_declined_toast;
 	}
diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java
index 51ddcc838a73f349f5c40096b6fa089cbe9bf0fb..6b5811eaac51682ddeb9c4c0ac56214b4fcf7539 100644
--- a/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java
@@ -29,9 +29,9 @@ public class InvitationsForumActivity extends InvitationsActivity {
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ForumManager forumManager;
+	volatile ForumManager forumManager;
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
+	volatile ForumSharingManager forumSharingManager;
 
 	@Override
 	public void injectActivity(ActivityComponent component) {
@@ -62,31 +62,34 @@ public class InvitationsForumActivity extends InvitationsActivity {
 		}
 	}
 
+	@Override
 	protected InvitationAdapter getAdapter(Context ctx,
 			AvailableForumClickListener listener) {
 		return new ForumInvitationAdapter(ctx, listener);
 	}
 
+	@Override
 	protected void loadInvitations(final boolean clear) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				Collection<InvitationItem> invitations = new ArrayList<>();
 				try {
+					Collection<InvitationItem> invitations = new ArrayList<>();
 					long now = System.currentTimeMillis();
 					invitations.addAll(forumSharingManager.getInvitations());
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Load took " + duration + " ms");
+					displayInvitations(invitations, clear);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
-				displayInvitations(invitations, clear);
 			}
 		});
 	}
 
+	@Override
 	protected void respondToInvitation(final InvitationItem item,
 			final boolean accept) {
 		runOnDbThread(new Runnable() {
@@ -95,6 +98,7 @@ public class InvitationsForumActivity extends InvitationsActivity {
 				try {
 					Forum f = (Forum) item.getShareable();
 					for (Contact c : item.getNewSharers()) {
+						// TODO: What happens if a contact has been removed?
 						forumSharingManager.respondToInvitation(f, c, accept);
 					}
 				} catch (DbException e) {
@@ -105,10 +109,12 @@ public class InvitationsForumActivity extends InvitationsActivity {
 		});
 	}
 
+	@Override
 	protected int getAcceptRes() {
 		return R.string.forum_joined_toast;
 	}
 
+	@Override
 	protected int getDeclineRes() {
 		return R.string.forum_declined_toast;
 	}
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
index 969d525a3fdf2328ec9f0dea1358d0196da94778..377b10d71c52ead6583db71e6d44d92eb5048efa 100644
--- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
@@ -63,13 +63,21 @@ abstract class SharingStatusActivity extends BriarActivity {
 	}
 
 	@Override
-	public void onResume() {
-		super.onResume();
-
+	public void onStart() {
+		super.onStart();
 		loadSharedBy();
 		loadSharedWith();
 	}
 
+	@Override
+	public void onStop() {
+		super.onStop();
+		sharedByAdapter.clear();
+		sharedByList.showProgressBar();
+		sharedWithAdapter.clear();
+		sharedWithList.showProgressBar();
+	}
+
 	@Override
 	public boolean onOptionsItemSelected(final MenuItem item) {
 		// Handle presses on the action bar items
@@ -97,11 +105,11 @@ abstract class SharingStatusActivity extends BriarActivity {
 	}
 
 	private void loadSharedBy() {
-		dbController.runOnDbThread(new Runnable() {
+		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				List<ContactListItem> contactItems = new ArrayList<>();
 				try {
+					List<ContactListItem> contactItems = new ArrayList<>();
 					for (Contact c : getSharedBy()) {
 						LocalAuthor localAuthor = identityManager
 								.getLocalAuthor(c.getLocalAuthorId());
@@ -110,11 +118,11 @@ abstract class SharingStatusActivity extends BriarActivity {
 										groupId, new GroupCount(0, 0, 0));
 						contactItems.add(item);
 					}
+					displaySharedBy(contactItems);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
-				displaySharedBy(contactItems);
 			}
 		});
 	}
@@ -123,21 +131,18 @@ abstract class SharingStatusActivity extends BriarActivity {
 		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (contacts.isEmpty()) {
-					sharedByList.showData();
-				} else {
-					sharedByAdapter.addAll(contacts);
-				}
+				if (contacts.isEmpty()) sharedByList.showData();
+				else sharedByAdapter.addAll(contacts);
 			}
 		});
 	}
 
 	private void loadSharedWith() {
-		dbController.runOnDbThread(new Runnable() {
+		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				List<ContactListItem> contactItems = new ArrayList<>();
 				try {
+					List<ContactListItem> contactItems = new ArrayList<>();
 					for (Contact c : getSharedWith()) {
 						LocalAuthor localAuthor = identityManager
 								.getLocalAuthor(c.getLocalAuthorId());
@@ -146,11 +151,11 @@ abstract class SharingStatusActivity extends BriarActivity {
 										groupId, new GroupCount(0, 0, 0));
 						contactItems.add(item);
 					}
+					displaySharedWith(contactItems);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
 				}
-				displaySharedWith(contactItems);
 			}
 		});
 	}
@@ -159,11 +164,8 @@ abstract class SharingStatusActivity extends BriarActivity {
 		runOnUiThreadUnlessDestroyed(new Runnable() {
 			@Override
 			public void run() {
-				if (contacts.isEmpty()) {
-					sharedWithList.showData();
-				} else {
-					sharedWithAdapter.addAll(contacts);
-				}
+				if (contacts.isEmpty()) sharedWithList.showData();
+				else sharedWithAdapter.addAll(contacts);
 			}
 		});
 	}
diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java
index 889399525de6ab9a880511dd43789533d65b835d..5ae9b5c6ff72b2bf6b806ac03c467274db965e37 100644
--- a/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java
+++ b/briar-android/src/org/briarproject/android/threaded/ThreadListActivity.java
@@ -75,7 +75,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
 
 		if (state != null) {
 			byte[] replyIdBytes = state.getByteArray(KEY_REPLY_ID);
-			if(replyIdBytes != null) replyId = new MessageId(replyIdBytes);
+			if (replyIdBytes != null) replyId = new MessageId(replyIdBytes);
 		}
 
 		loadItems();
@@ -131,35 +131,33 @@ public abstract class ThreadListActivity<G extends NamedGroup, I extends ThreadI
 
 	@CallSuper
 	@Override
-	public void onResume() {
-		super.onResume();
+	public void onStart() {
+		super.onStart();
 		list.startPeriodicUpdate();
 	}
 
 	@CallSuper
 	@Override
-	public void onPause() {
-		super.onPause();
+	public void onStop() {
+		super.onStop();
 		list.stopPeriodicUpdate();
 	}
 
 	@Override
 	protected void onRestoreInstanceState(Bundle savedInstanceState) {
 		super.onRestoreInstanceState(savedInstanceState);
-		textInput.setVisibility(
-				savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY) ?
-						VISIBLE : GONE);
+		boolean visible = savedInstanceState.getBoolean(KEY_INPUT_VISIBILITY);
+		textInput.setVisibility(visible ? VISIBLE : GONE);
 	}
 
 	@Override
 	protected void onSaveInstanceState(Bundle outState) {
 		super.onSaveInstanceState(outState);
-		outState.putBoolean(KEY_INPUT_VISIBILITY,
-				textInput.getVisibility() == VISIBLE);
+		boolean visible = textInput.getVisibility() == VISIBLE;
+		outState.putBoolean(KEY_INPUT_VISIBILITY, visible);
 		ThreadItem replyItem = adapter.getReplyItem();
 		if (replyItem != null) {
-			outState.putByteArray(KEY_REPLY_ID,
-					replyItem.getId().getBytes());
+			outState.putByteArray(KEY_REPLY_ID, replyItem.getId().getBytes());
 		}
 	}
 
diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java
index 7dd039dfee74575a790718b7f1010366901a6cf6..80a5b44ea2ab4a968dc897dcd5d6c6f517c7b84a 100644
--- a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java
+++ b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java
@@ -49,8 +49,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	private final EventBus eventBus;
 	private final Clock clock;
 
-	private final Map<MessageId, String> bodyCache =
-			new ConcurrentHashMap<>();
+	private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
 
 	private volatile GroupId groupId;
 
@@ -82,14 +81,14 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 
 	@CallSuper
 	@Override
-	public void onActivityResume() {
+	public void onActivityStart() {
 		notificationManager.blockNotification(getGroupId());
 		eventBus.addListener(this);
 	}
 
 	@CallSuper
 	@Override
-	public void onActivityPause() {
+	public void onActivityStop() {
 		notificationManager.unblockNotification(getGroupId());
 		eventBus.removeListener(this);
 	}
@@ -127,8 +126,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 					G groupItem = loadNamedGroup();
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
-						LOG.info(
-								"Loading named group took " + duration + " ms");
+						LOG.info("Loading group took " + duration + " ms");
 					handler.onResult(groupItem);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
@@ -149,7 +147,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				LOG.info("Loading items...");
 				try {
 					// Load headers
 					long now = System.currentTimeMillis();
@@ -193,8 +190,8 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
-				LOG.info("Loading item...");
 				try {
+					long now = System.currentTimeMillis();
 					String body;
 					if (!bodyCache.containsKey(header.getId())) {
 						body = loadMessageBody(header.getId());
@@ -202,6 +199,9 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 					} else {
 						body = bodyCache.get(header.getId());
 					}
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Loading item took " + duration + " ms");
 					I item = buildItem(header, body);
 					handler.onResult(item);
 				} catch (DbException e) {
@@ -250,12 +250,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 			@Override
 			public void run() {
 				try {
+					long now = System.currentTimeMillis();
 					LocalAuthor author = identityManager.getLocalAuthor();
 					long timestamp = getLatestTimestamp();
-					timestamp =
-							Math.max(timestamp, clock.currentTimeMillis());
-					createMessage(body, timestamp, parentId, author,
-							handler);
+					timestamp = Math.max(timestamp, clock.currentTimeMillis());
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO)) {
+						LOG.info("Loading identity and timestamp took " +
+								duration + " ms");
+					}
+					createMessage(body, timestamp, parentId, author, handler);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
@@ -274,8 +278,11 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 		cryptoExecutor.execute(new Runnable() {
 			@Override
 			public void run() {
-				LOG.info("Creating message...");
+				long now = System.currentTimeMillis();
 				M msg = createLocalMessage(body, timestamp, parentId, author);
+				long duration = System.currentTimeMillis() - now;
+				if (LOG.isLoggable(INFO))
+					LOG.info("Creating message took " + duration + " ms");
 				storePost(msg, body, handler);
 			}
 		});
@@ -291,7 +298,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 			@Override
 			public void run() {
 				try {
-					LOG.info("Store message...");
 					long now = System.currentTimeMillis();
 					H header = addLocalMessage(msg);
 					bodyCache.put(msg.getMessage().getId(), body);
@@ -354,10 +360,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
 	}
 
 	private void checkGroupId() {
-		if (groupId == null) {
-			throw new IllegalStateException(
-					"You must set the GroupId before the controller is started.");
-		}
+		if (groupId == null) throw new IllegalStateException();
 	}
 
 }
diff --git a/briar-android/src/org/briarproject/android/util/BriarAdapter.java b/briar-android/src/org/briarproject/android/util/BriarAdapter.java
index 0385c56c362027dad5ced4167a10ef574657d48d..e9e4b3dbac97de7b4067e1c31905043c46e50c7a 100644
--- a/briar-android/src/org/briarproject/android/util/BriarAdapter.java
+++ b/briar-android/src/org/briarproject/android/util/BriarAdapter.java
@@ -75,6 +75,13 @@ public abstract class BriarAdapter<T, V extends ViewHolder>
 		this.items.addAll(items);
 	}
 
+	public void setItems(Collection<T> items) {
+		this.items.beginBatchedUpdates();
+		this.items.clear();
+		this.items.addAll(items);
+		this.items.endBatchedUpdates();
+	}
+
 	@Nullable
 	public T getItemAt(int position) {
 		if (position == INVALID_POSITION || position >= items.size()) {
diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java b/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java
index 3d531c4e05f6c51d5f0270ae6b8fbc40b2226956..f1002e66b9d424cfbadc7199c65a42bc48911678 100644
--- a/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java
+++ b/briar-api/src/org/briarproject/api/crypto/CryptoExecutor.java
@@ -1,17 +1,25 @@
 package org.briarproject.api.crypto;
 
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import javax.inject.Qualifier;
 
-/** Annotation for injecting the executor for long-running crypto tasks. */
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for injecting the executor for long-running crypto tasks. Also
+ * used for annotating methods that should run on the crypto executor.
+ * <p>
+ * The contract of this executor is that tasks may be run concurrently, and
+ * submitting a task will never block. Tasks must not run indefinitely. Tasks
+ * submitted during shutdown are discarded.
+ */
 @Qualifier
 @Target({FIELD, METHOD, PARAMETER})
 @Retention(RUNTIME)
-public @interface CryptoExecutor {}
+public @interface CryptoExecutor {
+}
diff --git a/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java b/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java
index f682121d077dea6805e7ac4ecf99827ba3c02bab..5421f451f872684ab02305f42a0261aa87203010 100644
--- a/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java
+++ b/briar-api/src/org/briarproject/api/db/DatabaseExecutor.java
@@ -1,21 +1,23 @@
 package org.briarproject.api.db;
 
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import javax.inject.Qualifier;
 
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
- * Annotation for injecting the executor for database tasks.
+ * Annotation for injecting the executor for database tasks. Also used for
+ * annotating methods that should run on the database executor.
  * <p>
- * The contract of this executor is that tasks are executed in the order
- * they're submitted, tasks are not executed concurrently, and submitting a
- * task will never block.
+ * The contract of this executor is that tasks are run in the order they're
+ * submitted, tasks are not run concurrently, and submitting a task will never
+ * block. Tasks must not run indefinitely. Tasks submitted during shutdown are
+ * discarded.
  */
 @Qualifier
 @Target({ FIELD, METHOD, PARAMETER })
diff --git a/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java
index 04f7f9164575eadc2021c2286676df01e32e87be..e1ddbfd1942494e2a3079ff4f28148142ecf62f1 100644
--- a/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java
+++ b/briar-api/src/org/briarproject/api/event/PrivateMessageReceivedEvent.java
@@ -1,5 +1,6 @@
 package org.briarproject.api.event;
 
+import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.messaging.PrivateMessageHeader;
 import org.briarproject.api.sync.GroupId;
 
@@ -9,11 +10,13 @@ import org.briarproject.api.sync.GroupId;
 public class PrivateMessageReceivedEvent extends Event {
 
 	private final PrivateMessageHeader messageHeader;
+	private final ContactId contactId;
 	private final GroupId groupId;
 
 	public PrivateMessageReceivedEvent(PrivateMessageHeader messageHeader,
-			GroupId groupId) {
+			ContactId contactId, GroupId groupId) {
 		this.messageHeader = messageHeader;
+		this.contactId = contactId;
 		this.groupId = groupId;
 	}
 
@@ -21,6 +24,10 @@ public class PrivateMessageReceivedEvent extends Event {
 		return messageHeader;
 	}
 
+	public ContactId getContactId() {
+		return contactId;
+	}
+
 	public GroupId getGroupId() {
 		return groupId;
 	}
diff --git a/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java b/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java
index 02bc5bf875a941be136b0939a268028739a4d2f4..1bffc3c3cc73c9fa9f32b48c87e65d014c9f5b87 100644
--- a/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java
+++ b/briar-api/src/org/briarproject/api/lifecycle/IoExecutor.java
@@ -1,17 +1,25 @@
 package org.briarproject.api.lifecycle;
 
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import javax.inject.Qualifier;
 
-/** Annotation for injecting the executor used by long-lived IO tasks. */
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for injecting the executor for long-running IO tasks. Also used
+ * for annotating methods that should run on the UI executor.
+ * <p>
+ * The contract of this executor is that tasks may be run concurrently, and
+ * submitting a task will never block. Tasks may run indefinitely. Tasks
+ * submitted during shutdown are discarded.
+ */
 @Qualifier
-@Target({ FIELD, METHOD, PARAMETER })
+@Target({FIELD, METHOD, PARAMETER})
 @Retention(RUNTIME)
-public @interface IoExecutor {}
\ No newline at end of file
+public @interface IoExecutor {
+}
\ No newline at end of file
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index 8a591849a24ca5643abf77ce54f12b2340cf8166..a8fa365cb71dcc8f0f7d2dfc705937d1543a0a10 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -102,10 +102,11 @@ class MessagingManagerImpl extends ConversationClientImpl
 		boolean local = meta.getBoolean("local");
 		boolean read = meta.getBoolean(MSG_KEY_READ);
 		PrivateMessageHeader header = new PrivateMessageHeader(
-				m.getId(), m.getGroupId(), timestamp, contentType, local, read,
+				m.getId(), groupId, timestamp, contentType, local, read,
 				false, false);
+		ContactId contactId = getContactId(txn, groupId);
 		PrivateMessageReceivedEvent event = new PrivateMessageReceivedEvent(
-				header, groupId);
+				header, contactId, groupId);
 		txn.attach(event);
 		trackIncomingMessage(txn, m);
 
@@ -133,6 +134,17 @@ class MessagingManagerImpl extends ConversationClientImpl
 		}
 	}
 
+	private ContactId getContactId(Transaction txn, GroupId g)
+			throws DbException {
+		try {
+			BdfDictionary meta =
+					clientHelper.getGroupMetadataAsDictionary(txn, g);
+			return new ContactId(meta.getLong("contactId").intValue());
+		} catch (FormatException e) {
+			throw new DbException(e);
+		}
+	}
+
 	@Override
 	public ContactId getContactId(GroupId g) throws DbException {
 		try {