From a4cf91fba540187e2f361724c7f2b671ec319986 Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Wed, 3 Aug 2016 13:00:24 -0300
Subject: [PATCH] Use Inheritence for shared Forum and Blog Sharing Code

---
 briar-android/AndroidManifest.xml             |  40 ++-
 ...ity_share_forum.xml => activity_share.xml} |   0
 ...status.xml => activity_sharing_status.xml} |   0
 ...n_out.xml => list_item_msg_notice_out.xml} |   0
 .../list_item_shareable_invitation_in.xml     |   6 +-
 briar-android/res/menu/blogs_blog_actions.xml |   2 +-
 briar-android/res/menu/forum_actions.xml      |   2 +-
 briar-android/res/values-pt-rBR/strings.xml   |   2 +-
 briar-android/res/values/strings.xml          |   7 +-
 .../android/ActivityComponent.java            |  29 +-
 .../android/blogs/BlogFragment.java           |  14 +-
 .../android/contact/ContactListFragment.java  |  16 +-
 .../android/contact/ConversationActivity.java |  11 +-
 .../android/contact/ConversationAdapter.java  |  21 +-
 .../android/forum/ForumActivity.java          |  12 +-
 .../android/forum/ForumListFragment.java      |   7 +-
 .../sharing/ContactSelectorFragment.java      |  30 +--
 .../android/sharing/InvitationsActivity.java  | 249 ++----------------
 .../sharing/InvitationsBlogActivity.java      | 127 +++++++++
 .../sharing/InvitationsForumActivity.java     | 127 +++++++++
 .../android/sharing/ShareActivity.java        |  30 +--
 .../android/sharing/ShareBlogActivity.java    |  35 +++
 .../sharing/ShareBlogMessageFragment.java     |  81 ++++++
 .../android/sharing/ShareForumActivity.java   |  34 +++
 .../sharing/ShareForumMessageFragment.java    |  79 ++++++
 .../android/sharing/ShareMessageFragment.java | 104 ++------
 .../sharing/SharingStatusActivity.java        |  64 ++---
 .../sharing/SharingStatusBlogActivity.java    |  37 +++
 .../sharing/SharingStatusForumActivity.java   |  37 +++
 29 files changed, 746 insertions(+), 457 deletions(-)
 rename briar-android/res/layout/{activity_share_forum.xml => activity_share.xml} (100%)
 rename briar-android/res/layout/{activity_forum_sharing_status.xml => activity_sharing_status.xml} (100%)
 rename briar-android/res/layout/{list_item_introduction_out.xml => list_item_msg_notice_out.xml} (100%)
 create mode 100644 briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/SharingStatusBlogActivity.java
 create mode 100644 briar-android/src/org/briarproject/android/sharing/SharingStatusForumActivity.java

diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 7b2c1ceacf..df2a916d3d 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -102,7 +102,7 @@
 		</activity>
 
 		<activity
-			android:name=".android.sharing.InvitationsActivity"
+			android:name=".android.sharing.InvitationsForumActivity"
 			android:label="@string/forum_invitations_title"
 			android:parentActivityName=".android.NavDrawerActivity">
 			<meta-data
@@ -111,6 +111,16 @@
 				/>
 		</activity>
 
+		<activity
+			android:name=".android.sharing.InvitationsBlogActivity"
+			android:label="@string/blogs_sharing_invitations_title"
+			android:parentActivityName=".android.contact.ConversationActivity">
+			<meta-data
+				android:name="android.support.PARENT_ACTIVITY"
+				android:value=".android.contact.ConversationActivity"
+				/>
+		</activity>
+
 		<activity
 			android:name=".android.forum.CreateForumActivity"
 			android:label="@string/create_forum_title"
@@ -133,8 +143,8 @@
 		</activity>
 
 		<activity
-			android:name=".android.sharing.ShareActivity"
-			android:label="@string/forums_share_toolbar_header"
+			android:name=".android.sharing.ShareForumActivity"
+			android:label="@string/activity_share_toolbar_header"
 			android:parentActivityName=".android.forum.ForumActivity">
 			<meta-data
 				android:name="android.support.PARENT_ACTIVITY"
@@ -143,8 +153,18 @@
 		</activity>
 
 		<activity
-			android:name=".android.sharing.SharingStatusActivity"
-			android:label="@string/forum_sharing_status"
+			android:name=".android.sharing.ShareBlogActivity"
+			android:label="@string/activity_share_toolbar_header"
+			android:parentActivityName=".android.blogs.BlogActivity">
+			<meta-data
+				android:name="android.support.PARENT_ACTIVITY"
+				android:value=".android.blogs.BlogActivity"
+				/>
+		</activity>
+
+		<activity
+			android:name=".android.sharing.SharingStatusForumActivity"
+			android:label="@string/sharing_status"
 			android:parentActivityName=".android.forum.ForumActivity">
 			<meta-data
 				android:name="android.support.PARENT_ACTIVITY"
@@ -152,6 +172,16 @@
 				/>
 		</activity>
 
+		<activity
+			android:name=".android.sharing.SharingStatusBlogActivity"
+			android:label="@string/sharing_status"
+			android:parentActivityName=".android.blogs.BlogActivity">
+			<meta-data
+				android:name="android.support.PARENT_ACTIVITY"
+				android:value=".android.blogs.BlogActivity"
+				/>
+		</activity>
+
 		<activity
 			android:name=".android.blogs.CreateBlogActivity"
 			android:label="@string/blogs_my_blogs_label"
diff --git a/briar-android/res/layout/activity_share_forum.xml b/briar-android/res/layout/activity_share.xml
similarity index 100%
rename from briar-android/res/layout/activity_share_forum.xml
rename to briar-android/res/layout/activity_share.xml
diff --git a/briar-android/res/layout/activity_forum_sharing_status.xml b/briar-android/res/layout/activity_sharing_status.xml
similarity index 100%
rename from briar-android/res/layout/activity_forum_sharing_status.xml
rename to briar-android/res/layout/activity_sharing_status.xml
diff --git a/briar-android/res/layout/list_item_introduction_out.xml b/briar-android/res/layout/list_item_msg_notice_out.xml
similarity index 100%
rename from briar-android/res/layout/list_item_introduction_out.xml
rename to briar-android/res/layout/list_item_msg_notice_out.xml
diff --git a/briar-android/res/layout/list_item_shareable_invitation_in.xml b/briar-android/res/layout/list_item_shareable_invitation_in.xml
index 33f95059ba..2903e4646b 100644
--- a/briar-android/res/layout/list_item_shareable_invitation_in.xml
+++ b/briar-android/res/layout/list_item_shareable_invitation_in.xml
@@ -37,13 +37,13 @@
 			android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
 			android:layout_alignEnd="@+id/introductionText"
 			android:layout_alignRight="@+id/introductionText"
-			android:layout_below="@+id/showForumsButton"
+			android:layout_below="@+id/showInvitationsButton"
 			android:textColor="@color/private_message_date"
 			android:textSize="@dimen/text_size_tiny"
 			tools:text="Dec 24, 13:37"/>
 
 		<Button
-			android:id="@+id/showForumsButton"
+			android:id="@+id/showInvitationsButton"
 			style="@style/BriarButtonFlat.Positive"
 			android:layout_width="wrap_content"
 			android:layout_height="wrap_content"
@@ -51,7 +51,7 @@
 			android:layout_alignEnd="@+id/introductionText"
 			android:layout_alignRight="@+id/introductionText"
 			android:layout_below="@+id/introductionText"
-			android:text="@string/forum_show_invitations"/>
+			tools:text="@string/forum_show_invitations"/>
 
 	</RelativeLayout>
 
diff --git a/briar-android/res/menu/blogs_blog_actions.xml b/briar-android/res/menu/blogs_blog_actions.xml
index ef84cfb201..e8f680a7c3 100644
--- a/briar-android/res/menu/blogs_blog_actions.xml
+++ b/briar-android/res/menu/blogs_blog_actions.xml
@@ -11,7 +11,7 @@
 
 	<item
 		android:id="@+id/action_blog_sharing_status"
