diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 722e6b8588e2c49dc6a658ee2661bd3e0d990859..6f3f1f4e894eb470fb2cd70c80dad556932d8bc2 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -77,11 +77,11 @@ import org.briarproject.util.StringUtils;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
 
@@ -106,7 +106,7 @@ public class ConversationActivity extends BriarActivity
 	private static final Logger LOG =
 			Logger.getLogger(ConversationActivity.class.getName());
 	private static final int REQUEST_CODE_INTRODUCTION = 1;
-	public static final String SHOW_ONBOARDING_INTRODUCTION =
+	private static final String SHOW_ONBOARDING_INTRODUCTION =
 			"showOnboardingIntroduction";
 
 	@Inject
@@ -115,7 +115,9 @@ public class ConversationActivity extends BriarActivity
 	ConnectionRegistry connectionRegistry;
 	@Inject
 	@CryptoExecutor
-	protected Executor cryptoExecutor;
+	Executor cryptoExecutor;
+
+	private final Map<MessageId, byte[]> bodyCache = new ConcurrentHashMap<>();
 
 	private ConversationAdapter adapter;
 	private Toolbar toolbar;
@@ -148,7 +150,6 @@ public class ConversationActivity extends BriarActivity
 	private volatile String contactName = null;
 	private volatile byte[] contactIdenticonKey = null;
 	private volatile boolean connected = false;
-	private volatile Map<MessageId, byte[]> bodyCache = new HashMap<>();
 
 	@SuppressWarnings("ConstantConditions")
 	@Override
@@ -167,7 +168,8 @@ public class ConversationActivity extends BriarActivity
 		if (toolbar != null) {
 			toolbarAvatar =
 					(CircleImageView) toolbar.findViewById(R.id.contactAvatar);
-			toolbarStatus = (ImageView) toolbar.findViewById(R.id.contactStatus);
+			toolbarStatus =
+					(ImageView) toolbar.findViewById(R.id.contactStatus);
 			toolbarTitle = (TextView) toolbar.findViewById(R.id.contactName);
 			setSupportActionBar(toolbar);
 		}
@@ -383,11 +385,9 @@ public class ConversationActivity extends BriarActivity
 				} else {
 					List<ConversationItem> items = new ArrayList<>();
 					for (PrivateMessageHeader h : headers) {
-						ConversationMessageItem item =
-								(ConversationMessageItem) ConversationItem
-										.from(h);
+						ConversationMessageItem item = ConversationItem.from(h);
 						byte[] body = bodyCache.get(h.getId());
-						if (body == null) loadMessageBody(h);
+						if (body == null) loadMessageBody(h.getId());
 						else item.setBody(body);
 						items.add(item);
 					}
@@ -406,12 +406,10 @@ public class ConversationActivity extends BriarActivity
 					}
 					for (InvitationMessage i : invitations) {
 						if (i instanceof InvitationRequest) {
-							InvitationRequest r =
-									(InvitationRequest) i;
+							InvitationRequest r = (InvitationRequest) i;
 							items.add(ConversationItem.from(r));
 						} else if (i instanceof InvitationResponse) {
-							InvitationResponse r =
-									(InvitationResponse) i;
+							InvitationResponse r = (InvitationResponse) i;
 							items.add(ConversationItem
 									.from(ConversationActivity.this,
 											contactName, r));
@@ -425,17 +423,17 @@ public class ConversationActivity extends BriarActivity
 		});
 	}
 
