diff --git a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
index 966de01db949176bda374f03248e51174c1c0b88..7d47079e137bde40a5db8c649291f78938910286 100644
--- a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
+++ b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
@@ -28,7 +28,7 @@ import org.briarproject.api.event.ForumPostReceivedEvent;
 import org.briarproject.api.event.IntroductionRequestReceivedEvent;
 import org.briarproject.api.event.IntroductionResponseReceivedEvent;
 import org.briarproject.api.event.IntroductionSucceededEvent;
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.event.PrivateMessageReceivedEvent;
 import org.briarproject.api.event.SettingsUpdatedEvent;
@@ -235,8 +235,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		} else if (e instanceof IntroductionResponseReceivedEvent) {
 			ContactId c = ((IntroductionResponseReceivedEvent) e).getContactId();
 			showNotificationForPrivateConversation(c);
-		} else if (e instanceof InvitationReceivedEvent) {
-			ContactId c = ((InvitationReceivedEvent) e).getContactId();
+		} else if (e instanceof InvitationRequestReceivedEvent) {
+			ContactId c = ((InvitationRequestReceivedEvent) e).getContactId();
 			showNotificationForPrivateConversation(c);
 		} else if (e instanceof InvitationResponseReceivedEvent) {
 			ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();
diff --git a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
index 633ced849e037c0896ea6202028828bf527a59f0..aa48714f77f086e031054e7d5929e5b70c11ed24 100644
--- a/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/BaseContactListAdapter.java
@@ -50,10 +50,8 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
 			}
 		});
 
-		if (item.getGroupId() != null) {
-			ViewCompat.setTransitionName(ui.avatar, "avatar" +
-					StringUtils.toHexString(item.getGroupId().getBytes()));
-		}
+		ViewCompat.setTransitionName(ui.avatar, "avatar" +
+				StringUtils.toHexString(item.getGroupId().getBytes()));
 	}
 
 	@Override