-		android:title="@string/forum_sharing_status"
+		android:title="@string/sharing_status"
 		app:showAsAction="never"/>
 
 </menu>
\ No newline at end of file
diff --git a/briar-android/res/menu/forum_actions.xml b/briar-android/res/menu/forum_actions.xml
index 599529b50b..2a262cbfa3 100644
--- a/briar-android/res/menu/forum_actions.xml
+++ b/briar-android/res/menu/forum_actions.xml
@@ -17,7 +17,7 @@
 
 	<item
 		android:id="@+id/action_forum_sharing_status"
-		android:title="@string/forum_sharing_status"
+		android:title="@string/sharing_status"
 		app:showAsAction="never"/>
 
 	<item
diff --git a/briar-android/res/values-pt-rBR/strings.xml b/briar-android/res/values-pt-rBR/strings.xml
index d5332cc645..52ec3c9026 100644
--- a/briar-android/res/values-pt-rBR/strings.xml
+++ b/briar-android/res/values-pt-rBR/strings.xml
@@ -79,7 +79,7 @@
   <string name="show_forums">Mostrar</string>
   <string name="forum_leave">Sair do fórum</string>
   <string name="forum_left_toast">Saiu do fórum</string>
-  <string name="forum_sharing_status">Status de compartilhamento</string>
+  <string name="sharing_status">Status de compartilhamento</string>
   <string name="no_posts">Sem Posts</string>
   <plurals name="unread_posts">
     <item quantity="one">%d post não lido</item>
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 54c7316a6b..d6c5807fc4 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -53,6 +53,7 @@
 	<string name="now">now</string>
 	<string name="contact_list_title">Contacts</string>
 	<string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string>
+	<string name="no_contacts_selector">It seems that you are new here and have no contacts yet.\n\nPlease come back here after you added your first contact.</string>
 	<string name="add_contact_title">Add a Contact</string>
 	<string name="your_nickname">Choose the identity you want to use:</string>
 	<string name="face_to_face">You must be face-to-face with the person you want to add as a contact. This will prevent anyone from impersonating you or reading your messages in future.</string>
@@ -95,7 +96,7 @@
 	<string name="show_forums">Show</string>
 	<string name="forum_leave">Leave Forum</string>
 	<string name="forum_left_toast">Left Forum</string>
-	<string name="forum_sharing_status">Sharing Status</string>
+	<string name="sharing_status">Sharing Status</string>
 	<string name="no_posts">No posts</string>
 	<plurals name="unread_posts">
 		<item quantity="one">%d unread post</item>
@@ -266,7 +267,7 @@
 	<string name="settings_toolbar_header">Settings</string>
 	<string name="contacts_toolbar_header">Contacts</string>
 	<string name="forums_toolbar_header">Forums</string>
-	<string name="forums_share_toolbar_header">Choose Contacts</string>
+	<string name="activity_share_toolbar_header">Choose Contacts</string>
 	<!-- Progress titles -->
 	<string name="progress_title_logout">Signing out of Briar..</string>
 	<string name="progress_title_please_wait">Please wait..</string>
@@ -317,7 +318,7 @@
 	<string name="blogs_sharing_invitation_sent">You have shared the personal blog of %1$s with %2$s.</string>
 	<string name="blogs_sharing_show_invitations">Show Blog Invitations</string>
 	<string name="blogs_sharing_invitations_title">Blog Invitations</string>
-	<string name="blogs_sharing_exists">You are subscribed to this blog already.\nWarning: Accepting again might reveal that %s is your contact.</string>
+	<string name="blogs_sharing_exists">You are subscribed to this blog already. Accepting again can lead to faster blog post delivery.</string>
 	<string name="blogs_sharing_joined_toast">Subscribed to Blog</string>
 	<string name="blogs_sharing_declined_toast">Blog Invitation Declined</string>
 
diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java
index 81ef8bd57e..74fcd472ce 100644
--- a/briar-android/src/org/briarproject/android/ActivityComponent.java
+++ b/briar-android/src/org/briarproject/android/ActivityComponent.java
@@ -15,14 +15,9 @@ import org.briarproject.android.blogs.RssFeedManageActivity;
 import org.briarproject.android.blogs.WriteBlogPostActivity;
 import org.briarproject.android.contact.ContactListFragment;
 import org.briarproject.android.contact.ConversationActivity;
-import org.briarproject.android.sharing.InvitationsActivity;
-import org.briarproject.android.sharing.ContactSelectorFragment;
 import org.briarproject.android.forum.CreateForumActivity;
 import org.briarproject.android.forum.ForumActivity;
 import org.briarproject.android.forum.ForumListFragment;
-import org.briarproject.android.sharing.SharingStatusActivity;
-import org.briarproject.android.sharing.ShareActivity;
-import org.briarproject.android.sharing.ShareMessageFragment;
 import org.briarproject.android.identity.CreateIdentityActivity;
 import org.briarproject.android.introduction.ContactChooserFragment;
 import org.briarproject.android.introduction.IntroductionActivity;
@@ -33,6 +28,15 @@ import org.briarproject.android.keyagreement.KeyAgreementActivity;
 import org.briarproject.android.keyagreement.ShowQrCodeFragment;
 import org.briarproject.android.panic.PanicPreferencesActivity;
 import org.briarproject.android.panic.PanicResponderActivity;
+import org.briarproject.android.sharing.ContactSelectorFragment;
+import org.briarproject.android.sharing.InvitationsBlogActivity;
+import org.briarproject.android.sharing.InvitationsForumActivity;
+import org.briarproject.android.sharing.ShareBlogActivity;
+import org.briarproject.android.sharing.ShareBlogMessageFragment;
+import org.briarproject.android.sharing.ShareForumActivity;
+import org.briarproject.android.sharing.ShareForumMessageFragment;
+import org.briarproject.android.sharing.SharingStatusBlogActivity;
+import org.briarproject.android.sharing.SharingStatusForumActivity;
 
 import dagger.Component;
 