-	private void loadMessageBody(final PrivateMessageHeader h) {
+	private void loadMessageBody(final MessageId m) {
 		runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
 				try {
 					long now = System.currentTimeMillis();
-					byte[] body = messagingManager.getMessageBody(h.getId());
+					byte[] body = messagingManager.getMessageBody(m);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
-						LOG.info("Loading message took " + duration + " ms");
-					displayMessageBody(h.getId(), body);
+						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) {
@@ -525,7 +523,7 @@ public class ConversationActivity extends BriarActivity
 				LOG.info("Message received, adding");
 				PrivateMessageHeader h = p.getMessageHeader();
 				addConversationItem(ConversationItem.from(h));
-				loadMessageBody(h);
+				loadMessageBody(h.getId());
 				markMessageReadIfNew(h);
 			}
 		} else if (e instanceof MessagesSentEvent) {
@@ -663,9 +661,9 @@ public class ConversationActivity extends BriarActivity
 			@Override
 			public void run() {
 				try {
-					storeMessage(privateMessageFactory
-							.createPrivateMessage(groupId, timestamp, null,
-									"text/plain", body), body);
+					storeMessage(privateMessageFactory.createPrivateMessage(
+							groupId, timestamp, null, "text/plain", body),
+							body);
 				} catch (FormatException e) {
 					throw new RuntimeException(e);
 				}
@@ -684,14 +682,13 @@ public class ConversationActivity extends BriarActivity
 					if (LOG.isLoggable(INFO))
 						LOG.info("Storing message took " + duration + " ms");
 
-					PrivateMessageHeader h = new PrivateMessageHeader(
-							m.getMessage().getId(),
+					MessageId id = m.getMessage().getId();
+					PrivateMessageHeader h = new PrivateMessageHeader(id,
 							m.getMessage().getTimestamp(), m.getContentType(),
 							true, false, false, false);
-					ConversationMessageItem item =
-							(ConversationMessageItem) ConversationItem.from(h);
+					ConversationMessageItem item = ConversationItem.from(h);
 					item.setBody(body);
-					bodyCache.put(m.getMessage().getId(), body);
+					bodyCache.put(id, body);
 					addConversationItem(item);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
index caefec6a61bb328f602e1c972273653f53c29792..331a062358c62d4c6d5fef55771e6259cda7ac0f 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
@@ -3,12 +3,12 @@ package org.briarproject.android.contact;
 import org.briarproject.api.introduction.IntroductionRequest;
 
 // This class is not thread-safe
-public class ConversationIntroductionInItem extends ConversationIntroductionItem
+class ConversationIntroductionInItem extends ConversationIntroductionItem
 		implements ConversationItem.IncomingItem {
 
 	private boolean read;
 
-	public ConversationIntroductionInItem(IntroductionRequest ir) {
+	ConversationIntroductionInItem(IntroductionRequest ir) {
 		super(ir);
 
 		this.read = ir.isRead();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java
index 51a7c3ebbc789ba05adfea1e4ee3a8afd5964f2c..5fb30a23d96611efffbaa7ba13541082109e8483 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java
@@ -8,22 +8,22 @@ abstract class ConversationIntroductionItem extends ConversationItem {
 	private final IntroductionRequest ir;
 	private boolean answered;
 
-	public ConversationIntroductionItem(IntroductionRequest ir) {
+	ConversationIntroductionItem(IntroductionRequest ir) {
 		super(ir.getMessageId(), ir.getTimestamp());
 
 		this.ir = ir;
 		this.answered = ir.wasAnswered();
 	}
 
-	public IntroductionRequest getIntroductionRequest() {
+	IntroductionRequest getIntroductionRequest() {
 		return ir;
 	}
 
-	public boolean wasAnswered() {
+	boolean wasAnswered() {
 		return answered;
 	}
 
-	public void setAnswered(boolean answered) {
+	void setAnswered(boolean answered) {
 		this.answered = answered;
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionOutItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionOutItem.java
index 7c7082a8d0538da2b74656a935ba64269de290ab..2729fea0cd549748c7cfccceb43f12813503505d 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionOutItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionOutItem.java
@@ -9,13 +9,12 @@ import org.briarproject.api.introduction.IntroductionRequest;
  *
  *  This class is not thread-safe
  */
-public class ConversationIntroductionOutItem
-		extends ConversationIntroductionItem
+class ConversationIntroductionOutItem extends ConversationIntroductionItem
 		implements ConversationItem.OutgoingItem {
 
 	private boolean sent, seen;
 
-	public ConversationIntroductionOutItem(IntroductionRequest ir) {
+	ConversationIntroductionOutItem(IntroductionRequest ir) {
 		super(ir);
 		this.sent = ir.isSent();
 		this.seen = ir.isSeen();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationItem.java b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
index 321cceab338bb2b996767dcfb9a00d3f84bbd0c2..083dc6bf7840ce47c8611d729e2ec5de1dc583dd 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
@@ -48,14 +48,15 @@ public abstract class ConversationItem {
 		return time;
 	}
 
-	public static ConversationItem from(PrivateMessageHeader h) {
-		if (h.isLocal())
+	public static ConversationMessageItem from(PrivateMessageHeader h) {
+		if (h.isLocal()) {
 			return new ConversationMessageOutItem(h);
-		else
+		} else {
 			return new ConversationMessageInItem(h);
+		}
 	}
 
-	public static ConversationItem from(IntroductionRequest ir) {
+	public static ConversationIntroductionItem from(IntroductionRequest ir) {
 		if (ir.isLocal()) {
 			return new ConversationIntroductionOutItem(ir);
 		} else {
@@ -63,7 +64,7 @@ public abstract class ConversationItem {
 		}
 	}
 
-	public static ConversationItem from(Context ctx, String contactName,
+	public static ConversationNoticeItem from(Context ctx, String contactName,
 			IntroductionResponse ir) {
 
 		if (ir.isLocal()) {
@@ -101,7 +102,8 @@ public abstract class ConversationItem {
 		}
 	}
 
-	public static ConversationItem from(InvitationRequest fim) {
+	public static ConversationShareableInvitationItem from(
+			InvitationRequest fim) {
 		if (fim.isLocal()) {
 			return new ConversationShareableInvitationOutItem(fim);
 		} else {
@@ -109,7 +111,7 @@ public abstract class ConversationItem {
 		}
 	}
 
-	public static ConversationItem from(Context ctx, String contactName,
+	public static ConversationNoticeItem from(Context ctx, String contactName,
 			InvitationResponse ir) {
 
 		if (ir instanceof ForumInvitationResponse) {
@@ -121,7 +123,7 @@ public abstract class ConversationItem {
 		}
 	}
 
-	private static ConversationItem from(Context ctx, String contactName,
+	private static ConversationNoticeItem from(Context ctx, String contactName,
 			ForumInvitationResponse fir) {
 
 		if (fir.isLocal()) {
@@ -153,7 +155,7 @@ public abstract class ConversationItem {
 		}
 	}
 
-	private static ConversationItem from(Context ctx, String contactName,
+	private static ConversationNoticeItem from(Context ctx, String contactName,
 			BlogInvitationResponse fir) {
 
 		if (fir.isLocal()) {
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationMessageInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationMessageInItem.java
index 7969aebd7890d6ee06b168ac07a7fc1ec7527502..eefef09b4ef4dc3c38d8d2896ce405af9948e61b 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationMessageInItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationMessageInItem.java
@@ -3,12 +3,12 @@ package org.briarproject.android.contact;
 import org.briarproject.api.messaging.PrivateMessageHeader;
 
 // This class is not thread-safe
-public class ConversationMessageInItem extends ConversationMessageItem
+class ConversationMessageInItem extends ConversationMessageItem
 		implements ConversationItem.IncomingItem {
 
 	private boolean read;
 
-	public ConversationMessageInItem(PrivateMessageHeader header) {
+	ConversationMessageInItem(PrivateMessageHeader header) {
 		super(header);
 
 		read = header.isRead();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java b/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java
index f151cde176483d72be4637e4c9924ce9e517d97c..b7a6aac44a9b35698ae9a5a59c744be1b46d0034 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationMessageItem.java
@@ -8,7 +8,7 @@ abstract class ConversationMessageItem extends ConversationItem {
 	private final PrivateMessageHeader header;
 	private byte[] body;
 
-	public ConversationMessageItem(PrivateMessageHeader header) {
+	ConversationMessageItem(PrivateMessageHeader header) {
 		super(header.getId(), header.getTimestamp());
 
 		this.header = header;
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationMessageOutItem.java b/briar-android/src/org/briarproject/android/contact/ConversationMessageOutItem.java
index 7fc6025546ad15f50858c1601b8ff22acba3a647..550219e9b3e5cd9aadc71405bb0488b9513fbc4b 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationMessageOutItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationMessageOutItem.java
@@ -3,12 +3,12 @@ package org.briarproject.android.contact;
 import org.briarproject.api.messaging.PrivateMessageHeader;
 
 // This class is not thread-safe
-public class ConversationMessageOutItem extends ConversationMessageItem
+class ConversationMessageOutItem extends ConversationMessageItem
 		implements ConversationItem.OutgoingItem {
 
 	private boolean sent, seen;
 
-	public ConversationMessageOutItem(PrivateMessageHeader header) {
+	ConversationMessageOutItem(PrivateMessageHeader header) {
 		super(header);
 
 		sent = header.isSent();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java
index 9b4acb556aea257f5b52d96019794266e45b9738..bfa83160b167cac8761a3cde87a59fc195cfdde5 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeInItem.java
@@ -3,12 +3,12 @@ package org.briarproject.android.contact;
 import org.briarproject.api.sync.MessageId;
 
 // This class is not thread-safe
-public class ConversationNoticeInItem extends ConversationNoticeItem
+class ConversationNoticeInItem extends ConversationNoticeItem
 		implements ConversationItem.IncomingItem {
 
 	private boolean read;
 
-	public ConversationNoticeInItem(MessageId id, String text, long time,
+	ConversationNoticeInItem(MessageId id, String text, long time,
 			boolean read) {
 		super(id, text, time);
 
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java
index 8245f775887c7994bee6a5f19d87b73f41b621cb..b722ab95d2c32c945e544dcda0d10c5e95e8472f 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeItem.java
@@ -6,7 +6,7 @@ abstract class ConversationNoticeItem extends ConversationItem {
 
 	private final String text;
 
-	public ConversationNoticeItem(MessageId id, String text, long time) {
+	ConversationNoticeItem(MessageId id, String text, long time) {
 		super(id, time);
 
 		this.text = text;
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java b/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java
index c8a6b5459c1b6af0638d6b183e2e3004db07c381..a5bdb5e20bf1fc2255c3c27214d3ecabd80fe329 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationNoticeOutItem.java
@@ -3,12 +3,12 @@ package org.briarproject.android.contact;
 import org.briarproject.api.sync.MessageId;
 
 // This class is not thread-safe
-public class ConversationNoticeOutItem extends ConversationNoticeItem
+class ConversationNoticeOutItem extends ConversationNoticeItem
 		implements ConversationItem.OutgoingItem {
 
 	private boolean sent, seen;
 
-	public ConversationNoticeOutItem(MessageId id, String text, long time,
+	ConversationNoticeOutItem(MessageId id, String text, long time,
 			boolean sent, boolean seen) {
 		super(id, text, time);