@@ -96,8 +94,7 @@ public abstract class BaseContactListAdapter<VH extends BaseContactListAdapter.B
 		int count = getItemCount();
 		for (int i = 0; i < count; i++) {
 			ContactListItem item = getItemAt(i);
-			if (item != null && item.getGroupId() != null &&
-					item.getGroupId().equals(g)) {
+			if (item != null && item.getGroupId().equals(g)) {
 				return i;
 			}
 		}
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
index f7c3444adc24f5253900efa9c5aa87433c293b00..a2cf8012d3eae990d857108fa282a63234822805 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListAdapter.java
@@ -35,7 +35,7 @@ public class ContactListAdapter
 		if (item == null) return;
 
 		// unread count
-		long unread = item.getUnreadCount();
+		int unread = item.getUnreadCount();
 		if (unread > 0) {
 			ui.unread.setText(String.valueOf(unread));
 			ui.unread.setVisibility(View.VISIBLE);
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index 637d893fa92193b46108916ca6768250d8ce3f48..22f77a841dc18a44aadf1c5772718188d4159b95 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -36,7 +36,7 @@ import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.IntroductionRequestReceivedEvent;
 import org.briarproject.api.event.IntroductionResponseReceivedEvent;
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.event.PrivateMessageReceivedEvent;
 import org.briarproject.api.identity.IdentityManager;
@@ -121,7 +121,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 					@Override
 					public void onItemClick(View view, ContactListItem item) {
 						GroupId groupId = item.getGroupId();
-						if (groupId == null) return;
 						Intent i = new Intent(getActivity(),
 								ConversationActivity.class);
 						i.putExtra(GROUP_ID, groupId.getBytes());
@@ -270,9 +269,9 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 					(IntroductionResponseReceivedEvent) e;
 			IntroductionResponse ir = m.getIntroductionResponse();
 			updateItem(m.getContactId(), ConversationItem.from(ir));
-		} else if (e instanceof InvitationReceivedEvent) {
+		} else if (e instanceof InvitationRequestReceivedEvent) {
 			LOG.info("Invitation Request received, update contact");
-			InvitationReceivedEvent m = (InvitationReceivedEvent) e;
+			InvitationRequestReceivedEvent m = (InvitationRequestReceivedEvent) e;
 			InvitationRequest ir = m.getRequest();
 			updateItem(m.getContactId(), ConversationItem.from(ir));
 		} else if (e instanceof InvitationResponseReceivedEvent) {
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListItem.java b/briar-android/src/org/briarproject/android/contact/ContactListItem.java
index 9a6b8ea998668a3341de18733eaf6de6ea8e4c3f..e90cdf939b14f6a582594bcc36dd36d4b2aa7909 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListItem.java
@@ -1,11 +1,10 @@
 package org.briarproject.android.contact;
 
-import android.support.annotation.Nullable;
-
 import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.sync.GroupId;
+import org.jetbrains.annotations.NotNull;
 
 import static org.briarproject.android.contact.ConversationItem.IncomingItem;
 
@@ -17,10 +16,11 @@ public class ContactListItem {
 	private final GroupId groupId;
 	private boolean connected, empty;
 	private long timestamp;
-	private long unread;
+	private int unread;
 
-	public ContactListItem(Contact contact, LocalAuthor localAuthor,
-			boolean connected, @Nullable GroupId groupId, GroupCount count) {
+	public ContactListItem(@NotNull Contact contact,
+			@NotNull LocalAuthor localAuthor, boolean connected,
+			@NotNull GroupId groupId, @NotNull GroupCount count) {
 		this.contact = contact;
 		this.localAuthor = localAuthor;
 		this.groupId = groupId;
@@ -48,7 +48,6 @@ public class ContactListItem {
 		return localAuthor;
 	}
 
-	@Nullable
 	GroupId getGroupId() {
 		return groupId;
 	}
@@ -69,7 +68,7 @@ public class ContactListItem {
 		return timestamp;
 	}
 
-	long getUnreadCount() {
+	int getUnreadCount() {
 		return unread;
 	}
 }
\ No newline at end of file
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 14851da07a97be6cebe980f67600e7c3e9e5a0a5..75c0b88c8fc38fda8a0b4bda51de840049608bf8 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -51,7 +51,7 @@ import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.IntroductionRequestReceivedEvent;
 import org.briarproject.api.event.IntroductionResponseReceivedEvent;
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.event.MessagesAckedEvent;
 import org.briarproject.api.event.MessagesSentEvent;
@@ -77,7 +77,7 @@ 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;
@@ -481,12 +481,13 @@ public class ConversationActivity extends BriarActivity
 		SparseArray<IncomingItem> list = adapter.getIncomingMessages();
 		for (int i = 0; i < list.size(); i++) {
 			IncomingItem item = list.valueAt(i);
-			if (!item.isRead()) unread.put(item.getId(), item.getGroupId());
+			if (!item.isRead())
+				unread.put(item.getId(), item.getGroupId());
 		}
 		if (unread.isEmpty()) return;
 		if (LOG.isLoggable(INFO))
 			LOG.info("Marking " + unread.size() + " messages read");
-		markMessagesRead(Collections.unmodifiableMap(unread));
+		markMessagesRead(unread);
 	}
 
 	private void markMessagesRead(final Map<MessageId, GroupId> unread) {
@@ -573,9 +574,9 @@ public class ConversationActivity extends BriarActivity
 				addConversationItem(item);
 				markMessageReadIfNew(ir);
 			}
-		} else if (e instanceof InvitationReceivedEvent) {
-			InvitationReceivedEvent event =
-					(InvitationReceivedEvent) e;
+		} else if (e instanceof InvitationRequestReceivedEvent) {
+			InvitationRequestReceivedEvent event =
+					(InvitationRequestReceivedEvent) e;
 			if (event.getContactId().equals(contactId)) {
 				LOG.info("Invitation received, adding...");
 				InvitationRequest ir = event.getRequest();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
index 331a062358c62d4c6d5fef55771e6259cda7ac0f..6959d214b10abb5599c5d1e04d439ecc7ae1f296 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionInItem.java
@@ -1,14 +1,16 @@
 package org.briarproject.android.contact;
 
+import org.briarproject.android.contact.ConversationItem.IncomingItem;
 import org.briarproject.api.introduction.IntroductionRequest;
+import org.jetbrains.annotations.NotNull;
 
 // This class is not thread-safe
 class ConversationIntroductionInItem extends ConversationIntroductionItem
-		implements ConversationItem.IncomingItem {
+		implements IncomingItem {
 
 	private boolean read;
 
-	ConversationIntroductionInItem(IntroductionRequest ir) {
+	ConversationIntroductionInItem(@NotNull 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 123887df8d394f5827b2fcc777170b4886e0a3dc..d2cdef596ffdadd4c4b38a280f5536ce0d4ead6a 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationIntroductionItem.java
@@ -1,6 +1,7 @@
 package org.briarproject.android.contact;
 
 import org.briarproject.api.introduction.IntroductionRequest;
+import org.jetbrains.annotations.NotNull;
 
 // This class is not thread-safe
 abstract class ConversationIntroductionItem extends ConversationItem {
@@ -8,13 +9,14 @@ abstract class ConversationIntroductionItem extends ConversationItem {
 	private final IntroductionRequest ir;
 	private boolean answered;
 
-	ConversationIntroductionItem(IntroductionRequest ir) {
+	ConversationIntroductionItem(@NotNull IntroductionRequest ir) {
 		super(ir.getMessageId(), ir.getGroupId(), ir.getTimestamp());
 
 		this.ir = ir;
 		this.answered = ir.wasAnswered();
 	}
 
+	@NotNull
 	IntroductionRequest getIntroductionRequest() {
 		return ir;
 	}
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationItem.java b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
index 99b9d116d3d4e67014634764c857f4b777f338f2..d8c5e5aa746900f212744ae1423f811e5e09f818 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationItem.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationItem.java
@@ -14,6 +14,7 @@ import org.briarproject.api.sharing.InvitationRequest;
 import org.briarproject.api.sharing.InvitationResponse;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 // This class is not thread-safe
 public abstract class ConversationItem {
@@ -31,11 +32,12 @@ public abstract class ConversationItem {
 	final static int BLOG_INVITATION_IN = 9;
 	final static int BLOG_INVITATION_OUT = 10;
 
-	private MessageId id;
-	private GroupId groupId;
-	private long time;
+	final private MessageId id;
+	final private GroupId groupId;
+	final private long time;
 
-	public ConversationItem(MessageId id, GroupId groupId, long time) {
+	public ConversationItem(@NotNull MessageId id, @NotNull GroupId groupId,
+			long time) {
 		this.id = id;
 		this.groupId = groupId;
 		this.time = time;
@@ -43,10 +45,12 @@ public abstract class ConversationItem {
 
 	abstract int getType();
 
+	@NotNull
 	public MessageId getId() {
 		return id;
 	}
 
+	@NotNull
 	public GroupId getGroupId() {
 		return groupId;
 	}
@@ -221,6 +225,7 @@ public abstract class ConversationItem {
 
 	interface OutgoingItem {
 
+		@NotNull
 		MessageId getId();
 
 		boolean isSent();
@@ -234,8 +239,10 @@ public abstract class ConversationItem {
 
 	interface IncomingItem {
 
+		@NotNull
 		MessageId getId();
 
+		@NotNull
 		GroupId getGroupId();
 
 		boolean isRead();
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
index 83f2a793a3107be18a9525e0bbc76517f91dd0e4..ca237eb35e8847002c3aec56dd3894a0cd285911 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
@@ -51,7 +51,7 @@ class ForumListAdapter
 		ui.name.setText(item.getForum().getName());
 
 		// Post Count
-		int postCount = (int) item.getPostCount();
+		int postCount = item.getPostCount();
 		if (postCount > 0) {
 			ui.avatar.setProblem(false);
 			ui.postCount.setText(ctx.getResources()
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListItem.java b/briar-android/src/org/briarproject/android/forum/ForumListItem.java
index 3b8d4e98998c64fef1278de3641653a690268b56..281eb64b41fbffee6b382abfb97322134d10a2bf 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListItem.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListItem.java
@@ -8,7 +8,8 @@ import org.briarproject.api.forum.ForumPostHeader;
 class ForumListItem {
 
 	private final Forum forum;
-	private long postCount, unread, timestamp;
+	private int postCount, unread;
+	private long timestamp;
 
 	ForumListItem(Forum forum, GroupCount count) {
 		this.forum = forum;
@@ -31,7 +32,7 @@ class ForumListItem {
 		return postCount == 0;
 	}
 
-	long getPostCount() {
+	int getPostCount() {
 		return postCount;
 	}
 
@@ -39,7 +40,7 @@ class ForumListItem {
 		return timestamp;
 	}
 
-	long getUnreadCount() {
+	int getUnreadCount() {
 		return unread;
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
index 4bc3db43738275172b3e83ffacd9d9a00117914a..422a7d16d85af5d05181c16d88a0c3a6737bad2b 100644
--- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
@@ -9,7 +9,6 @@ import org.briarproject.R;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.android.view.BriarRecyclerView;
-import org.briarproject.api.clients.MessageTracker;
 import org.briarproject.api.clients.MessageTracker.GroupCount;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.db.DbException;
@@ -107,8 +106,8 @@ abstract class SharingStatusActivity extends BriarActivity {
 						LocalAuthor localAuthor = identityManager
 								.getLocalAuthor(c.getLocalAuthorId());
 						ContactListItem item =
-								new ContactListItem(c, localAuthor, false, null,
-										new GroupCount(0, 0, 0));
+								new ContactListItem(c, localAuthor, false,
+										groupId, new GroupCount(0, 0, 0));
 						contactItems.add(item);
 					}
 				} catch (DbException e) {
@@ -143,8 +142,8 @@ abstract class SharingStatusActivity extends BriarActivity {
 						LocalAuthor localAuthor = identityManager
 								.getLocalAuthor(c.getLocalAuthorId());
 						ContactListItem item =
-								new ContactListItem(c, localAuthor, false, null,
-										new GroupCount(0, 0, 0));
+								new ContactListItem(c, localAuthor, false,
+										groupId, new GroupCount(0, 0, 0));
 						contactItems.add(item);
 					}
 				} catch (DbException e) {
diff --git a/briar-android/src/org/briarproject/android/view/TextAvatarView.java b/briar-android/src/org/briarproject/android/view/TextAvatarView.java
index 0b4e3703eea7b90e49e3a0e9d78ddbeeff949654..8b06ecb4c1cd49ffc4acd83b72f20ff08123ebb8 100644
--- a/briar-android/src/org/briarproject/android/view/TextAvatarView.java
+++ b/briar-android/src/org/briarproject/android/view/TextAvatarView.java
@@ -24,7 +24,7 @@ public class TextAvatarView extends FrameLayout {
 	final private AppCompatTextView character;
 	final private CircleImageView background;
 	final private TextView badge;
-	private long unreadCount;
+	private int unreadCount;
 
 	public TextAvatarView(Context context, @Nullable AttributeSet attrs) {
 		super(context, attrs);
@@ -48,11 +48,7 @@ public class TextAvatarView extends FrameLayout {
 	}
 
 	public void setUnreadCount(int count) {
-		setUnreadCount((long) count);
-	}
-
-	public void setUnreadCount(long count) {
-		this.unreadCount = count;
+		unreadCount = count;
 		if (count > 0) {
 			badge.setBackgroundResource(R.drawable.bubble);
 			badge.setText(String.valueOf(count));
@@ -60,7 +56,6 @@ public class TextAvatarView extends FrameLayout {
 					R.color.briar_text_primary_inverse));
 			badge.setVisibility(VISIBLE);
 		} else {
-			badge.setText("");
 			badge.setVisibility(INVISIBLE);
 		}
 	}
@@ -72,11 +67,8 @@ public class TextAvatarView extends FrameLayout {
 			badge.setTextColor(ContextCompat
 					.getColor(getContext(), R.color.briar_primary));
 			badge.setVisibility(VISIBLE);
-		} else if (unreadCount > 0) {
-			setUnreadCount(unreadCount);
 		} else {
-			badge.setText("");
-			badge.setVisibility(INVISIBLE);
+			setUnreadCount(unreadCount);
 		}
 	}
 
diff --git a/briar-android/src/org/briarproject/android/view/TextInputView.java b/briar-android/src/org/briarproject/android/view/TextInputView.java
index e65c519ab9ddf4eb979d15f34b18799759a378b6..e005624d2a62b58832bfa745f0a40cd71cc622a6 100644
--- a/briar-android/src/org/briarproject/android/view/TextInputView.java
+++ b/briar-android/src/org/briarproject/android/view/TextInputView.java
@@ -9,18 +9,13 @@ import android.support.annotation.CallSuper;
 import android.support.annotation.Nullable;
 import android.support.annotation.StringRes;
 import android.support.annotation.UiThread;
-import android.support.v7.widget.AppCompatImageButton;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.ImageButton;
-import android.widget.LinearLayout;
 
 import org.briarproject.R;
 import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
@@ -32,7 +27,6 @@ import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
 import java.util.logging.Logger;
 
 import static android.content.Context.INPUT_METHOD_SERVICE;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 @UiThread
 public class TextInputView extends KeyboardAwareLinearLayout
diff --git a/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java b/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java
index 523aeed2605f42e52f9c9154e6324a843116a70e..3798ea75e29b2282cfe236ea40db1c9d9b5229ad 100644
--- a/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java
+++ b/briar-api/src/org/briarproject/api/blogs/BlogInvitationResponse.java
@@ -5,10 +5,11 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sharing.InvitationResponse;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 public class BlogInvitationResponse extends InvitationResponse {
 
-	public BlogInvitationResponse(MessageId id, SessionId sessionId,
+	public BlogInvitationResponse(@NotNull MessageId id, SessionId sessionId,
 			GroupId groupId, ContactId contactId, boolean accept, long time,
 			boolean local, boolean sent, boolean seen, boolean read) {
 
diff --git a/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java b/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java
index fa8b6bc8609b7464eacd31e9204a8449a2f6c182..b77ac908d4fa7a98a850f17ef5a67bcae7cbbda7 100644
--- a/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java
+++ b/briar-api/src/org/briarproject/api/clients/BaseMessageHeader.java
@@ -2,6 +2,7 @@ package org.briarproject.api.clients;
 
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class BaseMessageHeader {
 
@@ -10,8 +11,9 @@ public abstract class BaseMessageHeader {
 	private final long timestamp;
 	private final boolean local, read, sent, seen;
 
-	public BaseMessageHeader(MessageId id, GroupId groupId, long timestamp,
-			boolean local, boolean read, boolean sent, boolean seen) {
+	public BaseMessageHeader(@NotNull MessageId id, @NotNull GroupId groupId,
+			long timestamp, boolean local, boolean read, boolean sent,
+			boolean seen) {
 
 		this.id = id;
 		this.groupId = groupId;
@@ -22,10 +24,12 @@ public abstract class BaseMessageHeader {
 		this.seen = seen;
 	}
 
+	@NotNull
 	public MessageId getId() {
 		return id;
 	}
 
+	@NotNull
 	public GroupId getGroupId() {
 		return groupId;
 	}
diff --git a/briar-api/src/org/briarproject/api/clients/MessageTracker.java b/briar-api/src/org/briarproject/api/clients/MessageTracker.java
index 8226a3058cfb697cd54dbf902f6a50c4f0f7c336..a73c87183fa949d61cd7858c2a6a443e99236f46 100644
--- a/briar-api/src/org/briarproject/api/clients/MessageTracker.java
+++ b/briar-api/src/org/briarproject/api/clients/MessageTracker.java
@@ -1,9 +1,7 @@
 package org.briarproject.api.clients;
 
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.db.Transaction;
 import org.briarproject.api.sync.GroupId;
-import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 
 public interface MessageTracker {
@@ -20,19 +18,20 @@ public interface MessageTracker {
 	void setReadFlag(GroupId g, MessageId m, boolean read) throws DbException;
 
 	class GroupCount {
-		private final long msgCount, unreadCount, latestMsgTime;
+		private final int msgCount, unreadCount;
+		private final long latestMsgTime;
 
-		public GroupCount(long msgCount, long unreadCount, long latestMsgTime) {
+		public GroupCount(int msgCount, int unreadCount, long latestMsgTime) {
 			this.msgCount = msgCount;
 			this.unreadCount = unreadCount;
 			this.latestMsgTime = latestMsgTime;
 		}
 
-		public long getMsgCount() {
+		public int getMsgCount() {
 			return msgCount;
 		}
 
-		public long getUnreadCount() {
+		public int getUnreadCount() {
 			return unreadCount;
 		}
 
diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java
index b92a4666782755ba69989da992c7eead022c4e77..26a2ae097d81b4a7068661990191ca1db4aceb0e 100644
--- a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java
+++ b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java
@@ -4,7 +4,8 @@ import org.briarproject.api.blogs.Blog;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sharing.InvitationRequest;
 
-public class BlogInvitationReceivedEvent extends InvitationReceivedEvent {
+public class BlogInvitationReceivedEvent extends
+		InvitationRequestReceivedEvent {
 
 	private final Blog blog;
 
diff --git a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java
index bbfab9cfe07872a30d42c70b9821d779120bde41..3077f91605de30b7a6d8bf105f7f058e754f995a 100644
--- a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java
+++ b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java
@@ -4,7 +4,8 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.forum.Forum;
 import org.briarproject.api.forum.ForumInvitationRequest;
 
-public class ForumInvitationReceivedEvent extends InvitationReceivedEvent {
+public class ForumInvitationReceivedEvent extends
+		InvitationRequestReceivedEvent {
 
 	private final Forum forum;
 
diff --git a/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java
similarity index 72%
rename from briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java
rename to briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java
index a72478d660f2dc946fed0d9fd195bbdc1145d7e7..184a88f5387a5e8fae71d4771c7d58e1893f1e50 100644
--- a/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java
+++ b/briar-api/src/org/briarproject/api/event/InvitationRequestReceivedEvent.java
@@ -3,12 +3,13 @@ package org.briarproject.api.event;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sharing.InvitationRequest;
 
-public abstract class InvitationReceivedEvent extends Event {
+public abstract class InvitationRequestReceivedEvent extends Event {
 
 	private final ContactId contactId;
 	private final InvitationRequest request;
 
-	InvitationReceivedEvent(ContactId contactId, InvitationRequest request) {
+	InvitationRequestReceivedEvent(ContactId contactId,
+			InvitationRequest request) {
 		this.contactId = contactId;
 		this.request = request;
 	}
diff --git a/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java b/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java
index 059c7d385bb185cd3248a7a2b02f7e29eeb4e920..d9c49d154546febfe1041f61535a08f66e8385c7 100644
--- a/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java
+++ b/briar-api/src/org/briarproject/api/forum/ForumInvitationResponse.java
@@ -5,11 +5,12 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sharing.InvitationResponse;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class ForumInvitationResponse extends InvitationResponse {
 
-	public ForumInvitationResponse(MessageId id, SessionId sessionId,
+	public ForumInvitationResponse(@NotNull MessageId id, SessionId sessionId,
 			GroupId groupId, ContactId contactId, boolean accept, long time, boolean local,
 			boolean sent, boolean seen, boolean read) {
 
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
index e218e1d095ad263e1162f6921fdc2942f74c70ca..e2d968bfa119feb813900876df126b0a84b8f85c 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionMessage.java
@@ -1,22 +1,23 @@
 package org.briarproject.api.introduction;
 
-import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.clients.BaseMessageHeader;
+import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
-import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCEE;
 import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRODUCER;
 
- public class IntroductionMessage extends BaseMessageHeader {
+public class IntroductionMessage extends BaseMessageHeader {
 
 	private final SessionId sessionId;
 	private final MessageId messageId;
 	private final int role;
 
-	public IntroductionMessage(SessionId sessionId, MessageId messageId,
-			GroupId groupId, int role, long time, boolean local, boolean sent,
-			boolean seen, boolean read) {
+	public IntroductionMessage(@NotNull SessionId sessionId,
+			@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
+			long time, boolean local, boolean sent, boolean seen,
+			boolean read) {
 
 		super(messageId, groupId, time, local, read, sent, seen);
 		this.sessionId = sessionId;
@@ -24,10 +25,12 @@ import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRO
 		this.role = role;
 	}
 
+	@NotNull
 	public SessionId getSessionId() {
 		return sessionId;
 	}
 
+	@NotNull
 	public MessageId getMessageId() {
 		return messageId;
 	}
@@ -36,9 +39,4 @@ import static org.briarproject.api.introduction.IntroductionConstants.ROLE_INTRO
 		return role == ROLE_INTRODUCER;
 	}
 
-	public boolean isIntroducee() {
-		return role == ROLE_INTRODUCEE;
-	}
-
 }
-
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
index 1942b7f3f7e227fb69fc76ef2d9c81611a605868..4a2910dc238092a2240e513acd16944af07734e1 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionRequest.java
@@ -4,16 +4,19 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class IntroductionRequest extends IntroductionResponse {
 
 	private final String message;
 	private final boolean answered, exists, introducesOtherIdentity;
 
-	public IntroductionRequest(SessionId sessionId, MessageId messageId,
-			GroupId groupId, int role, long time, boolean local, boolean sent,
-			boolean seen, boolean read, AuthorId authorId, String name,
-			boolean accepted, String message, boolean answered, boolean exists,
+	public IntroductionRequest(@NotNull SessionId sessionId,
+			@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
+			long time, boolean local, boolean sent, boolean seen, boolean read,
+			AuthorId authorId, String name, boolean accepted,
+			@Nullable String message, boolean answered, boolean exists,
 			boolean introducesOtherIdentity) {
 
 		super(sessionId, messageId, groupId, role, time, local, sent, seen,
@@ -25,6 +28,7 @@ public class IntroductionRequest extends IntroductionResponse {
 		this.introducesOtherIdentity = introducesOtherIdentity;
 	}
 
+	@Nullable
 	public String getMessage() {
 		return message;
 	}
diff --git a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
index c2423ce2e6b7d4ff4a62bfd7525284d48659a7d1..bcb2ce3349e1fd7b02b506d78651156e20d8d753 100644
--- a/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
+++ b/briar-api/src/org/briarproject/api/introduction/IntroductionResponse.java
@@ -4,6 +4,7 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.identity.AuthorId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 public class IntroductionResponse extends IntroductionMessage {
 
@@ -11,10 +12,10 @@ public class IntroductionResponse extends IntroductionMessage {
 	private final String name;
 	private final boolean accepted;
 
-	public IntroductionResponse(SessionId sessionId, MessageId messageId,
-			GroupId groupId, int role, long time, boolean local, boolean sent,
-			boolean seen, boolean read, AuthorId remoteAuthorId, String name,
-			boolean accepted) {
+	public IntroductionResponse(@NotNull SessionId sessionId,
+			@NotNull MessageId messageId, @NotNull GroupId groupId, int role,
+			long time, boolean local, boolean sent, boolean seen, boolean read,
+			AuthorId remoteAuthorId, String name, boolean accepted) {
 
 		super(sessionId, messageId, groupId, role, time, local, sent, seen,
 				read);
diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java
index d67d479cd8da421f8d82370aba062662e82b1565..4e6e4858f0a370f530b50f896e17ec3cafbaf8cb 100644
--- a/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java
+++ b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java
@@ -5,25 +5,29 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class InvitationMessage extends BaseMessageHeader {
 
 	private final SessionId sessionId;
 	private final ContactId contactId;
 
-	public InvitationMessage(MessageId id, SessionId sessionId, GroupId groupId,
-			ContactId contactId, long time, boolean local, boolean sent,
-			boolean seen, boolean read) {
+	public InvitationMessage(@NotNull MessageId id,
+			@NotNull SessionId sessionId, @NotNull GroupId groupId,
+			@NotNull ContactId contactId, long time, boolean local,
+			boolean sent, boolean seen, boolean read) {
 
 		super(id, groupId, time, local, read, sent, seen);
 		this.sessionId = sessionId;
 		this.contactId = contactId;
 	}
 
+	@NotNull
 	public SessionId getSessionId() {
 		return sessionId;
 	}
 
+	@NotNull
 	public ContactId getContactId() {
 		return contactId;
 	}
diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java b/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java
index 3ae15c424688d092a661f5881b1f21b1b40937ae..23ed952b96d43829fa72a5149cec284bc6526e8d 100644
--- a/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java
+++ b/briar-api/src/org/briarproject/api/sharing/InvitationRequest.java
@@ -4,6 +4,7 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public abstract class InvitationRequest extends InvitationMessage {
@@ -11,8 +12,9 @@ public abstract class InvitationRequest extends InvitationMessage {
 	private final String message;
 	private final boolean available;
 
-	public InvitationRequest(MessageId id, SessionId sessionId, GroupId groupId,
-			ContactId contactId, String message,
+	public InvitationRequest(@NotNull MessageId id,
+			@NotNull SessionId sessionId, @NotNull GroupId groupId,
+			@NotNull ContactId contactId, @Nullable String message,
 			boolean available, long time, boolean local, boolean sent,
 			boolean seen, boolean read) {
 
diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java b/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java
index 710dc396c1f4119c0df89f2c55a620bb3de87b01..0e2d24ee65f00e1ca5f76a1108138d5c0ed9d69c 100644
--- a/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java
+++ b/briar-api/src/org/briarproject/api/sharing/InvitationResponse.java
@@ -4,12 +4,13 @@ import org.briarproject.api.clients.SessionId;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 
 public abstract class InvitationResponse extends InvitationMessage {
 
 	private final boolean accept;
 
-	public InvitationResponse(MessageId id, SessionId sessionId,
+	public InvitationResponse(@NotNull MessageId id, SessionId sessionId,
 			GroupId groupId, ContactId contactId, boolean accept, long time,
 			boolean local, boolean sent, boolean seen, boolean read) {
 
diff --git a/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java b/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java
index 73d57f11be798c5136b2413404e4602f9340dbec..575a2433d4b36569c04ea39a6259b4193313bf1c 100644
--- a/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java
+++ b/briar-core/src/org/briarproject/clients/BdfIncomingMessageHook.java
@@ -81,8 +81,8 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
 	protected void trackMessage(Transaction txn, GroupId g, long time,
 			boolean read) throws DbException {
 		GroupCount c = getGroupCount(txn, g);
-		long msgCount = c.getMsgCount() + 1;
-		long unreadCount = c.getUnreadCount() + (read ? 0 : 1);
+		int msgCount = c.getMsgCount() + 1;
+		int unreadCount = c.getUnreadCount() + (read ? 0 : 1);
 		long latestTime =
 				time > c.getLatestMsgTime() ? time : c.getLatestMsgTime();
 		storeGroupCount(txn, g,
@@ -109,8 +109,8 @@ public abstract class BdfIncomingMessageHook implements IncomingMessageHook,
 		try {
 			BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
 			count = new GroupCount(
-					d.getLong(GROUP_KEY_MSG_COUNT, 0L),
-					d.getLong(GROUP_KEY_UNREAD_COUNT, 0L),
+					d.getLong(GROUP_KEY_MSG_COUNT, 0L).intValue(),
+					d.getLong(GROUP_KEY_UNREAD_COUNT, 0L).intValue(),
 					d.getLong(GROUP_KEY_LATEST_MSG, 0L)
 			);
 		} catch (FormatException e) {
diff --git a/briar-core/src/org/briarproject/clients/ConversationClient.java b/briar-core/src/org/briarproject/clients/ConversationClientImpl.java
similarity index 78%
rename from briar-core/src/org/briarproject/clients/ConversationClient.java
rename to briar-core/src/org/briarproject/clients/ConversationClientImpl.java
index ba906d084f6078021f7819332400a3ff780aadc5..39342b87e73bf12d0d6c27700461ce43d376a07c 100644
--- a/briar-core/src/org/briarproject/clients/ConversationClient.java
+++ b/briar-core/src/org/briarproject/clients/ConversationClientImpl.java
@@ -8,19 +8,18 @@ import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.messaging.ConversationManager;
+import org.briarproject.api.messaging.ConversationManager.ConversationClient;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.GroupId;
 
-public abstract class ConversationClient extends BdfIncomingMessageHook
-		implements ConversationManager.ConversationClient {
+public abstract class ConversationClientImpl extends BdfIncomingMessageHook
+		implements ConversationClient {
 
-	protected ConversationClient(DatabaseComponent db,
+	protected ConversationClientImpl(DatabaseComponent db,
 			ClientHelper clientHelper, MetadataParser metadataParser) {
 		super(db, clientHelper, metadataParser);
 	}
 
-	// TODO overwrite super methods to store GroupCount data in a single group
-
 	protected abstract Group getContactGroup(Contact contact);
 
 	@Override
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
index 31e671ca578bf5ac04f587e28e1087205c7d3e9b..e42ee1e0973156660b336258335e1a6ded233ba5 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionManagerImpl.java
@@ -29,7 +29,7 @@ import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.sync.MessageStatus;
-import org.briarproject.clients.ConversationClient;
+import org.briarproject.clients.ConversationClientImpl;
 import org.briarproject.util.StringUtils;
 
 import java.io.IOException;
@@ -76,7 +76,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE
 import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
 import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
 
-class IntroductionManagerImpl extends ConversationClient
+class IntroductionManagerImpl extends ConversationClientImpl
 		implements IntroductionManager, Client, AddContactHook,
 		RemoveContactHook {
 
diff --git a/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java b/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java
index 877e51f8d3540b8c5616fa7fee3e22b09a89cb0c..670af288ed00ad9f465066b7fae0ae98fdbb3cd3 100644
--- a/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/ConversationManagerImpl.java
@@ -32,7 +32,10 @@ class ConversationManagerImpl implements ConversationManager {
 
 	@Override
 	public void registerConversationClient(ConversationClient client) {
-		clients.add(client);
+		if (!clients.add(client)) {
+			throw new IllegalStateException(
+					"This client is already registered");
+		}
 	}
 
 	@Override
@@ -56,7 +59,8 @@ class ConversationManagerImpl implements ConversationManager {
 	public GroupCount getGroupCount(ContactId contactId)
 			throws DbException {
 
-		long msgCount = 0, unreadCount = 0, latestTime = 0;
+		int msgCount = 0, unreadCount = 0;
+		long latestTime = 0;
 		Transaction txn = db.startTransaction(true);
 		try {
 			for (ConversationClient client : clients) {
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index 3bb3c743a9c0b452f0ee01273d3fac4b301bd961..8a591849a24ca5643abf77ce54f12b2340cf8166 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -24,7 +24,7 @@ import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.sync.MessageStatus;
-import org.briarproject.clients.ConversationClient;
+import org.briarproject.clients.ConversationClientImpl;
 import org.briarproject.util.StringUtils;
 
 import java.util.ArrayList;
@@ -35,7 +35,7 @@ import javax.inject.Inject;
 
 import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
 
-class MessagingManagerImpl extends ConversationClient
+class MessagingManagerImpl extends ConversationClientImpl
 		implements MessagingManager, Client, AddContactHook, RemoveContactHook {
 
 	static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString(
diff --git a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java
index 2ffc4d8d1f6b82b01a9055253dbdb42de29fdf01..58ab24a0e9331a70c9dcec5fa08485c00fb6dd4b 100644
--- a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java
+++ b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java
@@ -5,6 +5,7 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
@@ -22,7 +23,7 @@ public class BlogInviteeSessionState extends InviteeSessionState {
 	public BlogInviteeSessionState(SessionId sessionId, MessageId storageId,
 			GroupId groupId, State state, ContactId contactId, GroupId blogId,
 			String blogTitle, String blogDesc, String blogAuthorName,
-			byte[] blogPublicKey, @Nullable MessageId invitationId) {
+			byte[] blogPublicKey, @NotNull MessageId invitationId) {
 		super(sessionId, storageId, groupId, state, contactId, blogId,
 				invitationId);
 
diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
index eb492cc610b6f9ba771cac28dc081921f830a93e..7786dedee9cf585ec67e42c40c375b3d2b01d4b4 100644
--- a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java
@@ -44,6 +44,7 @@ import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
 import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
 import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
 import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
+import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID;
 
 class BlogSharingManagerImpl extends
 		SharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent>
@@ -253,10 +254,7 @@ class BlogSharingManagerImpl extends
 			String blogDesc = d.getString(BLOG_DESC);
 			String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
 			byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
-			MessageId invitationId = null;
-			byte[] invitationIdBytes = d.getOptionalRaw(INVITATION_ID);
-			if (invitationIdBytes != null)
-				invitationId = new MessageId(invitationIdBytes);
+			MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID));
 			return new BlogInviteeSessionState(sessionId, storageId,
 					groupId, state, contactId, blogId, blogTitle, blogDesc,
 					blogAuthorName, blogPublicKey, invitationId);
@@ -286,7 +284,7 @@ class BlogSharingManagerImpl extends
 			String blogAuthorName = d.getString(BLOG_AUTHOR_NAME);
 			byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY);
 			MessageId responseId = null;
-			byte[] responseIdBytes = d.getOptionalRaw(INVITATION_ID);
+			byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID);
 			if (responseIdBytes != null)
 				responseId = new MessageId(responseIdBytes);
 			return new BlogSharerSessionState(sessionId, storageId,
@@ -336,8 +334,11 @@ class BlogSharingManagerImpl extends
 				BlogSharerSessionState localState, boolean accept, long time) {
 			String title = localState.getBlogTitle();
 			ContactId c = localState.getContactId();
+			MessageId responseId = localState.getResponseId();
+			if (responseId == null)
+				throw new IllegalStateException("No responseId");
 			BlogInvitationResponse response =
-					new BlogInvitationResponse(localState.getResponseId(),
+					new BlogInvitationResponse(responseId,
 							localState.getSessionId(), localState.getGroupId(),
 							localState.getContactId(), accept, time, false,
 							false, false, false);
diff --git a/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java
index 259b38b00b03682b277e9fda33e0ba7c0d9b1267..79c732e932702417cea9bfdf837b1b20739111c2 100644
--- a/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java
+++ b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java
@@ -5,7 +5,7 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
 
 import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
 import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
@@ -18,7 +18,7 @@ public class ForumInviteeSessionState extends InviteeSessionState {
 	public ForumInviteeSessionState(SessionId sessionId, MessageId storageId,
 			GroupId groupId, State state, ContactId contactId, GroupId forumId,
 			String forumName, byte[] forumSalt,
-			@Nullable MessageId invitationId) {
+			@NotNull MessageId invitationId) {
 		super(sessionId, storageId, groupId, state, contactId, forumId,
 				invitationId);
 
diff --git a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
index ab47bea6a29f49575c0de450d5679fcb974c9c0d..c78cda5bcc22b4bde0bf255f89cc7128791e08b3 100644
--- a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java
@@ -36,6 +36,7 @@ import javax.inject.Inject;
 import static org.briarproject.api.forum.ForumConstants.FORUM_NAME;
 import static org.briarproject.api.forum.ForumConstants.FORUM_SALT;
 import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
+import static org.briarproject.api.sharing.SharingConstants.RESPONSE_ID;
 
 class ForumSharingManagerImpl extends
 		SharingManagerImpl<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent>
@@ -204,10 +205,7 @@ class ForumSharingManagerImpl extends
 				GroupId forumId, BdfDictionary d) throws FormatException {
 			String forumName = d.getString(FORUM_NAME);
 			byte[] forumSalt = d.getRaw(FORUM_SALT);
-			MessageId invitationId = null;
-			byte[] invitationIdBytes = d.getOptionalRaw(INVITATION_ID);
-			if (invitationIdBytes != null)
-				invitationId = new MessageId(invitationIdBytes);
+			MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID));
 			return new ForumInviteeSessionState(sessionId, storageId,
 					groupId, state, contactId, forumId, forumName, forumSalt,
 					invitationId);
@@ -234,7 +232,7 @@ class ForumSharingManagerImpl extends
 			String forumName = d.getString(FORUM_NAME);
 			byte[] forumSalt = d.getRaw(FORUM_SALT);
 			MessageId responseId = null;
-			byte[] responseIdBytes = d.getOptionalRaw(INVITATION_ID);
+			byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID);
 			if (responseIdBytes != null)
 				responseId = new MessageId(responseIdBytes);
 			return new ForumSharerSessionState(sessionId, storageId,
@@ -282,8 +280,11 @@ class ForumSharingManagerImpl extends
 				ForumSharerSessionState localState, boolean accept, long time) {
 			String name = localState.getForumName();
 			ContactId c = localState.getContactId();
+			MessageId responseId = localState.getResponseId();
+			if (responseId == null)
+				throw new IllegalStateException("No responseId");
 			ForumInvitationResponse response = new ForumInvitationResponse(
-					localState.getResponseId(), localState.getSessionId(),
+					responseId, localState.getSessionId(),
 					localState.getGroupId(), localState.getContactId(), accept,
 					time, false, false, false, false);
 			return new ForumInvitationResponseReceivedEvent(name, c, response);
diff --git a/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java
index 7c1e324d0a53e15f919720b85072f65400e06e32..9172656e9f74e1f2bc37747d1a07ff4798f6d9e8 100644
--- a/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java
+++ b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java
@@ -1,8 +1,8 @@
 package org.briarproject.sharing;
 
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 
-public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> {
+public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> {
 
 	IR build(IS localState, long time, String msg);
 }
diff --git a/briar-core/src/org/briarproject/sharing/InviteeEngine.java b/briar-core/src/org/briarproject/sharing/InviteeEngine.java
index f8458331681b32c3797cfb70f40b50e53bb32820..96af6e3207da4eb44e35a4c2d61a3cc5e76ae00b 100644
--- a/briar-core/src/org/briarproject/sharing/InviteeEngine.java
+++ b/briar-core/src/org/briarproject/sharing/InviteeEngine.java
@@ -3,7 +3,7 @@ package org.briarproject.sharing;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.clients.ProtocolEngine;
 import org.briarproject.api.event.Event;
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.sharing.SharingMessage.Invitation;
 import org.briarproject.api.system.Clock;
 
@@ -25,7 +25,7 @@ import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREAB
 import static org.briarproject.api.sharing.SharingMessage.BaseMessage;
 import static org.briarproject.api.sharing.SharingMessage.SimpleMessage;
 
-class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceivedEvent>
+class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent>
 		implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> {
 
 	private static final Logger LOG =
diff --git a/briar-core/src/org/briarproject/sharing/InviteeSessionState.java b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java
index 295076fd41dfda373a8ac4a70d1d516cdfb528fa..1aa65b2320245ef655912328ef27a8c86769a9ad 100644
--- a/briar-core/src/org/briarproject/sharing/InviteeSessionState.java
+++ b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java
@@ -5,7 +5,7 @@ import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.data.BdfDictionary;
 import org.briarproject.api.sync.GroupId;
 import org.briarproject.api.sync.MessageId;
-import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.NotNull;
 
 import static org.briarproject.api.sharing.SharingConstants.INVITATION_ID;
 import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
@@ -23,11 +23,12 @@ import static org.briarproject.sharing.InviteeSessionState.Action.REMOTE_LEAVE;
 public abstract class InviteeSessionState extends SharingSessionState {
 
 	private State state;
+	@NotNull
 	private final MessageId invitationId;
 
 	public InviteeSessionState(SessionId sessionId, MessageId storageId,
 			GroupId groupId, State state, ContactId contactId,
-			GroupId shareableId, MessageId invitationId) {
+			GroupId shareableId, @NotNull MessageId invitationId) {
 
 		super(sessionId, storageId, groupId, contactId, shareableId);
 		this.state = state;
@@ -38,7 +39,7 @@ public abstract class InviteeSessionState extends SharingSessionState {
 		BdfDictionary d = super.toBdfDictionary();
 		d.put(STATE, getState().getValue());
 		d.put(IS_SHARER, false);
-		if (invitationId != null) d.put(INVITATION_ID, invitationId);
+		d.put(INVITATION_ID, invitationId);
 		return d;
 	}
 
@@ -50,7 +51,7 @@ public abstract class InviteeSessionState extends SharingSessionState {
 		return state;
 	}
 
-	@Nullable
+	@NotNull
 	public MessageId getInvitationId() {
 		return invitationId;
 	}
diff --git a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
index 2e12a46a7b889753e1caeb4900da6a26e96025b1..9def8487dc2b82b803b6baff9b0092062c13dc61 100644
--- a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java
@@ -22,7 +22,7 @@ import org.briarproject.api.db.Metadata;
 import org.briarproject.api.db.NoSuchMessageException;
 import org.briarproject.api.db.Transaction;
 import org.briarproject.api.event.Event;
-import org.briarproject.api.event.InvitationReceivedEvent;
+import org.briarproject.api.event.InvitationRequestReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.sharing.InvitationItem;
@@ -36,7 +36,7 @@ import org.briarproject.api.sync.Message;
 import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.sync.MessageStatus;
 import org.briarproject.api.system.Clock;
-import org.briarproject.clients.ConversationClient;
+import org.briarproject.clients.ConversationClientImpl;
 import org.briarproject.util.StringUtils;
 
 import java.io.IOException;
@@ -85,8 +85,8 @@ import static org.briarproject.api.sharing.SharingMessage.Invitation;
 import static org.briarproject.clients.BdfConstants.MSG_KEY_READ;
 import static org.briarproject.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE;
 
-abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent>
-		extends ConversationClient
+abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationRequestReceivedEvent, IRR extends InvitationResponseReceivedEvent>
+		extends ConversationClientImpl
 		implements SharingManager<S>, Client, AddContactHook,
 		RemoveContactHook {
 
@@ -212,7 +212,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 				if (stateExists) throw new FormatException();
 
 				// check if shareable can be shared
-				@SuppressWarnings("unchecked")
 				I invitation = (I) msg;
 				S f = getSFactory().parse(invitation);
 				ContactId contactId = getContactId(txn, m.getGroupId());
@@ -249,7 +248,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			SharingSessionState s = getSessionState(txn, sessionId, true);
 			if (s instanceof SharerSessionState) {
 				// we are a sharer and the invitee wants to leave or abort
-				@SuppressWarnings("unchecked")
 				SS state = (SS) s;
 				SharerEngine<I, SS, IRR> engine =
 						new SharerEngine<I, SS, IRR>(getIFactory(),
@@ -258,7 +256,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 						engine.onMessageReceived(state, msg));
 			} else {
 				// we are an invitee and the sharer wants to leave or abort
-				@SuppressWarnings("unchecked")
 				IS state = (IS) s;
 				InviteeEngine<IS, IR> engine =
 						new InviteeEngine<IS, IR>(getIRFactory(), clock);
@@ -298,6 +295,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			processSharerStateUpdate(txn, null, update);
 
 			// track message
+			// TODO handle this properly without engine hacks (#376)
 			long time = update.toSend.get(0).getTime();
 			trackMessage(txn, localState.getGroupId(), time, true);
 
@@ -334,6 +332,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			processInviteeStateUpdate(txn, null, update);
 
 			// track message
+			// TODO handle this properly without engine hacks (#376)
 			long time = update.toSend.get(0).getTime();
 			trackMessage(txn, localState.getGroupId(), time, true);
 
@@ -475,7 +474,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			BdfDictionary d = m.getValue();
 			try {
 				I msg = getIFactory().build(group.getId(), d);
-				@SuppressWarnings("unchecked")
 				IS iss = (IS) getSessionState(txn, msg.getSessionId(), true);
 				// get and add the shareable if the invitation is unanswered
 				if (iss.getState().equals(AWAIT_LOCAL_RESPONSE)) {
@@ -733,7 +731,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 
 		if (!d.getBoolean(IS_SHARER)) throw new FormatException();
 
-		//noinspection unchecked
 		return (SS) SharingSessionState
 				.fromBdfDictionary(getISFactory(), getSSFactory(), d);
 	}
@@ -768,7 +765,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			}
 			throw new DbException();
 		}
-		//noinspection unchecked
 		return (IS) SharingSessionState
 				.fromBdfDictionary(getISFactory(), getSSFactory(),
 						map.values().iterator().next());
@@ -954,7 +950,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 			SharerEngine<I, SS, IRR> engine =
 					new SharerEngine<I, SS, IRR>(getIFactory(),
 							getIRRFactory(), clock);
-			//noinspection unchecked
 			processSharerStateUpdate(txn, null,
 					engine.onLocalAction((SS) state, action));
 		} else {
@@ -962,7 +957,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
 					InviteeSessionState.Action.LOCAL_LEAVE;
 			InviteeEngine<IS, IR> engine =
 					new InviteeEngine<IS, IR>(getIRFactory(), clock);
-			//noinspection unchecked
 			processInviteeStateUpdate(txn, null,
 					engine.onLocalAction((IS) state, action));
 		}
diff --git a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
index c02c29192bc06081234404467a633999c31ca4e2..19903224e5cb15ea301b3eef81c381f3f4497062 100644
--- a/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
+++ b/briar-tests/src/org/briarproject/introduction/IntroductionManagerImplTest.java
@@ -96,13 +96,13 @@ public class IntroductionManagerImplTest extends BriarTestCase {
 				TestUtils.getRandomBytes(MESSAGE_HEADER_LENGTH + 1)
 		);
 		metadataBefore = BdfDictionary.of(
-				new BdfEntry(GROUP_KEY_MSG_COUNT, 41L),
-				new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L),
-				new BdfEntry(GROUP_KEY_LATEST_MSG, 0L)
+				new BdfEntry(GROUP_KEY_MSG_COUNT, 41),
+				new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0),
+				new BdfEntry(GROUP_KEY_LATEST_MSG, 0)
 		);
 		metadataAfter = BdfDictionary.of(
-				new BdfEntry(GROUP_KEY_MSG_COUNT, 42L),
-				new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0L),
+				new BdfEntry(GROUP_KEY_MSG_COUNT, 42),
+				new BdfEntry(GROUP_KEY_UNREAD_COUNT, 0),
 				new BdfEntry(GROUP_KEY_LATEST_MSG, time)
 		);
 
@@ -273,8 +273,8 @@ public class IntroductionManagerImplTest extends BriarTestCase {
 		final BdfDictionary state = new BdfDictionary();
 		txn = new Transaction(null, false);
 
-		metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1L);
-		metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2L);
+		metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 1);
+		metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 2);
 
 		context.checking(new Expectations() {{
 			oneOf(introduceeManager)
@@ -314,8 +314,8 @@ public class IntroductionManagerImplTest extends BriarTestCase {
 
 		txn = new Transaction(null, false);
 
-		metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41L);
-		metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42L);
+		metadataBefore.put(GROUP_KEY_UNREAD_COUNT, 41);
+		metadataAfter.put(GROUP_KEY_UNREAD_COUNT, 42);
 
 		context.checking(new Expectations() {{
 			oneOf(clientHelper).getMessageMetadataAsDictionary(txn, sessionId);