@@ -63,13 +67,19 @@ public interface ActivityComponent {
 
 	void inject(CreateIdentityActivity activity);
 
-	void inject(InvitationsActivity activity);
+	void inject(InvitationsForumActivity activity);
+
+	void inject(InvitationsBlogActivity activity);
 
 	void inject(CreateForumActivity activity);
 
-	void inject(ShareActivity activity);
+	void inject(ShareForumActivity activity);
+
+	void inject(ShareBlogActivity activity);
+
+	void inject(SharingStatusForumActivity activity);
 
-	void inject(SharingStatusActivity activity);
+	void inject(SharingStatusBlogActivity activity);
 
 	void inject(ForumActivity activity);
 
@@ -104,7 +114,8 @@ public interface ActivityComponent {
 	void inject(ShowQrCodeFragment fragment);
 	void inject(ContactChooserFragment fragment);
 	void inject(ContactSelectorFragment fragment);
-	void inject(ShareMessageFragment fragment);
+	void inject(ShareForumMessageFragment fragment);
+	void inject(ShareBlogMessageFragment fragment);
 	void inject(IntroductionMessageFragment fragment);
 
 }
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
index e588777081..9b9cf4f090 100644
--- a/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/BlogFragment.java
@@ -23,8 +23,8 @@ import org.briarproject.android.blogs.BlogController.BlogPostListener;
 import org.briarproject.android.blogs.BlogPostAdapter.OnBlogPostClickListener;
 import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.android.fragment.BaseFragment;
-import org.briarproject.android.sharing.ShareActivity;
-import org.briarproject.android.sharing.SharingStatusActivity;
+import org.briarproject.android.sharing.ShareBlogActivity;
+import org.briarproject.android.sharing.SharingStatusBlogActivity;
 import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.api.sync.GroupId;
 
@@ -44,8 +44,6 @@ import static org.briarproject.android.blogs.BlogActivity.IS_MY_BLOG;
 import static org.briarproject.android.blogs.BlogActivity.IS_NEW_BLOG;
 import static org.briarproject.android.blogs.BlogActivity.REQUEST_SHARE;
 import static org.briarproject.android.blogs.BlogActivity.REQUEST_WRITE_POST;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
 public class BlogFragment extends BaseFragment implements BlogPostListener {
 
@@ -169,18 +167,16 @@ public class BlogFragment extends BaseFragment implements BlogPostListener {
 						REQUEST_WRITE_POST, options.toBundle());
 				return true;
 			case R.id.action_blog_share:
-				Intent i2 = new Intent(getActivity(), ShareActivity.class);
+				Intent i2 = new Intent(getActivity(), ShareBlogActivity.class);
 				i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i2.putExtra(GROUP_ID, groupId.getBytes());
-				i2.putExtra(SHAREABLE, BLOG);
 				startActivityForResult(i2, REQUEST_SHARE, options.toBundle());
 				return true;
 			case R.id.action_blog_sharing_status:
-				Intent i3 =
-						new Intent(getActivity(), SharingStatusActivity.class);
+				Intent i3 = new Intent(getActivity(),
+						SharingStatusBlogActivity.class);
 				i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i3.putExtra(GROUP_ID, groupId.getBytes());
-				i3.putExtra(SHAREABLE, BLOG);
 				startActivity(i3, options.toBundle());
 				return true;
 			default:
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index c9df74031e..2f7dd90681 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -34,15 +34,11 @@ import org.briarproject.api.event.ContactStatusChangedEvent;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
-import org.briarproject.api.event.ForumInvitationReceivedEvent;
-import org.briarproject.api.event.ForumInvitationResponseReceivedEvent;
 import org.briarproject.api.event.IntroductionRequestReceivedEvent;
 import org.briarproject.api.event.IntroductionResponseReceivedEvent;
 import org.briarproject.api.event.InvitationReceivedEvent;
 import org.briarproject.api.event.InvitationResponseReceivedEvent;
 import org.briarproject.api.event.PrivateMessageReceivedEvent;
-import org.briarproject.api.forum.ForumInvitationRequest;
-import org.briarproject.api.forum.ForumInvitationResponse;
 import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
@@ -409,15 +405,19 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 			LOG.info("Loading introduction messages took " + duration + " ms");
 
 		now = System.currentTimeMillis();
-		Collection<InvitationMessage> invitations =
+		Collection<InvitationMessage> forumInvitations =
 				forumSharingManager.getInvitationMessages(id);
-		invitations.addAll(blogSharingManager.getInvitationMessages(id));
-		for (InvitationMessage i : invitations) {
+		for (InvitationMessage i : forumInvitations) {
+			messages.add(ConversationItem.from(i));
+		}
+		Collection<InvitationMessage> blogInvitations =
+				blogSharingManager.getInvitationMessages(id);
+		for (InvitationMessage i : blogInvitations) {
 			messages.add(ConversationItem.from(i));
 		}
 		duration = System.currentTimeMillis() - now;
 		if (LOG.isLoggable(INFO))
-			LOG.info("Loading forum invitations took " + duration + " ms");
+			LOG.info("Loading invitations took " + duration + " ms");
 
 		return messages;
 	}
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index b1cd0292d1..a85723601f 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -337,11 +337,16 @@ public class ConversationActivity extends BriarActivity
 					Collection<IntroductionMessage> introductions =
 							introductionManager
 									.getIntroductionMessages(contactId);
-					Collection<InvitationMessage> invitations =
+					Collection<InvitationMessage> forumInvitations =
 							forumSharingManager
 									.getInvitationMessages(contactId);
-					invitations.addAll(blogSharingManager
-							.getInvitationMessages(contactId));
+					Collection<InvitationMessage> blogInvitations =
+							blogSharingManager
+									.getInvitationMessages(contactId);
+					List<InvitationMessage> invitations = new ArrayList<>(
+							forumInvitations.size() + blogInvitations.size());
+					invitations.addAll(forumInvitations);
+					invitations.addAll(blogInvitations);
 					long duration = System.currentTimeMillis() - now;
 					if (LOG.isLoggable(INFO))
 						LOG.info("Loading headers took " + duration + " ms");
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
index 353a7e1ce2..c2fc1c026e 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationAdapter.java
@@ -13,7 +13,8 @@ import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.briarproject.R;
-import org.briarproject.android.sharing.InvitationsActivity;
+import org.briarproject.android.sharing.InvitationsBlogActivity;
+import org.briarproject.android.sharing.InvitationsForumActivity;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.api.blogs.BlogInvitationRequest;
 import org.briarproject.api.clients.SessionId;
@@ -42,9 +43,6 @@ import static org.briarproject.android.contact.ConversationItem.MSG_OUT;
 import static org.briarproject.android.contact.ConversationItem.NOTICE_IN;
 import static org.briarproject.android.contact.ConversationItem.NOTICE_OUT;
 import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
 class ConversationAdapter extends RecyclerView.Adapter {
 
@@ -86,7 +84,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
 			return new IntroductionHolder(v, type);
 		} else if (type == INTRODUCTION_OUT) {
 			v = LayoutInflater.from(viewGroup.getContext()).inflate(
-					R.layout.list_item_introduction_out, viewGroup, false);
+					R.layout.list_item_msg_notice_out, viewGroup, false);
 			return new IntroductionHolder(v, type);
 		} else if (type == NOTICE_IN) {
 			v = LayoutInflater.from(viewGroup.getContext()).inflate(
@@ -104,7 +102,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
 		} else if (type == FORUM_INVITATION_OUT ||
 				type == BLOG_INVITATION_OUT) {
 			v = LayoutInflater.from(viewGroup.getContext()).inflate(
-					R.layout.list_item_introduction_out, viewGroup, false);
+					R.layout.list_item_msg_notice_out, viewGroup, false);
 			return new InvitationHolder(v, type);
 		}
 		// incoming message (non-local)
@@ -338,17 +336,16 @@ class ConversationAdapter extends RecyclerView.Adapter {
 			ui.text.setText(ctx.getString(receivedRes, contactName, name));
 
 			if (ir.isAvailable()) {
-				final int type =
-						ir instanceof ForumInvitationRequest ? FORUM : BLOG;
+				final Class c = ir instanceof ForumInvitationRequest ?
+						InvitationsForumActivity.class :
+						InvitationsBlogActivity.class;
 				ui.showInvitationsButton.setText(ctx.getString(buttonRes));
 				ui.showInvitationsButton.setVisibility(VISIBLE);
 				ui.showInvitationsButton
 						.setOnClickListener(new View.OnClickListener() {
 							@Override
 							public void onClick(View v) {
-								Intent i = new Intent(ctx,
-										InvitationsActivity.class);
-								i.putExtra(SHAREABLE, type);
+								Intent i = new Intent(ctx, c);
 								ctx.startActivity(i);
 							}
 						});
@@ -513,7 +510,7 @@ class ConversationAdapter extends RecyclerView.Adapter {
 			message = new MessageHolder(messageLayout,
 					type == FORUM_INVITATION_IN ? MSG_IN : MSG_OUT);
 			text = (TextView) v.findViewById(R.id.introductionText);
-			showInvitationsButton = (Button) v.findViewById(R.id.showForumsButton);
+			showInvitationsButton = (Button) v.findViewById(R.id.showInvitationsButton);
 			date = (TextView) v.findViewById(R.id.introductionTime);
 
 			if (type == FORUM_INVITATION_OUT || type == BLOG_INVITATION_OUT) {
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index 77d3a713a0..610c2b3e62 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -33,8 +33,8 @@ import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.controller.handler.UiResultHandler;
-import org.briarproject.android.sharing.ShareActivity;
-import org.briarproject.android.sharing.SharingStatusActivity;
+import org.briarproject.android.sharing.ShareForumActivity;
+import org.briarproject.android.sharing.SharingStatusForumActivity;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.android.util.TrustIndicatorView;
@@ -59,8 +59,6 @@ import static android.view.View.GONE;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 import static android.widget.Toast.LENGTH_SHORT;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
 public class ForumActivity extends BriarActivity implements
 		ForumController.ForumPostListener {
@@ -224,19 +222,17 @@ public class ForumActivity extends BriarActivity implements
 				showTextInput(null);
 				return true;
 			case R.id.action_forum_share:
-				Intent i2 = new Intent(this, ShareActivity.class);
+				Intent i2 = new Intent(this, ShareForumActivity.class);
 				i2.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i2.putExtra(GROUP_ID, groupId.getBytes());
-				i2.putExtra(SHAREABLE, FORUM);
 				ActivityCompat
 						.startActivityForResult(this, i2, REQUEST_FORUM_SHARED,
 								options.toBundle());
 				return true;
 			case R.id.action_forum_sharing_status:
-				Intent i3 = new Intent(this, SharingStatusActivity.class);
+				Intent i3 = new Intent(this, SharingStatusForumActivity.class);
 				i3.setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP);
 				i3.putExtra(GROUP_ID, groupId.getBytes());
-				i3.putExtra(SHAREABLE, FORUM);
 				ActivityCompat.startActivity(this, i3, options.toBundle());
 				return true;
 			case R.id.action_forum_delete:
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 26721db36d..93fece1089 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -16,7 +16,7 @@ import android.view.ViewGroup;
 import org.briarproject.R;
 import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.fragment.BaseEventFragment;
-import org.briarproject.android.sharing.InvitationsActivity;
+import org.briarproject.android.sharing.InvitationsForumActivity;
 import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.db.NoSuchGroupException;
@@ -41,8 +41,6 @@ import javax.inject.Inject;
 import static android.support.design.widget.Snackbar.LENGTH_INDEFINITE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
 public class ForumListFragment extends BaseEventFragment implements
 		View.OnClickListener {
@@ -288,8 +286,7 @@ public class ForumListFragment extends BaseEventFragment implements
 	@Override
 	public void onClick(View view) {
 		// snackbar click
-		Intent i = new Intent(getContext(), InvitationsActivity.class);
-		i.putExtra(SHAREABLE, FORUM);
+		Intent i = new Intent(getContext(), InvitationsForumActivity.class);
 		startActivity(i);
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
index 6ace473db2..a1671e2e24 100644
--- a/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ContactSelectorFragment.java
@@ -18,7 +18,6 @@ import org.briarproject.android.contact.BaseContactListAdapter;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.android.util.BriarRecyclerView;
-import org.briarproject.api.blogs.BlogSharingManager;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.contact.ContactManager;
@@ -38,10 +37,7 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
 import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
 import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
 
@@ -66,18 +62,13 @@ public class ContactSelectorFragment extends BaseFragment implements
 	protected volatile IdentityManager identityManager;
 	@Inject
 	protected volatile ForumSharingManager forumSharingManager;
-	@Inject
-	volatile BlogSharingManager blogSharingManager;
 
 	private volatile GroupId groupId;
-	private volatile int shareable;
 
-	public static ContactSelectorFragment newInstance(int shareable,
-			GroupId groupId) {
+	public static ContactSelectorFragment newInstance(GroupId groupId) {
 
 		Bundle args = new Bundle();
 		args.putByteArray(GROUP_ID, groupId.getBytes());
-		args.putInt(SHAREABLE, shareable);
 		ContactSelectorFragment fragment = new ContactSelectorFragment();
 		fragment.setArguments(args);
 		return fragment;
@@ -95,7 +86,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 			shareActivity = (ShareActivity) context;
 		} catch (ClassCastException e) {
 			throw new InstantiationError(
-					"This fragment is only meant to be attached to the ShareForumActivity");
+					"This fragment is only meant to be attached to a subclass of ShareActivity");
 		}
 	}
 
@@ -104,9 +95,9 @@ public class ContactSelectorFragment extends BaseFragment implements
 		super.onCreate(savedInstanceState);
 
 		setHasOptionsMenu(true);
-		groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
+		Bundle args = getArguments();
+		groupId = new GroupId(args.getByteArray(GROUP_ID));
 		if (groupId == null) throw new IllegalStateException("No GroupId");
-		shareable = getArguments().getInt(SHAREABLE);
 	}
 
 	@Override
@@ -125,7 +116,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 		list = (BriarRecyclerView) contentView.findViewById(R.id.contactList);
 		list.setLayoutManager(new LinearLayoutManager(getActivity()));
 		list.setAdapter(adapter);
-		list.setEmptyText(getString(R.string.no_contacts));
+		list.setEmptyText(getString(R.string.no_contacts_selector));
 
 		// restore selected contacts if available
 		if (savedInstanceState != null) {
@@ -195,7 +186,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 	}
 
 	private void loadContacts(final Collection<ContactId> selection) {
-		listener.runOnDbThread(new Runnable() {
+		shareActivity.runOnDbThread(new Runnable() {
 			@Override
 			public void run() {
 				try {
@@ -209,14 +200,7 @@ public class ContactSelectorFragment extends BaseFragment implements
 						boolean selected = selection != null &&
 								selection.contains(c.getId());
 						// do we have already some sharing with that contact?
-						boolean disabled = true;
-						if (shareable == FORUM) {
-							disabled = !forumSharingManager
-									.canBeShared(groupId, c);
-						} else if (shareable == BLOG) {
-							disabled = !blogSharingManager
-									.canBeShared(groupId, c);
-						}
+						boolean disabled = shareActivity.isDisabled(groupId, c);
 						contacts.add(new SelectableContactListItem(c,
 								localAuthor, groupId, selected, disabled));
 					}
diff --git a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
index 614f54cbf3..985b73bdd2 100644
--- a/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsActivity.java
@@ -1,68 +1,36 @@
 package org.briarproject.android.sharing;
 
-import android.content.Intent;
+import android.content.Context;
 import android.os.Bundle;
 import android.support.v7.widget.LinearLayoutManager;
 import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.util.BriarRecyclerView;
-import org.briarproject.api.blogs.Blog;
-import org.briarproject.api.blogs.BlogManager;
-import org.briarproject.api.blogs.BlogSharingManager;
-import org.briarproject.api.contact.Contact;
-import org.briarproject.api.db.DbException;
-import org.briarproject.api.db.NoSuchGroupException;
-import org.briarproject.api.event.BlogInvitationReceivedEvent;
 import org.briarproject.api.event.ContactRemovedEvent;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
 import org.briarproject.api.event.EventListener;
-import org.briarproject.api.event.ForumInvitationReceivedEvent;
-import org.briarproject.api.event.GroupAddedEvent;
-import org.briarproject.api.event.GroupRemovedEvent;
-import org.briarproject.api.event.InvitationReceivedEvent;
-import org.briarproject.api.forum.Forum;
-import org.briarproject.api.forum.ForumManager;
-import org.briarproject.api.forum.ForumSharingManager;
-import org.briarproject.api.sync.ClientId;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
 import static android.widget.Toast.LENGTH_SHORT;
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
 import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
-public class InvitationsActivity extends BriarActivity
+abstract class InvitationsActivity extends BriarActivity
 		implements EventListener, AvailableForumClickListener {
 
-	private static final Logger LOG =
+	protected static final Logger LOG =
 			Logger.getLogger(InvitationsActivity.class.getName());
 
-	private int shareable;
 	private InvitationAdapter adapter;
 
-	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ForumManager forumManager;
-	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
-	@Inject
-	protected volatile BlogManager blogManager;
-	@Inject
-	protected volatile BlogSharingManager blogSharingManager;
-	@Inject
-	protected volatile EventBus eventBus;
+	protected EventBus eventBus;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -70,18 +38,7 @@ public class InvitationsActivity extends BriarActivity
 
 		setContentView(R.layout.activity_invitations);
 
-		Intent i = getIntent();
-		shareable = i.getIntExtra(SHAREABLE, 0);
-		if (shareable == 0) throw new IllegalStateException("No Shareable");
-
-		if (shareable == FORUM) {
-			adapter = new ForumInvitationAdapter(this, this);
-		} else if (shareable == BLOG) {
-			adapter = new BlogInvitationAdapter(this, this);
-			setTitle(getString(R.string.blogs_sharing_invitations_title));
-		} else {
-			throw new IllegalArgumentException("Unknown Shareable Type");
-		}
+		adapter = getAdapter(this, this);
 
 		BriarRecyclerView list =
 				(BriarRecyclerView) findViewById(R.id.invitationsView);
@@ -91,16 +48,11 @@ public class InvitationsActivity extends BriarActivity
 		}
 	}
 
-	@Override
-	public void injectActivity(ActivityComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public void onResume() {
 		super.onResume();
 		eventBus.addListener(this);
-		loadShareables(false);
+		loadInvitations(false);
 	}
 
 	@Override
@@ -110,131 +62,11 @@ public class InvitationsActivity extends BriarActivity
 		adapter.clear();
 	}
 
-	private void loadShareables(boolean clear) {
-		if (shareable == FORUM) {
-			loadForums(clear);
-		} else if (shareable == BLOG) {
-			loadBlogs(clear);
-		}
-	}
-
-	private void loadForums(final boolean clear) {
-		runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					Collection<InvitationItem> forums = new ArrayList<>();
-					long now = System.currentTimeMillis();
-					for (Forum f : forumSharingManager.getInvited()) {
-						boolean subscribed;
-						try {
-							forumManager.getForum(f.getId());
-							subscribed = true;
-						} catch (NoSuchGroupException e) {
-							subscribed = false;
-						}
-						Collection<Contact> c =
-								forumSharingManager.getSharedBy(f.getId());
-						forums.add(
-								new InvitationItem(f, subscribed, c));
-					}
-					long duration = System.currentTimeMillis() - now;
-					if (LOG.isLoggable(INFO))
-						LOG.info("Load took " + duration + " ms");
-					displayInvitations(forums, clear);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
-
-	private void loadBlogs(final boolean clear) {
-		runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					Collection<InvitationItem> invitations = new ArrayList<>();
-					long now = System.currentTimeMillis();
-					for (Blog b : blogSharingManager.getInvited()) {
-						boolean subscribed;
-						try {
-							blogManager.getBlog(b.getId());
-							subscribed = true;
-						} catch (NoSuchGroupException e) {
-							subscribed = false;
-						}
-						Collection<Contact> c =
-								blogSharingManager.getSharedBy(b.getId());
-						invitations.add(
-								new InvitationItem(b, subscribed, c));
-					}
-					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);
-				}
-			}
-		});
-	}
-
-	private void displayInvitations(final Collection<InvitationItem> invitations,
-			final boolean clear) {
-		runOnUiThread(new Runnable() {
-			@Override
-			public void run() {
-				if (invitations.isEmpty()) {
-					LOG.info("No more invitations available, finishing");
-					finish();
-				} else {
-					if (clear) adapter.clear();
-					adapter.addAll(invitations);
-				}
-			}
-		});
-	}
-
 	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof ContactRemovedEvent) {
-			LOG.info("Contact removed, reloading");
-			loadShareables(true);
-		} else if (e instanceof GroupAddedEvent) {
-			GroupAddedEvent g = (GroupAddedEvent) e;
-			ClientId cId = g.getGroup().getClientId();
-			if (cId.equals(forumManager.getClientId()) && shareable == FORUM) {
-				LOG.info("Forum added, reloading");
-				loadShareables(false);
-			} else if (cId.equals(blogManager.getClientId()) &&
-					shareable == BLOG) {
-				LOG.info("Blog added, reloading");
-				loadShareables(true);
-			}
-		} else if (e instanceof GroupRemovedEvent) {
-			GroupRemovedEvent g = (GroupRemovedEvent) e;
-			ClientId cId = g.getGroup().getClientId();
-			if (cId.equals(forumManager.getClientId()) && shareable == FORUM) {
-				LOG.info("Forum removed, reloading");
-				loadShareables(true);
-			} else if (cId.equals(blogManager.getClientId()) &&
-					shareable == BLOG) {
-				LOG.info("Blog removed, reloading");
-				loadShareables(true);
-			}
-		} else if (e instanceof InvitationReceivedEvent) {
-			if (e instanceof ForumInvitationReceivedEvent &&
-					shareable == FORUM) {
-				LOG.info("Forum invitation received, reloading");
-				loadShareables(false);
-			} else if (e instanceof BlogInvitationReceivedEvent &&
-					shareable == BLOG) {
-				LOG.info("Blog invitation received, reloading");
-				loadShareables(false);
-			}
+			LOG.info("Contact removed, reloading...");
+			loadInvitations(true);
 		}
 	}
 
@@ -243,14 +75,8 @@ public class InvitationsActivity extends BriarActivity
 		respondToInvitation(item, accept);
 
 		// show toast
-		int res;
-		if (shareable == FORUM) {
-			res = R.string.forum_declined_toast;
-			if (accept) res = R.string.forum_joined_toast;
-		} else {
-			res = R.string.blogs_sharing_declined_toast;
-			if (accept) res = R.string.blogs_sharing_joined_toast;
-		}
+		int res = getDeclineRes();
+		if (accept) res = getAcceptRes();
 		Toast.makeText(this, res, LENGTH_SHORT).show();
 
 		// remove item and finish if it was the last
@@ -260,49 +86,32 @@ public class InvitationsActivity extends BriarActivity
 		}
 	}
 
-	private void respondToInvitation(final InvitationItem item,
-			final boolean accept) {
+	abstract protected InvitationAdapter getAdapter(Context ctx,
+			AvailableForumClickListener listener);
 
-		if (shareable == FORUM) {
-			respondToForumInvitation(item, accept);
-		} else if (shareable == BLOG) {
-			respondToBlogInvitation(item, accept);
-		}
-	}
+	abstract protected void loadInvitations(boolean clear);
 
-	private void respondToForumInvitation(final InvitationItem item,
-			final boolean accept) {
-		runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					Forum f = (Forum) item.getShareable();
-					for (Contact c : item.getContacts()) {
-						forumSharingManager.respondToInvitation(f, c, accept);
-					}
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
+	abstract protected void respondToInvitation(final InvitationItem item,
+			final boolean accept);
+
+	abstract protected int getAcceptRes();
 
-	private void respondToBlogInvitation(final InvitationItem item,
-			final boolean accept) {
-		runOnDbThread(new Runnable() {
+	abstract protected int getDeclineRes();
+
+	protected void displayInvitations(
+			final Collection<InvitationItem> invitations, final boolean clear) {
+		runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				try {
-					Blog b = (Blog) item.getShareable();
-					for (Contact c : item.getContacts()) {
-						blogSharingManager.respondToInvitation(b, c, accept);
-					}
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
+				if (invitations.isEmpty()) {
+					LOG.info("No more invitations available, finishing");
+					finish();
+				} else {
+					if (clear) adapter.clear();
+					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
new file mode 100644
index 0000000000..a289ac2268
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsBlogActivity.java
@@ -0,0 +1,127 @@
+package org.briarproject.android.sharing;
+
+import android.content.Context;
+
+import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.blogs.Blog;
+import org.briarproject.api.blogs.BlogManager;
+import org.briarproject.api.blogs.BlogSharingManager;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.NoSuchGroupException;
+import org.briarproject.api.event.BlogInvitationReceivedEvent;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.GroupAddedEvent;
+import org.briarproject.api.event.GroupRemovedEvent;
+import org.briarproject.api.sync.ClientId;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
+
+public class InvitationsBlogActivity extends InvitationsActivity {
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile BlogManager blogManager;
+	@Inject
+	protected volatile BlogSharingManager blogSharingManager;
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	@Override
+	public void eventOccurred(Event e) {
+		super.eventOccurred(e);
+
+		if (e instanceof GroupAddedEvent) {
+			GroupAddedEvent g = (GroupAddedEvent) e;
+			ClientId cId = g.getGroup().getClientId();
+			if (cId.equals(blogManager.getClientId())) {
+				LOG.info("Blog added, reloading");
+				loadInvitations(false);
+			}
+		} else if (e instanceof GroupRemovedEvent) {
+			GroupRemovedEvent g = (GroupRemovedEvent) e;
+			ClientId cId = g.getGroup().getClientId();
+			if (cId.equals(blogManager.getClientId())) {
+				LOG.info("Blog removed, reloading");
+				loadInvitations(false);
+			}
+		} else if (e instanceof BlogInvitationReceivedEvent) {
+			LOG.info("Blog invitation received, reloading");
+			loadInvitations(false);
+		}
+	}
+
+	protected InvitationAdapter getAdapter(Context ctx,
+			AvailableForumClickListener listener) {
+		return new BlogInvitationAdapter(ctx, listener);
+	}
+
+	protected void loadInvitations(final boolean clear) {
+		runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					Collection<InvitationItem> invitations = new ArrayList<>();
+					long now = System.currentTimeMillis();
+					for (Blog b : blogSharingManager.getInvited()) {
+						boolean subscribed;
+						try {
+							blogManager.getBlog(b.getId());
+							subscribed = true;
+						} catch (NoSuchGroupException e) {
+							subscribed = false;
+						}
+						Collection<Contact> c =
+								blogSharingManager.getSharedBy(b.getId());
+						invitations.add(
+								new InvitationItem(b, subscribed, c));
+					}
+					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);
+				}
+			}
+		});
+	}
+
+	protected void respondToInvitation(final InvitationItem item,
+			final boolean accept) {
+		runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					Blog b = (Blog) item.getShareable();
+					for (Contact c : item.getContacts()) {
+						blogSharingManager.respondToInvitation(b, c, accept);
+					}
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	protected int getAcceptRes() {
+		return R.string.blogs_sharing_joined_toast;
+	}
+
+	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
new file mode 100644
index 0000000000..a994f9faa2
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/InvitationsForumActivity.java
@@ -0,0 +1,127 @@
+package org.briarproject.android.sharing;
+
+import android.content.Context;
+
+import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.NoSuchGroupException;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.ForumInvitationReceivedEvent;
+import org.briarproject.api.event.GroupAddedEvent;
+import org.briarproject.api.event.GroupRemovedEvent;
+import org.briarproject.api.forum.Forum;
+import org.briarproject.api.forum.ForumManager;
+import org.briarproject.api.forum.ForumSharingManager;
+import org.briarproject.api.sync.ClientId;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+import static org.briarproject.android.sharing.InvitationAdapter.AvailableForumClickListener;
+
+public class InvitationsForumActivity extends InvitationsActivity {
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile ForumManager forumManager;
+	@Inject
+	protected volatile ForumSharingManager forumSharingManager;
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	@Override
+	public void eventOccurred(Event e) {
+		super.eventOccurred(e);
+
+		if (e instanceof GroupAddedEvent) {
+			GroupAddedEvent g = (GroupAddedEvent) e;
+			ClientId cId = g.getGroup().getClientId();
+			if (cId.equals(forumManager.getClientId())) {
+				LOG.info("Forum added, reloading");
+				loadInvitations(false);
+			}
+		} else if (e instanceof GroupRemovedEvent) {
+			GroupRemovedEvent g = (GroupRemovedEvent) e;
+			ClientId cId = g.getGroup().getClientId();
+			if (cId.equals(forumManager.getClientId())) {
+				LOG.info("Forum removed, reloading");
+				loadInvitations(false);
+			}
+		} else if (e instanceof ForumInvitationReceivedEvent) {
+			LOG.info("Forum invitation received, reloading");
+			loadInvitations(false);
+		}
+	}
+
+	protected InvitationAdapter getAdapter(Context ctx,
+			AvailableForumClickListener listener) {
+		return new ForumInvitationAdapter(ctx, listener);
+	}
+
+	protected void loadInvitations(final boolean clear) {
+		runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					Collection<InvitationItem> forums = new ArrayList<>();
+					long now = System.currentTimeMillis();
+					for (Forum f : forumSharingManager.getInvited()) {
+						boolean subscribed;
+						try {
+							forumManager.getForum(f.getId());
+							subscribed = true;
+						} catch (NoSuchGroupException e) {
+							subscribed = false;
+						}
+						Collection<Contact> c =
+								forumSharingManager.getSharedBy(f.getId());
+						forums.add(
+								new InvitationItem(f, subscribed, c));
+					}
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Load took " + duration + " ms");
+					displayInvitations(forums, clear);
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	protected void respondToInvitation(final InvitationItem item,
+			final boolean accept) {
+		runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					Forum f = (Forum) item.getShareable();
+					for (Contact c : item.getContacts()) {
+						forumSharingManager.respondToInvitation(f, c, accept);
+					}
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	protected int getAcceptRes() {
+		return R.string.forum_joined_toast;
+	}
+
+	protected int getDeclineRes() {
+		return R.string.forum_declined_toast;
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java
index be0a6e8db6..a5e59ce895 100644
--- a/briar-android/src/org/briarproject/android/sharing/ShareActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/ShareActivity.java
@@ -5,60 +5,50 @@ import android.os.Bundle;
 import android.view.View;
 
 import org.briarproject.R;
-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;
+import org.briarproject.api.db.DbException;
 import org.briarproject.api.sync.GroupId;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
-public class ShareActivity extends BriarActivity implements
+public abstract class ShareActivity extends BriarActivity implements
 		BaseFragment.BaseFragmentListener {
 
-	public final static String SHAREABLE = "shareable";
-	public final static int FORUM = 1;
-	public final static int BLOG = 2;
-
 	final static String CONTACTS = "contacts";
 
-	private int shareable;
-
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 
-		setContentView(R.layout.activity_share_forum);
+		setContentView(R.layout.activity_share);
 
 		Intent i = getIntent();
 		byte[] b = i.getByteArrayExtra(GROUP_ID);
 		if (b == null) throw new IllegalStateException("No GroupId");
 		GroupId groupId = new GroupId(b);
 
-		shareable = i.getIntExtra(SHAREABLE, 0);
-		if (shareable == 0) throw new IllegalStateException("No Shareable");
-
 		if (savedInstanceState == null) {
 			ContactSelectorFragment contactSelectorFragment =
-					ContactSelectorFragment.newInstance(shareable, groupId);
+					ContactSelectorFragment.newInstance(groupId);
 			getSupportFragmentManager().beginTransaction()
 					.add(R.id.shareContainer, contactSelectorFragment)
 					.commit();
 		}
 	}
 
-	@Override
-	public void injectActivity(ActivityComponent component) {
-		component.inject(this);
-	}
+	abstract ShareMessageFragment getMessageFragment(GroupId groupId,
+			Collection<ContactId> contacts);
 
-	void showMessageScreen(GroupId groupId,
-			Collection<ContactId> contacts) {
+	abstract boolean isDisabled(GroupId groupId, Contact c) throws DbException;
 
+	void showMessageScreen(GroupId groupId, Collection<ContactId> contacts) {
 		ShareMessageFragment messageFragment =
-				ShareMessageFragment.newInstance(shareable, groupId, contacts);
+				getMessageFragment(groupId, contacts);
 
 		getSupportFragmentManager().beginTransaction()
 				.setCustomAnimations(android.R.anim.fade_in,
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java
new file mode 100644
index 0000000000..696ea14522
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogActivity.java
@@ -0,0 +1,35 @@
+package org.briarproject.android.sharing;
+
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.blogs.BlogSharingManager;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+public class ShareBlogActivity extends ShareActivity {
+
+	@Inject
+	volatile BlogSharingManager blogSharingManager;
+
+	ShareMessageFragment getMessageFragment(GroupId groupId,
+			Collection<ContactId> contacts) {
+		return ShareBlogMessageFragment.newInstance(groupId, contacts);
+	}
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	/**
+	 * This must only be called from a DbThread
+	 */
+	boolean isDisabled(GroupId groupId, Contact c) throws DbException {
+		return !blogSharingManager.canBeShared(groupId, c);
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
new file mode 100644
index 0000000000..9b562424c0
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/ShareBlogMessageFragment.java
@@ -0,0 +1,81 @@
+package org.briarproject.android.sharing;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.blogs.BlogSharingManager;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import static android.widget.Toast.LENGTH_SHORT;
+import static java.util.logging.Level.WARNING;
+
+public class ShareBlogMessageFragment extends ShareMessageFragment {
+
+	public final static String TAG = ShareBlogMessageFragment.class.getName();
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile BlogSharingManager blogSharingManager;
+
+	public static ShareBlogMessageFragment newInstance(GroupId groupId,
+			Collection<ContactId> contacts) {
+
+		ShareBlogMessageFragment fragment = new ShareBlogMessageFragment();
+		fragment.setArguments(getArguments(groupId, contacts));
+		return fragment;
+	}
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+
+		setTitle(R.string.blogs_sharing_share);
+
+		View v = super.onCreateView(inflater, container, savedInstanceState);
+		ui.button.setText(getString(R.string.blogs_sharing_button));
+		return v;
+	}
+
+	@Override
+	public void injectFragment(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	protected void share(final String msg) {
+		listener.runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					for (ContactId c : getContacts()) {
+						blogSharingManager.sendInvitation(getGroupId(), c, msg);
+					}
+				} catch (DbException e) {
+					sharingError();
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	protected void sharingError() {
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				int res = R.string.blogs_sharing_error;
+				Toast.makeText(getContext(), res, LENGTH_SHORT).show();
+			}
+		});
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java
new file mode 100644
index 0000000000..51a5d5a22a
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/ShareForumActivity.java
@@ -0,0 +1,34 @@
+package org.briarproject.android.sharing;
+
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.forum.ForumSharingManager;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+public class ShareForumActivity extends ShareActivity {
+	@Inject
+	volatile ForumSharingManager forumSharingManager;
+
+	ShareMessageFragment getMessageFragment(GroupId groupId,
+			Collection<ContactId> contacts) {
+		return ShareForumMessageFragment.newInstance(groupId, contacts);
+	}
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	/**
+	 * This must only be called from a DbThread
+	 */
+	boolean isDisabled(GroupId groupId, Contact c) throws DbException {
+		return !forumSharingManager.canBeShared(groupId, c);
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
new file mode 100644
index 0000000000..f24869467a
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/ShareForumMessageFragment.java
@@ -0,0 +1,79 @@
+package org.briarproject.android.sharing;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.forum.ForumSharingManager;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+import static android.widget.Toast.LENGTH_SHORT;
+import static java.util.logging.Level.WARNING;
+
+public class ShareForumMessageFragment extends ShareMessageFragment {
+
+	public final static String TAG = ShareForumMessageFragment.class.getName();
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile ForumSharingManager forumSharingManager;
+
+	public static ShareForumMessageFragment newInstance(GroupId groupId,
+			Collection<ContactId> contacts) {
+
+		ShareForumMessageFragment fragment = new ShareForumMessageFragment();
+		fragment.setArguments(getArguments(groupId, contacts));
+		return fragment;
+	}
+
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+
+		setTitle(R.string.forum_share_button);
+		return super.onCreateView(inflater, container, savedInstanceState);
+	}
+
+	@Override
+	public void injectFragment(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	protected void share(final String msg) {
+		listener.runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					for (ContactId c : getContacts()) {
+						forumSharingManager.
+								sendInvitation(getGroupId(), c, msg);
+					}
+				} catch (DbException e) {
+					sharingError();
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	protected void sharingError() {
+		runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				int res = R.string.forum_share_error;
+				Toast.makeText(getContext(), res, LENGTH_SHORT).show();
+			}
+		});
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
index 9e9fcac391..3d87df3785 100644
--- a/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/sharing/ShareMessageFragment.java
@@ -2,22 +2,17 @@ package org.briarproject.android.sharing;
 
 import android.content.Context;
 import android.os.Bundle;
-import android.support.v7.app.ActionBar;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.EditText;
-import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.fragment.BaseFragment;
-import org.briarproject.api.blogs.BlogManager;
 import org.briarproject.api.blogs.BlogSharingManager;
 import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.db.DbException;
 import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.sync.GroupId;
 
@@ -27,24 +22,18 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-import static android.widget.Toast.LENGTH_SHORT;
-import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
 import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
 import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
 
-public class ShareMessageFragment extends BaseFragment {
+abstract class ShareMessageFragment extends BaseFragment {
 
-	public final static String TAG = "IntroductionMessageFragment";
+	public final static String TAG = ShareMessageFragment.class.getName();
 
-	private static final Logger LOG =
-			Logger.getLogger(ShareMessageFragment.class.getName());
+	protected static final Logger LOG = Logger.getLogger(TAG);
 
+	protected ViewHolder ui;
 	private ShareActivity shareActivity;
-	private ViewHolder ui;
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
@@ -52,19 +41,15 @@ public class ShareMessageFragment extends BaseFragment {
 	@Inject
 	protected volatile BlogSharingManager blogSharingManager;
 	private volatile GroupId groupId;
-	private volatile int shareable;
 	private volatile Collection<ContactId> contacts;
 
-	public static ShareMessageFragment newInstance(int shareable,
-			GroupId groupId, Collection<ContactId> contacts) {
+	protected static Bundle getArguments(GroupId groupId,
+			Collection<ContactId> contacts) {
 
 		Bundle args = new Bundle();
 		args.putByteArray(GROUP_ID, groupId.getBytes());
-		args.putInt(SHAREABLE, shareable);
 		args.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts));
-		ShareMessageFragment fragment = new ShareMessageFragment();
-		fragment.setArguments(args);
-		return fragment;
+		return args;
 	}
 
 	@Override
@@ -82,29 +67,16 @@ public class ShareMessageFragment extends BaseFragment {
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 			Bundle savedInstanceState) {
 
-		// allow for home button to act as back button
+		// allow for "up" button to act as back button
 		setHasOptionsMenu(true);
 
-		// get groupID, shareable type and contactIDs from fragment arguments
+		// get groupID and contactIDs from fragment arguments
 		groupId = new GroupId(getArguments().getByteArray(GROUP_ID));
-		shareable = getArguments().getInt(SHAREABLE);
 		ArrayList<Integer> intContacts =
 				getArguments().getIntegerArrayList(CONTACTS);
 		if (intContacts == null) throw new IllegalArgumentException();
 		contacts = ShareActivity.getContactsFromIntegers(intContacts);
 
-		// change toolbar text
-		ActionBar actionBar = shareActivity.getSupportActionBar();
-		if (actionBar != null) {
-			if (shareable == FORUM) {
-				actionBar.setTitle(R.string.forum_share_button);
-			} else if (shareable == BLOG) {
-				actionBar.setTitle(R.string.blogs_sharing_button);
-			} else {
-				throw new IllegalArgumentException("Invalid Shareable Type!");
-			}
-		}
-
 		// inflate view
 		View v = inflater.inflate(R.layout.fragment_share_message, container,
 				false);
@@ -115,9 +87,6 @@ public class ShareMessageFragment extends BaseFragment {
 				onButtonClick();
 			}
 		});
-		if (shareable == BLOG) {
-			ui.button.setText(getString(R.string.blogs_sharing_button));
-		}
 
 		return v;
 	}
@@ -138,9 +107,8 @@ public class ShareMessageFragment extends BaseFragment {
 		return TAG;
 	}
 
-	@Override
-	public void injectFragment(ActivityComponent component) {
-		component.inject(this);
+	protected void setTitle(int res) {
+		shareActivity.setTitle(res);
 	}
 
 	private void onButtonClick() {
@@ -148,49 +116,31 @@ public class ShareMessageFragment extends BaseFragment {
 		ui.button.setEnabled(false);
 
 		String msg = ui.message.getText().toString();
-		shareForum(msg);
+		share(msg);
 
-		// don't wait for the introduction to be made before finishing activity
+		// don't wait for the invitation to be made before finishing activity
 		shareActivity.sharingSuccessful(ui.message);
 	}
 
-	private void shareForum(final String msg) {
-		listener.runOnDbThread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					for (ContactId c : contacts) {
-						if (shareable == FORUM) {
-							forumSharingManager.sendInvitation(groupId, c,
-									msg);
-						} else if (shareable == BLOG) {
-							blogSharingManager.sendInvitation(groupId, c, msg);
-						}
-					}
-				} catch (DbException e) {
-					sharingError();
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
+	abstract void share(final String msg);
+
+	abstract void sharingError();
+
+	protected Collection<ContactId> getContacts() {
+		return contacts;
 	}
 
-	private void sharingError() {
-		shareActivity.runOnUiThread(new Runnable() {
-			@Override
-			public void run() {
-				int res = R.string.forum_share_error;
-				if (shareable == BLOG) res = R.string.blogs_sharing_error;
-				Toast.makeText(shareActivity, res, LENGTH_SHORT).show();
-			}
-		});
+	protected GroupId getGroupId() {
+		return groupId;
 	}
 
-	private static class ViewHolder {
+	protected void runOnUiThread(Runnable runnable) {
+		listener.runOnUiThread(runnable);
+	}
 
-		private final EditText message;
-		private final Button button;
+	protected static class ViewHolder {
+		protected final EditText message;
+		protected final Button button;
 
 		ViewHolder(View v) {
 			message = (EditText) v.findViewById(R.id.invitationMessageView);
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
index 7d8bf5b31e..6a67448c9e 100644
--- a/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusActivity.java
@@ -6,14 +6,11 @@ import android.support.v7.widget.LinearLayoutManager;
 import android.view.MenuItem;
 
 import org.briarproject.R;
-import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.android.util.BriarRecyclerView;
-import org.briarproject.api.blogs.BlogSharingManager;
 import org.briarproject.api.contact.Contact;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.forum.ForumSharingManager;
 import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.api.sync.GroupId;
@@ -26,11 +23,8 @@ import java.util.logging.Logger;
 import javax.inject.Inject;
 
 import static java.util.logging.Level.WARNING;
-import static org.briarproject.android.sharing.ShareActivity.BLOG;
-import static org.briarproject.android.sharing.ShareActivity.FORUM;
-import static org.briarproject.android.sharing.ShareActivity.SHAREABLE;
 
-public class SharingStatusActivity extends BriarActivity {
+abstract class SharingStatusActivity extends BriarActivity {
 
 	private GroupId groupId;
 	private BriarRecyclerView sharedByList, sharedWithList;
@@ -38,28 +32,21 @@ public class SharingStatusActivity extends BriarActivity {
 
 	// Fields that are accessed from background threads must be volatile
 	@Inject
-	protected volatile ForumSharingManager forumSharingManager;
-	@Inject
-	protected volatile BlogSharingManager blogSharingManager;
-	@Inject
 	protected volatile IdentityManager identityManager;
 
-	public final static String TAG = "ForumSharingStatusActivity";
+	public final static String TAG = SharingStatusActivity.class.getName();
 	private static final Logger LOG = Logger.getLogger(TAG);
-	private int shareable;
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 
-		setContentView(R.layout.activity_forum_sharing_status);
+		setContentView(R.layout.activity_sharing_status);
 
 		Intent i = getIntent();
 		byte[] b = i.getByteArrayExtra(GROUP_ID);
 		if (b == null) throw new IllegalStateException("No GroupId");
 		groupId = new GroupId(b);
-		shareable = i.getIntExtra(SHAREABLE, 0);
-		if (shareable == 0) throw new IllegalStateException("No Shareable");
 
 		sharedByList = (BriarRecyclerView) findViewById(R.id.sharedByView);
 		sharedByAdapter = new SharingStatusAdapter(this);
@@ -94,9 +81,18 @@ public class SharingStatusActivity extends BriarActivity {
 		}
 	}
 
-	@Override
-	public void injectActivity(ActivityComponent component) {
-		component.inject(this);
+	/**
+	 * This must only be called from the DbThread
+	 */
+	abstract protected Collection<Contact> getSharedWith() throws DbException;
+
+	/**
+	 * This must only be called from the DbThread
+	 */
+	abstract protected Collection<Contact> getSharedBy() throws DbException;
+
+	protected GroupId getGroupId() {
+		return groupId;
 	}
 
 	private void loadSharedBy() {
@@ -158,36 +154,6 @@ public class SharingStatusActivity extends BriarActivity {
 		});
 	}
 
-	/**
-	 * This must only be called from the DbThread
-	 */
-	private Collection<Contact> getSharedWith() throws DbException {
-		Collection<Contact> contacts;
-		if (shareable == FORUM) {
-			contacts = forumSharingManager.getSharedWith(groupId);
-		} else if (shareable == BLOG) {
-			contacts = blogSharingManager.getSharedWith(groupId);
-		} else {
-			throw new IllegalArgumentException("Unknown Shareable");
-		}
-		return contacts;
-	}
-
-	/**
-	 * This must only be called from the DbThread
-	 */
-	private Collection<Contact> getSharedBy() throws DbException {
-		Collection<Contact> contacts;
-		if (shareable == FORUM) {
-			contacts = forumSharingManager.getSharedBy(groupId);
-		} else if (shareable == BLOG) {
-			contacts = blogSharingManager.getSharedBy(groupId);
-		} else {
-			throw new IllegalArgumentException("Unknown Shareable");
-		}
-		return contacts;
-	}
-
 	private void displaySharedWith(final List<ContactListItem> contacts) {
 		runOnUiThread(new Runnable() {
 			@Override
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusBlogActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusBlogActivity.java
new file mode 100644
index 0000000000..5c7be6deea
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusBlogActivity.java
@@ -0,0 +1,37 @@
+package org.briarproject.android.sharing;
+
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.blogs.BlogSharingManager;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.db.DbException;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+public class SharingStatusBlogActivity extends SharingStatusActivity {
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile BlogSharingManager blogSharingManager;
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	/**
+	 * This must only be called from the DbThread
+	 */
+	protected Collection<Contact> getSharedWith() throws DbException {
+		return blogSharingManager.getSharedWith(getGroupId());
+	}
+
+	/**
+	 * This must only be called from the DbThread
+	 */
+	protected Collection<Contact> getSharedBy() throws DbException {
+		return blogSharingManager.getSharedBy(getGroupId());
+	}
+
+}
diff --git a/briar-android/src/org/briarproject/android/sharing/SharingStatusForumActivity.java b/briar-android/src/org/briarproject/android/sharing/SharingStatusForumActivity.java
new file mode 100644
index 0000000000..ef3b333a0a
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/sharing/SharingStatusForumActivity.java
@@ -0,0 +1,37 @@
+package org.briarproject.android.sharing;
+
+import org.briarproject.android.ActivityComponent;
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.forum.ForumSharingManager;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+
+public class SharingStatusForumActivity extends SharingStatusActivity {
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile ForumSharingManager forumSharingManager;
+
+	@Override
+	public void injectActivity(ActivityComponent component) {
+		component.inject(this);
+	}
+
+	/**
+	 * This must only be called from the DbThread
+	 */
+	protected Collection<Contact> getSharedWith() throws DbException {
+		return forumSharingManager.getSharedWith(getGroupId());
+	}
+
+	/**
+	 * This must only be called from the DbThread
+	 */
+	protected Collection<Contact> getSharedBy() throws DbException {
+		return forumSharingManager.getSharedBy(getGroupId());
+	}
+
+}
-- 
GitLab